Squashed 'third_party/allwpilib/' changes from 83f1860047..f1a82828fe

f1a82828fe [wpiutil] Add DataLog and DataLogManager Stop() (#5860)
2a04e12c6f [apriltag] AprilTagFieldLayout: Add accessors for origin and field dimensions (#5869)
33e0089afb Cleanup usages of std::function<void(void)> (#5864)
d06fa633d5 [build] Fix protobuf generation when building with make (#5867)
049732afb8 [cscore] Make camera connection logging clearer (#5866)
87f7c19f90 [wpimath] Make InterpolatingDoubleTreeMap constructor public (#5865)
6b53ef47cf [wpimath] Don't recreate TrapezoidProfile in ProfiledPIDController calculate() (#5863)
8a3a268ae6 [commands] Add finallyDo with zero-arg lambda (#5862)
1c35d42cd0 [wpilib] Pop diagnostic for deprecated function use (#5859)
ddc8db6c26 [wpimath] Add feedforward constant constructor to ElevatorSim (#5823)
c6aff2c431 [upstream_utils] Update to LLVM 17.0.4 (#5855)
a9c5b18a39 [build] Update OpenCV to 2024-4.8.0-2 (#5854)
9540b6922d [hal] Add CAN IDs for AndyMark and Vivid Hosting (#5852)
83a7d33c47 [glass] Improve display of protobuf/struct type strings (#5850)
a4a8ad9c75 [commands] Make Java SelectCommand generic (#5849)
9eecf2a456 [build] Add CMake option to build Java sources jars (#5768)
9536a311cb [wpilib] Add support for the PS5 DualSense controller (#5257)
8d5e6737fc [wpilibc] SolenoidSim: Add virtual destructor (#5848)
07e13d60a2 [ntcore] Fix write_impl (#5847)
1713386869 [wpiutil] ProtobufMessageDatabase: Fix out-of-order Add() rebuild (#5845)
35472f5fc9 [ntcore] Fix a use-after-free in client close (#5844)
ed168b522c [ntcore] Disable buf pool when asan is enabled (#5843)
3e7ba2cc6f [wpinet] WebSocket: Fix write behavior (#5841)
80c47da237 [sim] Disable the robot program when DS disconnects (#5818)
abe1cec90c [wpilib] Update Usage Reporting ResourceType from NI Libraries (#5842)
cdf981abba [glass] Fix position of data type in NT view (#5840)
04dcd80adb [build] Publish unit tests for examples (#5838)
49920234ac [build] Fix checkstyle rules to allow Windows paths (#5839)
366b715942 [wpilib] Fix SendableChooser test (#5835)
3ba501f947 [commands] Java: Fix CommandXboxController.leftTrigger() parameter order (#5831)
ec569a58ef [wpimath] Make KalmanTypeFilter interface public (#5830)
b91317fd36 [wpiutil] DataLog.addSchema(): Don't add into a set view (#5829)
2ab4fcbc24 [wpiutil] ProtobufMessageDatabase: Clear messages first (#5827)
98c14f1692 [wpimath] Add EKF/UKF u-y-R correct overload (#5832)
60bcdeded9 [ci] Disable java in sanitizer builds (#5833)
c87f8fd538 [commands] Add DeferredCommand (#5566)
ad80eb3a0b [ci] Update actions for comment-command (#5824)
c7d6ad5a0b [ntcore] WebSocketConnection: Use weak capture (#5822)
8a8e220792 [simgui] Add 'Invalid' option for AllianceStation (#5820)
cfc6a47f76 [sim] DS plugin: Fix off-by-one error when setting alliance station (#5819)
8efa586ace [ntcore] Don't check type string on publishing an entry (#5816)
23ea188e60 [glass] Add protobuf decode error log message (#5812)
928e87b4f4 [build] Add combined test meta-task (#5813)
63ef585d4b [wpiutil] Fix compilation of MathExtras.h on Windows with /sdl (#5809)
b03a7668f9 [build] Windows CMake/vcpkg fixes (#5807)
3f08bcde54 [hal] Fix HAL AllianceStation on rio (#5811)
196d963dc4 [ntcore] Fix off-by-one error in stream write (#5810)
f4cbcbc984 Fix typos (NFC) (#5804)
ec0f7fefb0 [myrobot] Update the myRobot JRE (#5805)
3d618bdbfd [wpiutil] Fix Java struct array unpacking (#5801)
1fa7445667 [ntcore] Check for valid client in incoming text and binary (#5799)
269b9647da [ci] Update JDK for combine step (#5794)
bee32f080e [docs] Add wpiunits to JavaDocs (#5793)
25dad5a531 [wpinet] TCPConnector_parallel: Don't use thread_local (#5791)
4a93581f1a [build] cmake: use default library type for libglassnt, libglass, wpigui, and imgui (#5797)
abb2857e03 [wpilib] Counter: Fix default distance per pulse, add distance and rate to C++ (#5796)
b14a61e1c0 [readme] Add link to QuickBuffers release page (#5795)
cf54d9ccb7 [wpiutil, ntcore] Add structured data support (#5391)
ecb7cfa9ef [wpimath] Add Exponential motion profile (#5720)
7c6fe56cf2 [ntcore] Fix crash on disconnect (#5788)
85147bf69e [wpinet] WebSocketSerializer: Fix UB (#5787)
244163acad [wpinet] uv::Stream::TryWrite(): Return 0 on EAGAIN (#5784)
820728503d [hal] Remove extra semicolon in RoboRioData (#5786)
45f307d87e [upstream_utils] Upgrade to LLVM 17.0.3 (#5785)
4ce4d63efc [wpilibj] Fix RobotBase.isSimulation() (#5783)
579007ceb3 [commands] Add requirements parameter to Commands.idle() (#5774)
3f3a169149 [wpilib] Make physics sim setState() functions public (#5779)
7501e4ac88 [wpilib] Close sim device in ADIS IMUs (#5776)
99630d2e78 [wpimath] Upgrade to EJML 0.43.1 (#5778)
02cbbc997d [wpimath] Make Vector-Vector binary operators return Vector (#5772)
ed93889e17 [examples] Fix typo in TimesliceRobot example name (#5773)
da70e4c262 [docs] Add jinja2 to CMake prerequisites (#5771)
e814595ea7 [wpimath] Add ChassisSpeeds.fromRobotRelativeSpeeds() (#5744)
f98c943445 [wpimath] LinearSystemId: Add DCMotorSystem overload (#5770)
b3eb64b0f7 [wpiutil] ct_string: Use inline namespace for literals (#5767)
7d9ba256c2 Revert "[build] Add CMake option to build Java source jars (#5756)" (#5766)
1f6492e3d8 [sysid] Update JSON library usage (#5765)
638f04f626 [wpiutil] Add protobuf to thirdparty sources (#5746)
210255bfff [wpiutil] Update json to 3.11.2 (#5680)
896772c750 [wpimath] Add DCMotor functions for Kraken X60 and Neo Vortex (#5759)
fd427f6c82 [wpimath] Fix hardcoded module count in SwerveDriveKinematics.resetHeading() (#5762)
c0b4c6cce6 [wpimath] Add overloads for Transform2d and Transform3d (#5757)
9a0aafd8ab [examples] Make swerve examples multiply desired module speeds by cosine of heading error (#5758)
1c724884ca [build] Add CMake option to build Java source jars (#5756)
5b0db6b93e [ci] Forward CI as well (#5755)
f8cbbbac12 [ci] Take 2 on passing GITHUB_REF (#5754)
b9944be09c [ci] Pass GITHUB_REF to docker container (#5753)
de5e4eda6c [build] Update apriltag, libssh, googletest for 2024 (#5752)
227e660e20 [upstream_utils] Upgrade to LLVM 17.0.2 (#5750)
36f94c9f21 [commands,romi,xrp] Add frcYear to vendordep (#5747)
741d166457 [glass] NT view: enhance array support (#5732)
1d23513945 [ntcore] Fix string array value comparison (#5745)
ff1849052e [commands] Make command scheduling order consistent (#5470)
58e8474368 [build] Disable armsimulation unit test (#5739)
fb07b0da49 [examples] Add XRP C++ Examples and Templates (#5743)
81893ad73d Run wpiformat with clang-format 17 (#5740)
faa1e665ba [wpimath] Add ElevatorFeedforward.calculate(currentV, nextV) overload (#5715)
a789632052 [build] Update to native utils 2024.3.1 (#5738)
8f60ab5182 [build] Update OpenCV to 2024-4.8.0-1 (#5737)
33243f982b [wpimath] Expand Quaternion class with additional operators (#5600)
420f2f7c80 [ntcore] Add RTT-only subprotocol (#5731)
2b63e35ded [ntcore] Fix moving outgoing queue to new period (#5735)
be939cb636 [ntcore] Fix notification of SetDefaultEntryValue (#5733)
69a54de202 [build] Update enterprise plugin (#5730)
fef03a3ff5 [commands] Clean up C++ includes after Requirements was added (#5719)
8b7c6852cf [ntcore] Networking improvements (#5659)
1d19e09ca9 [wpiutil] Set WPI_{UN}IGNORE_DEPRECATED to empty when all else fails (#5728)
58141d6eb5 [wpilib] Make BooleanEvent more consistent (#5436)
6576d9b474 [wpilib] SendableChooser: implement Sendable instead of NTSendable (#5718)
a4030c670f [build] Update to gradle 8.4, enable win arm builds (#5727)
0960f11eba [wpinet] Revert removal of uv_clock_gettime() (#5723)
cb1bd0a3be [wpiutil] Get more precise system time on Windows (#5722)
4831277ffe [wpigui] Fix loading a maximized window on second monitor (#5721)
3eb372c25a [wpiutil] SendableBuilder: Add PublishConst methods (#5158)
1fec8596a4 [ci] Fix -dirty version (#5716)
f7e47d03f3 [build] Remove unnecessary CMake config installs (#5714)
a331ed2374 [sysid] Add SysId (#5672)
8d2cbfce16 [wpiutil] DataLog: Stop logging if insufficient free space (#5699)
48facb9cef [ntcoreffi] Add DataLogManager (#5702)
aecbcb08fc [ntcore] Correctly start DataLog for existing publishers (#5703)
5e295dfbda [wpiutil] DataLog: Limit total buffer allocation (#5700)
c7c7e05d9d [ci] Unbreak combiner (#5698)
c92bad52cb [wpilib] DataLogManager: Use system time valid function (#5697)
d404af5f24 [wpilib] RobotController: Add isSystemTimeValid() (#5696)
e56f1a3632 [ci] Run combine but skip all steps (#5695)
8f5bcad244 [ci] Use sccache for cmake builds (#5692)
703dedc4a6 [ci] Upgrade get-cmake action to fix node12 deprecation warning (#5694)
c69a0d7504 [ci] Don't run example unit test that segfaults (#5693)
66358d103e Add menu items for online docs to GUI tools (#5689)
4be8384a76 [ci] Disable combine on PR builds (#5691)
90288f06a6 [ci] Fix Gradle disk space issues (#5688)
9e9583412e [wpigui] Make wpi::gui::OpenURL() fork the process first (#5687)
d4fcd80b7b [ci] Gradle: Use container only for build step (#5684)
7b70e66772 [outlineviewer] Fix thirdparty library include sorting (#5683)
5f651df5d5 [build] Clean up Gradle configs (#5685)
65b26738d5 Add CMakeSettings.json to gitignore (#5682)
d0305951ad Fix GitHub inline warnings (#5681)
e8d4a20331 [build][cmake] Fix windows tests and re-enable CI tests (#5674)
2b58bbde0b [xrp] Add Reflectance sensor and rangefinder classes (#5673)
dd5612fbee [json] Add forward definition header (#5676)
eab44534c3 [wpimath] Remove unused SmallString include (#5677)
5ab54ff760 Replace wpi::raw_istream with wpi::MemoryBuffer (#5675)
1b6ec5a95d [wpiutil] Upgrade to LLVM 17.0.1 (#5482)
07a0d22fe6 [build] Build examples in CMake CI (#5667)
97021f074a [build] Upgrade imgui and implot (#5668)
87ce1e3761 [build] Fix wpilibNewCommands CMake install (#5671)
6ef94de9b5 [wpimath] Add tests for ArmFeedforward and ElevatorFeedforward (#5663)
c395b29fb4 [wpinet] Add WebSocket::TrySendFrames() (#5607)
c4643ba047 [romi/xrp] Fix version typo in vendordep json (#5664)
51dcb8b55a [examples] Make Romi/XRP Examples use appropriate vendordeps (#5665)
daf7702007 [build] Test each example in a new environment (#5662)
e67df8c180 [wpilib] Const-qualify EncoderSim getters (#5660)
7be290147c [wpiutil] Refactor SpanMatcher and TestPrinters from ntcore (#5658)
9fe258427a [commands] Add proxy factory to Commands (#5603)
633c5a8a22 [commands] Add C++ Requirements struct (#5504)
b265a68eea [commands] Add interruptor parameter to onCommandInterrupt callbacks (#5461)
e93c233d60 [ntcore] Compute Value memory size when creating value (#5657)
5383589f99 [wpinet] uv::Request: Return shared_ptr from Release() (#5656)
40b552be4a [wpinet] uv::Stream: Return error from TryWrite() (#5655)
202a75fe08 [wpinet] RequestImpl: Avoid infinite loop in shared_from_this() (#5654)
8896515eb7 [wpinet] uv::Buffer: Add bytes() accessor (#5653)
ae59a2fba2 [wpinet] uv::Error: Change default error to 0 (#5652)
3b51ecc35b [wpiutil] SpanExtras: Add take_back and take_front (#5651)
17f1062885 Replace std::snprintf() with wpi::format_to_n_c_str() (#5645)
bb39900353 [romi/xrp] Add Romi and XRP Vendordeps (#5644)
cb99517838 [build] cmake: Use default install location on windows for dlls (#5580)
25b0622d4c [build] Add Windows CMake CI (#5516)
34e7849605 Add warning to development builds instructions (NFC) (#5646)
e9e611c9d8 [cameraserver] Remove CameraServer.SetSize() (#5650)
94f58cc536 [wpilib] Remove Compressor.Enabled() (#5649)
4da5aee88a [wpimath] Remove SlewRateLimiter 2 argument constructor (#5648)
2e3ddf5502 Update versions in development builds instructions to 2024 (#5647)
19a8850fb1 [examples] Add TimesliceRobot templates (#3683)
9047682202 [sim] Add XRP-specific plugin (#5631)
575348b81c [wpilib] Use IsSimulation() consistently (#3534)
12e2043b77 [wpilib] Clean up Notifier (#5630)
4bac4dd0f4 [wpimath] Move PIDController from frc2 to frc namespace (#5640)
494cfd78c1 [wpiutil] Fix deprecation warning in LLVM for C++23 (#5642)
43a727e868 [apriltag] Make loadAprilTagFieldLayout throw an unchecked exception instead (#5629)
ad4b017321 [ci] Use Ninja for faster builds (#5626)
4f2114d6f5 Fix warnings from GCC 13 release build (#5637)
e7e927fe26 [build] Also compress debug info for CMake RelWithDebInfo build type (#5638)
205a40c895 [build] Specify zlib for debug info compression (#5636)
707444f000 [apriltag] Suppress -Wtype-limits warning in asserts from GCC 13 (#5635)
3b79cb6ed3 [commands] Revert SubsystemBase deprecation/removal (#5634)
bc7f23a632 [build] Compress Linux debug info (#5633)
57b2d6f254 [build] Update to image 2024 v1.0 (#5625)
339ef1ea39 [wpilib] DataLogManager: Warn user if logging to RoboRIO 1 internal storage (#5617)
7a9a901a73 [build] Fix cmake config files (#5624)
298f8a6e33 [wpilib] Add Mechanism2d tests and make Java impl match C++ (#5527)
d7ef817bae [apriltag] Update apriltag library (#5619)
c3fb31fd0e [docs] Switch to Java 17 api docs (#5613)
bd64f81cf9 [build] Run Google tests in release mode in CI (#5615)
66e6bd81ea [wpimath] Cleanup wpimath/algorithms.md (NFC) (#5621)
4fa56fd884 [build] Add missing find_dependency call (#5623)
f63d958995 [build] Update to native utils 2024.2.0 (#5601)
a9ab08f48b [wpimath] Rename ChassisSpeeds.fromDiscreteSpeeds() to discretize() (#5616)
8e05983a4a [wpimath] Add math docs to plant inversion feedforward internals (NFC) (#5618)
3a33ce918b [ntcore] Add missing StringMap include (#5620)
a6157f184d [wpiutil] timestamp: Add ShutdownNowRio (#5610)
e9f612f581 [build] Guard policy setting for CMake versions below 3.24 (#5612)
1a6df6fec6 [wpimath] Fix DARE Q decomposition (#5611)
9b3f7fb548 [build] Exclude IntelliJ folders from spotless XML (#5602)
814f18c7f5 [wpimath] Fix computation of C for DARE (A, C) detectability check (#5609)
ac23f92451 [hal] Add GetTeamNumber (#5596)
a750bee54d [wpimath] Use std::norm() in IsStabilizable() (#5599)
8e2465f8a0 [wpimath] Add arithmetic functions to wheel speeds classes (#5465)
10d4f5b5df [wpimath] Clean up notation in DARE precondition docs (#5595)
b2dd59450b [hal] Fix unfinished/incorrect GetCPUTemp functions (#5598)
99f66b1e24 [wpimath] Replace frc/EigenCore.h typedefs with Eigen's where possible (#5597)
383289bc4b [build] Make custom CMake macros use lowercase (#5594)
45e7720ec1 [build] Add error message when downloading files in CMake (#5593)
4e0d785356 [wpimath] ChassisSpeeds: document that values aren't relative to the robot (NFC) (#5551)
3c04580a57 [commands] ProxyCommand: Use inner command name in unique_ptr constructor (#5570)
cf19102c4a [commands] SelectCommand: Fix leakage and multiple composition bug (#5571)
171375f440 [ntcoreffi] Link to NI libraries (#5589)
89add5d05b Disable flaky tests (#5591)
a8d4b162ab [ntcore] Remove RPC manual tests (#5590)
39a73b5b58 [commands] C++: Add CommandPtr supplier constructor to ProxyCommand (#5572)
36d514eae7 [commands] Refactor C++ ScheduleCommand to use SmallSet (#5568)
52297ffe29 [commands] Add idle command (#5555)
67043a8eeb [wpimath] Add angular jerk unit (#5582)
51b0fb1492 [wpimath] Fix incorrect header inclusion in angular_acceleration.h (#5587)
b7657a8e28 [wpimath] Split WPIMathJNI into logical chunks (#5552)
ea17f90f87 [build] Fix tool builds with multiple arm platforms installed (#5586)
f1d7b05723 [wpimath] Clean up unit formatter (#5584)
d7264ff597 Replace wpi::errs() usage with fmtlib (#5560)
ab3bf39e0e [wpiutil] Upgrade to fmt 10.1.1 (#5585)
165ebe4c79 Upgrade to fmt 10.1.0 (#5326)
8e2a7fd306 Include thirdparty libraries with angle brackets (#5578)
e322ab8e46 [wpimath] Fix docs for DARE ABQRN stabilizability check (NFC) (#5579)
360fb835f4 [upstream_utils] Handle edge case in filename matches (#5576)
9d86624c00 [build] Fix CMake configure warnings (#5577)
969979d6c7 [wpiutil] Update to foonathan memory 0.7-3 (#5573)
0d2d989e84 [wpimath] Update to gcem 1.17.0 (#5575)
cf86af7166 [wpiutil] Update to mpack 1.1.1 (#5574)
a0c029a35b [commands] Fix dangling SelectCommand documentation (NFC) (#5567)
349141b91b [upstream_utils] Document adding a patch (NFC) (#5432)
7889b35b67 [wpimath] Add RamseteController comparison to LTV controller docs (NFC) (#5559)
b3ef536677 [build] Ignore nt/sim json files in spotless (#5565)
ed895815b5 [build] Compile Java with UTF-8 encoding (#5564)
2e4ad35e36 [wpiutil] jni_util: Add JSpan and CriticalJSpan (#5554)
8f3d6a1d4b [wpimath] Remove discretizeAQTaylor() (#5562)
7c20fa1b18 [wpimath] Refactor DARE tests to reduce RAM usage at compile time (#5557)
89e738262c [ntcore] Limit buffer pool size to 64KB per connection (#5485)
96f7fa662e Upgrade Maven dependencies (#5553)
7a2d336d52 [wpinet] Leak multicast handles during windows shutdown (#5550)
f9e2757d8f [wpimath] Use JDoubleArrayRef in all JNI functions (#5546)
0cf6e37dc1 [wpimath] Make LTV controller constructors use faster DARE solver (#5543)
6953a303b3 [build] Fix the windows build with fmt (#5544)
7a37e3a496 [wpimath] Correct Rotation3d::RotateBy doc comment (NFC) (#5541)
186b409e16 [wpimath] Remove internal Eigen header include (#5539)
03764dfe93 [wpimath] Add static matrix support to DARE solver (#5536)
394cfeadbd [wpimath] Use SDA algorithm instead of SSCA for DARE solver (#5526)
a4b7fde767 [wpilib] Add mechanism specific SetState overloads to physics sims (#5534)
8121566258 [wpimath] Fix CoordinateSystem.convert() Transform3d overload (#5532)
b542e01a0b [glass] Fix array crash when clearing existing workspace (#5535)
e2e1b763b2 [wpigui] Fix PFD file dialogs not closing after window closing (#5530)
86d7bbc4e4 [examples] Add Java Examples and Templates for the XRP (#5529)
e8b5d44752 [wpimath] Make Java Quaternion use doubles instead of Vector (#5525)
38c198fa64 [myRobot] Add apriltags to myRobot build (#5528)
00450c3548 [wpimath] Upgrade to EJML 0.42 (#5531)
faf3cecd83 [wpimath] Don't copy Matrix and underlying storage in VecBuilder (#5524)
6b896a38dc [build] Don't enforce WITH_FLAT_INSTALL with MSVC (part 2) (#5517)
c01814b80e [wpiutil] Add C API for DataLog (#5509)
b5bd0771eb [wpimath] Document extrinsic vs intrinsic rotations (NFC) (#5508)
84ed8aec05 [build] Don't enforce WITH_FLAT_INSTALL with MSVC (#5515)
999f677d8c [ntcoreffi] Add WPI_Impl_SetupNowRio to exported symbols (#5510)
338f37d302 Fix header sorting of libssh (#5507)
75cbd9d6d0 [glass] Add background color selector to glass plots (#5506)
e2c190487b [examples] Add flywheel bang-bang controller example (#4071)
c52dad609e [wpinet] WebSocket: Send pong in response to ping (#5498)
e2d17a24a6 [hal] Expose power rail disable and cpu temp functionality (#5477)
3ad5d2e42d [hal,wpiutil] Use HMB for FPGA Timestamps (#5499)
b46a872494 [ntcore] Remove pImpl from implementation (#5480)
d8c59ccc71 [wpimath] Add tests for MathUtil clamp() and interpolate() (#5501)
0552c8621d [glass,ov] Improve Glass and OutlineViewer title bar message (#5502)
90e37a129f [wpiutil,wpimath] Add generic InterpolatingTreeMap (#5372)
d83a6edc20 [wpilib] Update GetMatchTime docs and units (#5232)
6db2c42966 [wpimath] Trajectory: Throw on empty lists of States (#5497)
21439b606c [wpimath] Disallow LTV controller max velocities above 15 m/s (#5495)
7496e0d208 [ntcore] Value: More efficiently store arrays (#5484)
0c93aded8a [wpimath] Change kinematics.ToTwist2d(end - start) to kinematics.ToTwist2d(start, end) (#5493)
815a8403e5 [wpimath] Give infeasible trajectory constraints a better exception message (#5492)
35a8b129d9 [wpimath] Add RotateBy() function to pose classes (#5491)
26d6e68c8f [upstream_utils] Add GCEM to CI (#5483)
6aa469ae45 [wpilib] Document how to create LinearSystem object for physics sim classes (NFC) (#5488)
a01b6467d3 [wpimath] Link to docs on LQR and KF tolerances (#5486)
d814f1d123 [wpimath] Fix copy-paste error from Pose2d docs (NFC) (#5490)
98f074b072 [wpimath] Add folder prefix to geometry includes (#5489)
e9858c10e9 [glass] Add tooltips for NT settings (#5476)
12dda24f06 [examples] Fix C robot template not correctly looping (#5474)
fc75d31755 [apriltag] Update apriltaglib (#5475)
a95994fff6 [wpiutil] timestamp: Call FPGA functions directly (#5235)
2ba8fbb6f4 [wpimath] Improve documentation for SwerveModulePosition::operator- (#5468)
b8cdf97621 [build] Prepare for Windows arm64 builds (#5390)
552f4b76b5 [wpimath] Add FOC-enabled Falcon constants to the DCMotor class (#5469)
1938251436 [examples] Add Feedforward to ElevatorProfiledPid (#5300)
873c2a6c10 [examples] Update ElevatorTrapezoidProfile example (#5466)
99b88be4f3 [wpilib] Reduce usage of NTSendable (#5434)
d125711023 [hal] Fix Java REVPH faults bitfield (take 2) (#5464)
c3fab7f1f2 [ntcore] Don't update timestamp when value is unchanged (#5356)
5ec7f18bdc [wpilib] EventLoop docs: Remove BooleanEvent references (NFC) (#5463)
c065ae1fcf [wpiunits] Add subproject for a Java typesafe unit system (#5371)
44acca7c00 [wpiutil] Add ClassPreloader (#5365)
88b11832ec [hal] Fix Java REVPH faults bitfield (#5148)
fb57d82e52 [ntcore] Enhance Java raw value support
3a6e40a44b [wpiutil] Enhance DataLog Java raw value support
8dae5af271 [wpiutil] Add compile-time string utilities (ct_string) (#5462)
fc56f8049a [wpilib] DriverStation: Change alliance station to use optional (#5229)
ef155438bd [build] Consume libuv via cmake config instead of via pkg-config (#5438)
86e91e6724 [wpimath] Refactor TrapezoidProfile API (#5457)
72a4543493 [wpilib] DutyCycleEncoderSim: Expand API (#5443)
657338715d [wpimath] Add ChassisSpeeds method to fix drifting during compound swerve drive maneuvers (#5425)
1af224c21b Add missing <functional> includes (#5459)
0b91ca6d5a [wpilib] SendableChooser: Add onChange listener (#5458)
6f7cdd460e [wpimath] Pose3d: Switch to JNI for exp and log (#5444)
c69e34c80c [wpimath] ChassisSpeeds: Add arithmetic functions (#5293)
335e7dd89d [wpilib] Simulation: Add ctor parameter to set starting state of mechanism sims (#5288)
14f30752ab [wpilib] Deprecate Accelerometer and Gyro interfaces (#5445)
70b60e3a74 [commands] Trigger: Fix method names in requireNonNullParam (#5454)
593767c8c7 [wpimath] Improve Euler angle calculations in gimbal lock (#5437)
daf022d3da [build] Make devImplementation inherit from implementation (#5450)
9b8d90b852 [examples] Convert the unitless joystick inputs to actual physical units (#5451)
1f6428ab63 [ntcore] Fix undefined comparison behavior when array is empty (#5448)
17eb9161cd Update code owners for removal of old commands (#5447)
3c4b58ae1e [wpinet] Upgrade to libuv 1.46.0 (#5446)
aaea85ff16 [commands] Merge CommandBase into Command and SubsystemBase into Subsystem (#5392)
7ac932996a [ci] Use PAT for workflow dispatch (#5442)
efe1987e8b [ci] Trigger pages repo workflow (#5441)
828bc5276f [wpiutil] Upgrade to LLVM 16.0.6 (#5435)
701df9eb87 [ci] Change documentation publish to single-commit (#5440)
e5452e3f69 [wpiutil] Add WPICleaner and an example how to use it (#4850)
7a099cb02a [commands] Remove deprecated classes and functions (#5409)
b250a03944 [wpilib] Add function to wait for DS Connection (#5230)
a6463ed761 [wpiutil] Fix unused variable warning in release build (#5430)
f031513470 [ntcore] NetworkTable::GetSubTables(): Remove duplicates (#5076)
f8e74e2f7c [hal] Unify PWM simulation Speed, Position, and Raw (#5277)
fd5699b240 Remove references to Drake (#5427)
e2d385d80a [build] cmake: Respect USE_SYSTEM_FMTLIB (#5429)
d37f990ce3 [hal] Fix HAL Relay/Main doc module (NFC) (#5422)
a7a8b874ac [docs] Expand HAL_ENUM in doxygen docs (#5421)
3a61deedde [wpimath] Rotation2d: Only use gcem::hypot when constexpr evaluated (#5419)
96145de7db [examples] Fix formatting (NFC) (#5420)
fffe6a7b9a [examples] Improve Pneumatics example coverage in Solenoid and RapidReactCmdBot examples (#4998)
6b5817836d [wpimath] Add tolerance for some tests (#5416)
3233883f3e [cscore] Fix warnings on macos arm (#5415)
c4fc21838f [commands] Add ConditionalCommand getInterruptionBehavior (#5161)
89fc51f0d4 Add tests for SendableChooser and Command Sendable functionality (#5179)
663bf25aaf [docs] Generate docs for symbols in __cplusplus (#5412)
fe32127ea8 [command] Clean up Command doc comments (NFC) (#5321)
c1a01569b4 [wpilib][hal] PWM Raw using microseconds (#5283)
1fca519fb4 [wpiutil] Remove remnants of ghc fs and tcb_span libraries (#5411)
90602cc135 [github] Update issue template to collect more project info (#5090)
34412ac57e [build] Exclude files in bin from Spotless (#5410)
61aa60f0e3 [wpilib] Add robot callback that is called when the DS is initially connected (#5231)
ebae341a91 [commands] Add test for subsystem registration and periodic (#5408)
5d3a133f9f Remove spaces in NOLINT comments (#5407)
3a0e484691 [wpimath] Fix clang-tidy warnings (#5403)
eb3810c765 [wpiutil] Fix clang-tidy warnings (#5406)
c4dc697192 [hal] WS Simulation: Add message filtering capability (#5395)
0eccc3f247 [ntcore] Fix clang-tidy warnings (#5405)
f4dda4bac0 [hal] Add javadocs for JNI (NFC) (#5298)
1c20c69793 [cscore] Fix clang-tidy warnings (#5404)
1501607e48 [commands] Fix clang-tidy warnings (#5402)
991f4b0f62 [wpimath] PIDController: Add IZone (#5315)
f5b0d1484b [wpimath] Add isNear method to MathUtil (#5353)
2ce248f66c [hal] Fix clang-tidy warnings (#5401)
5fc4aee2d2 [wpimath] SwerveDriveKinematics: Rename currentChassisSpeed to desiredChassisSpeed (#5393)
50b90ceb54 [wpimath] SwerveDriveKinematics: Add reset method (#5398)
316cd2a453 [commands] Notify DriverStationSim in CommandTestBaseWithParam (#5400)
d4ea5fa902 [cscore] VideoMode: Add equals override (Java) (#5397)
d6bd72d738 [wpimath] ProfiledPIDController: Add getConstraints (#5399)
25ad5017a9 [wpimath] Refactor kinematics, odometry, and pose estimator (#5355)
5c2addda0f [doc] Add missing pneumatics docs (NFC) (#5389)
c3e04a6ea2 Fix loading tests on macos 12 (#5388)
d5ed9fb859 [wpimath] Create separate archive with just units headers (#5383)
901ab693d4 [wpimath] Use UtilityClassTest for more utility classes (#5384)
9d53231b01 [wpilib] DataLogManager: Add warning for low storage space (#5364)
d466933963 [wpiutil] Group doxygen into MPack module (#5380)
652d1c44e3 [wpiutil] Upgrade to macOS 12 to remove concept shims (#5379)
6414be0e5d [wpimath] Group units doxygen modules (#5382)
7ab5800487 [wpiutil] Fix docs typo in SmallVector (#5381)
59905ea721 Replace WPI_DEPRECATED() macro with [[deprecated]] attribute (#5373)
753cb49a5e [ntcore] Fix doxygen module in generated C types (NFC) (#5374)
1c00a52b67 [hal] Expose CAN timestamp base clock (#5357)
91cbcea841 Replace SFINAE with concepts (#5361)
d57d1a4598 [wpimath] Remove unnecessary template argument from unit formatter (#5367)
5acc5e22aa [wpimath] Only compute eigenvalues with EigenSolvers (#5369)
d3c9316a97 extend shuffleboard test timeout (#5377)
1ea868081a [ci] Fix /format command (#5376)
5fac18ff4a Update formatting to clang-format 16 (#5370)
a94a998002 [wpimath] Generalize Eigen formatter (#5360)
125f6ea101 [wpimath] Make SwerveDriveKinematics::ToChassisSpeeds() take const-ref argument (#5363)
51066a5a8a [wpimath] Move unit formatters into units library (#5358)
282c032b60 [wpilibc] Add unit-aware Joystick.GetDirection() (#5319)
073d19cb69 [build] Fix CMake warning (#5359)
01490fc77b [wpiutil] DataLog: Add documentation for append methods (NFC) (#5348)
c9b612c986 [wpilibcExamples] Make C++ state-space elevator KF and LQR match Java (#5346)
eed1e6e3cb [wpimath] Replace DiscretizeAQTaylor() with DiscretizeAQ() (#5344)
c976f40364 [readme] Document how to run examples in simulation (#5340)
4d28bdc19e [ci] Update Github Pages deploy action parameters (#5343)
e0f851871f [ci] Fix github pages deploy version (#5342)
063c8cbedc Run wpiformat (NFC) (#5341)
96e41c0447 [ci] Update deploy and sshagent actions (#5338)
fd294bdd71 [build] Fix compilation with GCC 13 (#5322)
d223e4040b [dlt] Add delete without download functionality (#5329)
abc19bcb43 [upstream_utils] Zero out commit hashes and show 40 digits in index hashes (#5336)
e909f2e687 [build] Update gradle cache repo name (#5334)
52bd5b972d [wpimath] Rewrite DARE solver (#5328)
3876a2523a [wpimath] Remove unused MatrixImpl() function (#5330)
c82fcb1975 [wpiutil] Add reflection based cleanup helper (#4919)
15ba95df7e [wpiutil] Use std::filesystem (#4941)
77c2124fc5 [wpimath] Remove Eigen's custom STL types (#4945)
27fb47ab10 [glass] Field2D: Embed standard field images (#5159)
102e4f2566 [wpilib] Remove deprecated and broken SPI methods (#5249)
463a90f1df [wpilib, hal] Add function to read the RSL state (#5312)
7a90475eec [wpilib] Update RobotBase documentation (NFC) (#5320)
218cfea16b [wpilib] DutyCycleEncoder: Fix reset behavior (#5287)
91392823ff [build] Update to gradle 8.1 (#5303)
258b7cc48b [wpilibj] Filesystem.getDeployDirectory(): Strip JNI path from user.dir (#5317)
26cc43bee1 [wpilib] Add documentation to SPI mode enum (NFC) (#5324)
ac4da9b1cb [hal] Add HAL docs for Addressable LED (NFC) (#5304)
21d4244cf7 [wpimath] Fix DCMotor docs (NFC) (#5309)
1dff81bea7 [hal] Miscellaneous HAL doc fixes (NFC) (#5306)
7ce75574bf [wpimath] Upgrade to Drake v1.15.0 (#5310)
576bd646ae [hal] Add CANManufacturer for Redux Robotics (#5305)
ee3b4621e5 [commands] Add onlyWhile and onlyIf (#5291)
40ca094686 [commands] Fix RepeatCommand calling end() twice (#5261)
9cbeb841f5 [rtns] Match imaging tool capitalization (#5265)
a63d06ff77 [examples] Add constants to java gearsbot example (#5248)
b6c43322a3 [wpilibc] XboxController: Add return tag to docs (NFC) (#5246)
5162d0001c [hal] Fix and document addressable LED timings (#5272)
90fabe9651 [wpilibj] Use method references in drive class initSendable() (#5251)
24828afd11 [wpimath] Fix desaturateWheelSpeeds to account for negative speeds (#5269)
e099948a77 [wpimath] Clean up rank notation in docs (NFC) (#5274)
fd2d8cb9c1 [hal] Use std::log2() for base-2 logarithm (#5278)
ba8c64bcff [wpimath] Fix misspelled Javadoc parameters in pose estimators (NFC) (#5292)
f53c6813d5 [wpimath] Patch Eigen warnings (#5290)
663703d370 [gitattributes] Mark json files as lf text files (#5256)
aa34aacf6e [wpilib] Shuffleboard: Keep duplicates on SelectTab() (#5198)
63512bbbb8 [wpimath] Fix potential divide-by-zero in RKDP (#5242)
9227b2166e [wpilibj] DriverStation: Fix joystick data logs (#5240)
fbf92e9190 [wpinet] ParallelTcpConnector: don't connect to duplicate addresses (#5169)
2108a61362 [ntcore] NT4 client: close timed-out connections (#5175)
0a66479693 [ntcore] Optimize scan of outgoing messages (#5227)
b510c17ef6 [hal] Fix RobotController.getComments() mishandling quotes inside the comments string (#5197)
e7a7eb2e93 [commands] WaitCommand: Remove subclass doc note (NFC) (#5200)
a465f2d8f0 [examples] Shuffleboard: Correct parameter order (#5204)
a3364422fa LICENSE.md: Bump year to 2023 (#5195)
df3242a40a [wpimath] Fix NaN in C++ MakeCostMatrix() that takes an array (#5194)
00abb8c1e0 [commands] RamseteCommand: default-initialize m_prevSpeeds (#5188)
c886273fd7 [wpilibj] DutyCycleEncoder.setDistancePerRotation(): fix simulation (#5147)
53b5fd2ace [ntcore] Use int64 for datalog type string (#5186)
56b758320f [wpilib] DataLogManager: increase time for datetime to be valid (#5185)
08f298e4cd [wpimath] Fix Pose3d log returning Twist3d NaN for theta between 1E-8 and 1E-7 (#5168)
6d0c5b19db [commands] CommandScheduler.isComposed: Remove incorrect throws clause (NFC) (#5183)
0d22cf5ff7 [wpilib] Fix enableLiveWindowInTest crashing in disabled (#5173)
32ec5b3f75 [wpilib] Add isTestEnabled and minor docs cleanup (#5172)
e5c4c6b1a7 [wpimath] Fix invalid iterator access in TimeInterpolatableBuffer (#5138)
099d048d9e [wpimath] Fix Pose3d log returning Twist3d NaN for theta between 1E-9 and 1E-8 (#5143)
4af84a1c12 Fix Typos (NFC) (#5137)
ce3686b80d [wpimath] Check LTV controller max velocity precondition (#5142)
4b0eecaee0 [commands] Subsystem: Add default command removal method (#5064)
edf4ded412 [wpilib] PH: Revert to 5V rail being fixed 5V (#5122)
4c46b6aff9 [wpilibc] Fix DataLogManager crash on exit in sim (#5125)
490ca4a68a [wpilibc] Fix XboxController::GetBackButton doc (NFC) (#5131)
cbb5b0b802 [hal] Simulation: Fix REV PH solenoids 8+ (#5132)
bb7053d9ee [hal] Fix HAL_GetRuntimeType being slow on the roboRIO (#5130)
9efed9a533 Update .clang-format to c++20 (#5121)
dbbfe1aed2 [wpilib] Use PH voltage to calc Analog pressure switch threshold (#5115)
de65a135c3 [wpilib] DutyCycleEncoderSim: Add channel number constructor (#5118)
3e9788cdff [docs] Strip path from generated NT docs (#5119)
ecb072724d [ntcore] Client::Disconnect(): actually close connection (#5113)
0d462a4561 [glass] NT view: Change string/string array to quoted (#5111)
ba37986561 [ntcore] NetworkClient::Disconnect: Add null check (#5112)
25ab9cda92 [glass,ov] Provide menu item to create topic from root (#5110)
2f6251d4a6 [glass] Set default value when publishing new topic (#5109)
e9a7bed988 [wpimath] Add timestamp getter to MathShared (#5091)
9cc14bbb43 [ntcore] Add stress test to dev executable (#5107)
8068369542 [wpinet] uv: Stop creating handles when closing loop (#5102)
805c837a42 [ntcore] Fix use-after-free in server (#5101)
fd18577ba0 [commands] Improve documentation of addRequirements (NFC) (#5103)
74dea9f05e [wpimath] Fix exception for empty pose buffer in pose estimators (#5106)
9eef79d638 [wpilib] PneumaticHub: Document range of enableCompressorAnalog (NFC) (#5099)
843574a810 [ntcore] Use wpi::Now instead of loop time for transmit time
226ef35212 [wpinet] WebSocket: Reduce server send frame overhead
b30664d630 [ntcore] Reduce initial connection overhead
804e5ce236 [examples] MecanumDrive: Fix axis comment in C++ example (NFC) (#5096)
49af88f2bb [examples] ArmSimulation: Fix flaky test (#5093)
d56314f866 [wpiutil] Disable mock time on the Rio (#5092)
43975ac7cc [examples] ArmSimulation, ElevatorSimulation: Extract mechanism to class (#5052)
5483464158 [examples, templates] Improve descriptions (NFC) (#5051)
785e7dd85c [wpilibc] SendableChooser: static_assert copy- and default-constructibility (#5078)
e57ded8c39 [ntcore] Improve disconnect error reporting (#5085)
01f0394419 [wpinet] Revert WebSocket: When Close() is called, call closed immediately (#5084)
59be120982 [wpimath] Fix Pose3d exp()/log() and add rotation vector constructor to Rotation3d (#5072)
37f065032f [wpilib] Refactor TimedRobot tests (#5068)
22a170bee7 [wpilib] Add Notifier test (#5070)
2f310a748c [wpimath] Fix DCMotor.getSpeed() (#5061)
b43ec87f57 [wpilib] ElevatorSim: Fix WouldHitLimit methods (#5057)
19267bef0c [ntcore] Output warning on property set on unpublished topic (#5059)
84cbd48d84 [ntcore] Handle excludeSelf on SetDefault (#5058)
1f35750865 [cameraserver] Add GetInstance() to all functions (#5054)
8230fc631d [wpilib] Revert throw on nonexistent SimDevice name in SimDeviceSim (#5053)
b879a6f8c6 [wpinet] WebSocket: When Close() is called, call closed immediately (#5047)
49459d3e45 [ntcore] Change wire timeout to fixed 1 second (#5048)
4079eabe9b [wpimath] Discard stale pose estimates (#5045)
fe5d226a19 [glass] Fix option for debug-level NT logging (#5049)
b7535252c2 [ntcore] Don't leak buffers in rare WS shutdown case (#5046)
b61ac6db33 [ntcore] Add client disconnect function (#5022)
7b828ce84f [wpimath] Add nearest to Pose2d and Translation2d (#4882)
08a536291b [examples] Improvements to Elevator Simulation Example (#4937)
193a10d020 [wpigui] Limit frame rate to 120 fps by default (#5030)
7867bbde0e [wpilib] Clarify DS functions provided by FMS (NFC) (#5043)
fa7c01b598 [glass] Add option for debug-level NT logging (#5007)
2b81610248 [wpiutil] Add msgpack to datalog Python example (#5032)
a4a369b8da CONTRIBUTING.md: Add unicodeit CLI to math docs guidelines (#5031)
d991f6e435 [wpilib] Throw on nonexistent SimDevice name in SimDeviceSim constructor (#5041)
a27a047ae8 [hal] Check for null in getSimDeviceName JNI (#5038)
2f96cae31a [examples] Hatchbots: Add telemetry (#5011)
83ef8f9658 [simulation] GUI: Fix buffer overflow in joystick axes copy (#5036)
4054893669 [commands] Fix C++ Select() factory (#5024)
f75acd11ce [commands] Use Timer.restart() (#5023)
8bf67b1b33 [wpimath] PIDController::Calculate(double, double): update setpoint flag (#5021)
49bb1358d8 [wpiutil] MemoryBuffer: Fix GetMemoryBufferForStream (#5017)
9c4c07c0f9 [wpiutil] Remove NDEBUG check for debug-level logging (#5018)
1a47cc2e86 [ntcore] Use full handle when subscribing (#5013)
7cd30cffbc Ignore networktables.json (#5006)
92aecab2ef [commands] Command controllers are not subclasses (NFC) (#5000)
8785bba080 [ntcore] Special-case default timestamps (#5003)
9e5b7b8040 [ntcore] Handle topicsonly followed by value subscribe (#4991)
917906530a [wpilib] Add Timer::Restart() (#4963)
00aa66e4fd [wpimath] Remove extraneous assignments from DiscretizeAB() (#4967)
893320544a [examples] C++ RamseteCommand: Fix units (#4954)
b95d0e060d [wpilib] XboxController: Fix docs discrepancy (NFC) (#4993)
008232b43c [ntcore] Write empty persistent file if none found (#4996)
522be348f4 [examples] Rewrite tags (NFC) (#4961)
d48a83dee2 [wpimath] Update Wikipedia links for quaternion to Euler angle conversion (NFC) (#4995)
504fa22143 [wpimath] Workaround intellisense Eigen issue (#4992)
b2b25bf09f [commands] Fix docs inconsistency for toggleOnFalse(Command) (NFC) (#4978)
ce3dc4eb3b [hal] Properly use control word that is in sync with DS data (#4989)
1ea48caa7d [wpilib] Fix C++ ADXRS450 and Java SPI gyro defs (#4988)
fb101925a7 [build] Include wpimathjni in commands binaries (#4981)
657951f6dd [starter] Add a process starter for use by the installer for launching tools (#4931)
a60ca9d71c [examples] Update AprilTag field load API usage (#4975)
f8a45f1558 [wpimath] Remove print statements from tests (#4977)
ecba8b99a8 [examples] Fix swapped arguments in MecanumControllerCommand example (#4976)
e95e88fdf9 [examples] Add comment to drivedistanceoffboard example (#4877)
371d15dec3 [examples] Add Computer Vision Pose Estimation and Latency Compensation Example (#4901)
cb9b8938af [sim] Enable docking in the GUI (#4960)
3b084ecbe0 [apriltag] AprilTagFieldLayout: Improve API shape for loading builtin JSONs (#4949)
27ba096ea1 [wpilib] Fix MOI calculation error in SingleJointedArmSim (#4968)
42c997a3c4 [wpimath] Fix Pose3d exponential and clean up Pose3d logarithm (#4970)
5f1a025f27 [wpilibj] Fix typo in MecanumDrive docs (NFC) (#4969)
0ebf79b54c [wpimath] Fix typo in Pose3d::Exp() docs (NFC) (#4966)
a8c465f3fb [wpimath] HolonomicDriveController: Add getters for the controllers (#4948)
a7b1ab683d [wpilibc] Add unit test for fast deconstruction of GenericHID (#4953)
bd6479dc29 [build] Add Spotless for JSON (#4956)
5cb0340a8c [hal, wpilib] Load joystick values upon code initialization (#4950)
ab0e8c37a7 [readme] Update build requirements (NFC) (#4947)
b74ac1c645 [build] Add apriltag to C++ cmake example builds (#4944)
cf1a411acf [examples] Add example programs for AprilTags detection (#4932)
1e05b21ab5 [wpimath] Fix PID atSetpoint to not return true prematurely (#4906)
e5a6197633 [wpimath] Fix SwerveDriveKinematics not initializing a new array each time (#4942)
039edcc23f [ntcore] Queue current value on subscriber creation (#4938)
f7f19207e0 [wpimath] Allow multiple vision measurements from same timestamp (#4917)
befd12911c [commands] Delete UB-causing rvalue variants of CommandPtr methods (#4923)
34519de60a [commands] Fix spacing in command composition exception (#4924)
dc4355c031 [hal] Add handle constructor and name getters for sim devices (#4925)
53d8d33bca [hal, wpilibj] Add missing distance per pulse functions to EncoderSim (#4928)
530ae40614 [apriltag] Explain what April tag poses represent (NFC) (#4930)
79f565191e [examples] DigitalCommunication, I2CCommunication: Add tests (#4865)
2cd9be413f [wpilib, examples] Cleanup PotentiometerPID, Ultrasonic, UltrasonicPID examples (#4893)
babb0c1fcf [apriltag] Add 2023 field layout JSON (#4912)
330ba45f9c [wpimath] Fix swerve kinematics util classes equals function (#4907)
51272ef6b3 [fieldImages] Add 2023 field (#4915)
0d105ab771 [commands] Deduplicate command test utils (#4897)
cf4235ea36 [wpiutil] Guard MSVC pragma in SymbolExports.h (#4911)
2d4b7b9147 [build] Update opencv version in opencv.gradle (#4909)
aec6f3d506 [ntcore] Fix client flush behavior (#4903)
bfe346c76a [build] Fix cmake java resources (#4898)

Change-Id: Ia1dd90fe42c6cd5df281b8a5b710e136f54355f4
git-subtree-dir: third_party/allwpilib
git-subtree-split: f1a82828fed8950f9a3f1586c44327027627a0c8
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/wpiutil/.styleguide b/wpiutil/.styleguide
index 9c1196e..4932e16 100644
--- a/wpiutil/.styleguide
+++ b/wpiutil/.styleguide
@@ -39,6 +39,13 @@
   wpiutil
 }
 
+includeOtherLibs {
+  ^fmt/
+  ^google/
+  ^gmock/
+  ^gtest/
+}
+
 includeGuardRoots {
   wpiutil/src/main/native/cpp/
   wpiutil/src/main/native/include/
diff --git a/wpiutil/CMakeLists.txt b/wpiutil/CMakeLists.txt
index 9b86e14..a319293 100644
--- a/wpiutil/CMakeLists.txt
+++ b/wpiutil/CMakeLists.txt
@@ -4,6 +4,7 @@
 include(GenResources)
 include(CompileWarnings)
 include(AddTest)
+include(DownloadAndCheck)
 
 file(GLOB wpiutil_jni_src src/main/native/cpp/jni/WPIUtilJNI.cpp src/main/native/cpp/jni/DataLogJNI.cpp)
 
@@ -14,18 +15,18 @@
   include(UseJava)
   set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
 
-  if(NOT EXISTS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/jackson-core-2.12.4.jar")
+  if(NOT EXISTS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/jackson-core-2.15.2.jar")
         set(BASE_URL "https://search.maven.org/remotecontent?filepath=")
         set(JAR_ROOT "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson")
 
         message(STATUS "Downloading Jackson jarfiles...")
 
-        file(DOWNLOAD "${BASE_URL}com/fasterxml/jackson/core/jackson-core/2.12.4/jackson-core-2.12.4.jar"
-            "${JAR_ROOT}/jackson-core-2.12.4.jar")
-        file(DOWNLOAD "${BASE_URL}com/fasterxml/jackson/core/jackson-databind/2.12.4/jackson-databind-2.12.4.jar"
-            "${JAR_ROOT}/jackson-databind-2.12.4.jar")
-        file(DOWNLOAD "${BASE_URL}com/fasterxml/jackson/core/jackson-annotations/2.12.4/jackson-annotations-2.12.4.jar"
-            "${JAR_ROOT}/jackson-annotations-2.12.4.jar")
+        download_and_check("${BASE_URL}com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar"
+            "${JAR_ROOT}/jackson-core-2.15.2.jar")
+        download_and_check("${BASE_URL}com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2.jar"
+            "${JAR_ROOT}/jackson-databind-2.15.2.jar")
+        download_and_check("${BASE_URL}com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2.jar"
+            "${JAR_ROOT}/jackson-annotations-2.15.2.jar")
 
         message(STATUS "All files downloaded.")
     endif()
@@ -33,18 +34,27 @@
   file(GLOB JACKSON_JARS
         ${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/*.jar)
 
-  set(CMAKE_JAVA_INCLUDE_PATH wpiutil.jar ${JACKSON_JARS})
+  if(NOT EXISTS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/quickbuf/quickbuf-runtime-1.3.2.jar")
+        set(BASE_URL "https://search.maven.org/remotecontent?filepath=")
+        set(JAR_ROOT "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/quickbuf")
+
+        message(STATUS "Downloading Quickbuf jarfile...")
+        file(DOWNLOAD "${BASE_URL}us/hebi/quickbuf/quickbuf-runtime/1.3.2/quickbuf-runtime-1.3.2.jar"
+            "${JAR_ROOT}/quickbuf-runtime-1.3.2.jar")
+
+        message(STATUS "Downloaded.")
+  endif()
+
+  file(GLOB QUICKBUF_JAR
+        ${WPILIB_BINARY_DIR}/wpiutil/thirdparty/quickbuf/*.jar)
+
+  set(CMAKE_JAVA_INCLUDE_PATH wpiutil.jar ${JACKSON_JARS} ${QUICKBUF_JAR})
 
   set(CMAKE_JNI_TARGET true)
 
   file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
 
-  if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
-    set(CMAKE_JAVA_COMPILE_FLAGS "-h" "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
-    add_jar(wpiutil_jar ${JAVA_SOURCES} INCLUDE_JARS ${JACKSON_JARS} OUTPUT_NAME wpiutil)
-  else()
-    add_jar(wpiutil_jar ${JAVA_SOURCES} INCLUDE_JARS ${JACKSON_JARS} OUTPUT_NAME wpiutil GENERATE_NATIVE_HEADERS wpiutil_jni_headers)
-  endif()
+  add_jar(wpiutil_jar ${JAVA_SOURCES} INCLUDE_JARS ${JACKSON_JARS} ${QUICKBUF_JAR} OUTPUT_NAME wpiutil GENERATE_NATIVE_HEADERS wpiutil_jni_headers)
 
   get_property(WPIUTIL_JAR_FILE TARGET wpiutil_jar PROPERTY JAR_FILE)
   install(FILES ${WPIUTIL_JAR_FILE} DESTINATION "${java_lib_dest}")
@@ -57,20 +67,35 @@
 
   set_property(TARGET wpiutiljni PROPERTY FOLDER "libraries")
 
-  if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
-    target_include_directories(wpiutiljni PRIVATE ${JNI_INCLUDE_DIRS})
-    target_include_directories(wpiutiljni PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
-  else()
-    target_link_libraries(wpiutiljni PRIVATE wpiutil_jni_headers)
-  endif()
+  target_link_libraries(wpiutiljni PRIVATE wpiutil_jni_headers)
   add_dependencies(wpiutiljni wpiutil_jar)
 
-  if (MSVC)
-    install(TARGETS wpiutiljni RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
-  endif()
+  install(TARGETS wpiutiljni EXPORT wpiutiljni)
 
-  install(TARGETS wpiutiljni EXPORT wpiutiljni DESTINATION "${main_lib_dest}")
+endif()
 
+if (WITH_JAVA_SOURCE)
+  find_package(Java REQUIRED)
+  include(UseJava)
+  file(GLOB WPIUTIL_SOURCES src/main/java/edu/wpi/first/util/*.java)
+  file(GLOB WPIUTIL_CLEANUP_SOURCES src/main/java/edu/wpi/first/util/cleanup/*.java)
+  file(GLOB WPIUTIL_CONCURRENT_SOURCES src/main/java/edu/wpi/first/util/concurrent/*.java)
+  file(GLOB WPIUTIL_DATALOG_SOURCES src/main/java/edu/wpi/first/util/datalog/*.java)
+  file(GLOB WPIUTIL_FUNCTION_SOURCES src/main/java/edu/wpi/first/util/function/*.java)
+  file(GLOB WPIUTIL_SENDABLE_SOURCES src/main/java/edu/wpi/first/util/sendable/*.java)
+  add_jar(wpiutil_src_jar
+  RESOURCES NAMESPACE "edu/wpi/first/util" ${WPIUTIL_SOURCES}
+  NAMESPACE "edu/wpi/first/util/cleanup" ${WPIUTIL_CLEANUP_SOURCES}
+  NAMESPACE "edu/wpi/first/util/concurrent" ${WPIUTIL_CONCURRENT_SOURCES}
+  NAMESPACE "edu/wpi/first/util/datalog" ${WPIUTIL_DATALOG_SOURCES}
+  NAMESPACE "edu/wpi/first/util/function" ${WPIUTIL_FUNCTION_SOURCES}
+  NAMESPACE "edu/wpi/first/util/sendable" ${WPIUTIL_SENDABLE_SOURCES}
+  OUTPUT_NAME wpiutil-sources)
+
+  get_property(WPIUTIL_SRC_JAR_FILE TARGET wpiutil_src_jar PROPERTY JAR_FILE)
+  install(FILES ${WPIUTIL_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
+
+  set_property(TARGET wpiutil_src_jar PROPERTY FOLDER "java")
 endif()
 
 set(THREADS_PREFER_PTHREAD_FLAG ON)
@@ -85,7 +110,7 @@
     endif()
 endif()
 
-GENERATE_RESOURCES(src/main/native/resources generated/main/cpp WPI wpi wpiutil_resources_src)
+generate_resources(src/main/native/resources generated/main/cpp WPI wpi wpiutil_resources_src)
 
 file(GLOB_RECURSE wpiutil_native_src src/main/native/cpp/*.cpp
                                      src/main/native/thirdparty/json/cpp/*.cpp
@@ -100,18 +125,18 @@
 file(GLOB fmtlib_native_src src/main/native/thirdparty/fmtlib/src/*.cpp)
 file(GLOB_RECURSE memory_native_src src/main/native/thirdparty/memory/src/*.cpp)
 
-add_library(wpiutil ${wpiutil_native_src} ${fmtlib_native_src} ${memory_native_src} ${wpiutil_resources_src})
+add_library(wpiutil ${wpiutil_native_src} ${memory_native_src} ${wpiutil_resources_src})
 set_target_properties(wpiutil PROPERTIES DEBUG_POSTFIX "d")
 
 set_property(TARGET wpiutil PROPERTY FOLDER "libraries")
 
 target_compile_features(wpiutil PUBLIC cxx_std_20)
 if (MSVC)
-    target_compile_options(wpiutil PUBLIC /permissive- /Zc:throwingNew /MP /bigobj)
+    target_compile_options(wpiutil PUBLIC /permissive- /Zc:preprocessor /Zc:throwingNew /MP /bigobj)
     target_compile_definitions(wpiutil PRIVATE -D_CRT_SECURE_NO_WARNINGS)
 endif()
 wpilib_target_warnings(wpiutil)
-target_link_libraries(wpiutil Threads::Threads ${CMAKE_DL_LIBS})
+target_link_libraries(wpiutil protobuf::libprotobuf Threads::Threads ${CMAKE_DL_LIBS})
 
 if (ATOMIC)
     target_link_libraries(wpiutil ${ATOMIC})
@@ -127,6 +152,13 @@
 else()
     find_package(fmt CONFIG REQUIRED)
     target_link_libraries(wpiutil fmt::fmt)
+    if(MSVC)
+        get_target_property(fmt_includes fmt::fmt INTERFACE_INCLUDE_DIRECTORIES)
+        foreach(dir ${fmt_includes})
+            target_compile_options(wpiutil PUBLIC /external:I "${dir}")
+        endforeach()
+        target_compile_options(wpiutil PUBLIC /external:W0)
+    endif()
 endif()
 
 if (MSVC)
@@ -146,11 +178,6 @@
                             $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/thirdparty/memory/include>
                             $<INSTALL_INTERFACE:${include_dest}/wpiutil>)
 
-install(DIRECTORY src/main/native/thirdparty/ghc/include/ DESTINATION "${include_dest}/wpiutil")
-target_include_directories(wpiutil PUBLIC
-                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/thirdparty/ghc/include>
-                            $<INSTALL_INTERFACE:${include_dest}/wpiutil>)
-
 install(DIRECTORY src/main/native/thirdparty/json/include/ DESTINATION "${include_dest}/wpiutil")
 target_include_directories(wpiutil PUBLIC
                             $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/thirdparty/json/include>
@@ -176,11 +203,7 @@
                             $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
                             $<INSTALL_INTERFACE:${include_dest}/wpiutil>)
 
-install(TARGETS wpiutil EXPORT wpiutil DESTINATION "${main_lib_dest}")
-
-if (WITH_JAVA AND MSVC)
-    install(TARGETS wpiutil RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
-endif()
+install(TARGETS wpiutil EXPORT wpiutil)
 
 if (WITH_FLAT_INSTALL)
     set (wpiutil_config_dir ${wpilib_dest})
@@ -192,7 +215,7 @@
 install(FILES ${WPILIB_BINARY_DIR}/wpiutil-config.cmake DESTINATION ${wpiutil_config_dir})
 install(EXPORT wpiutil DESTINATION ${wpiutil_config_dir})
 
-SUBDIR_LIST(wpiutil_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
+subdir_list(wpiutil_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
 foreach(example ${wpiutil_examples})
     file(GLOB wpiutil_example_src examples/${example}/*.cpp)
     if(wpiutil_example_src)
@@ -204,7 +227,10 @@
 endforeach()
 
 if (WITH_TESTS)
+    file(GLOB_RECURSE wpiutil_testlib_src src/test/native/include/*.h)
+    add_library(wpiutil_testlib INTERFACE ${wpiutil_test_src})
+    target_include_directories(wpiutil_testlib INTERFACE src/test/native/include)
+
     wpilib_add_test(wpiutil src/test/native/cpp)
-    target_include_directories(wpiutil_test PRIVATE src/test/native/include)
-    target_link_libraries(wpiutil_test wpiutil gmock_main)
+    target_link_libraries(wpiutil_test wpiutil gmock_main wpiutil_testlib)
 endif()
diff --git a/wpiutil/build.gradle b/wpiutil/build.gradle
index 501176a..ab13092 100644
--- a/wpiutil/build.gradle
+++ b/wpiutil/build.gradle
@@ -26,18 +26,13 @@
                     srcDirs 'src/main/native/thirdparty/fmtlib/include'
                 }
             }
-            ghcCpp(CppSourceSet) {
-                exportedHeaders {
-                    srcDirs 'src/main/native/thirdparty/ghc/include'
-                }
-            }
             jsonCpp(CppSourceSet) {
                 source {
                     srcDirs 'src/main/native/thirdparty/json/cpp'
                     include '*.cpp'
                 }
                 exportedHeaders {
-                    srcDirs 'src/main/native/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/fmtlib/include'
+                    srcDirs 'src/main/native/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/fmtlib/include'
                 }
             }
             llvmCpp(CppSourceSet) {
@@ -46,7 +41,7 @@
                     include '**/*.cpp'
                 }
                 exportedHeaders {
-                    srcDirs 'src/main/native/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/ghc/include'
+                    srcDirs 'src/main/native/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include'
                 }
             }
             mpackCpp(CppSourceSet) {
@@ -67,11 +62,6 @@
                     srcDirs 'src/main/native/thirdparty/sigslot/include'
                 }
             }
-            tcbSpanCpp(CppSourceSet) {
-                exportedHeaders {
-                    srcDirs 'src/main/native/thirdparty/tcb_span/include'
-                }
-            }
             memoryCpp(CppSourceSet) {
                 source {
                     srcDirs 'src/main/native/thirdparty/memory/src', 'src/main/native/thirdparty/memory/include/wpi/memory'
@@ -82,6 +72,15 @@
                     include '**/*.hpp'
                 }
             }
+            protobufCpp(CppSourceSet) {
+                source {
+                    srcDirs 'src/main/native/thirdparty/protobuf/src'
+                    include '**/*.cpp'
+                }
+                exportedHeaders {
+                    srcDirs 'src/main/native/thirdparty/protobuf/include'
+                }
+            }
             resourcesCpp(CppSourceSet) {
                 source {
                     srcDirs "$buildDir/generated/main/cpp", "$rootDir/shared/singlelib"
@@ -101,7 +100,7 @@
                         include '**/*.cpp'
                     }
                     exportedHeaders {
-                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/mpack/include'
+                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/mpack/include'
                         include '**/*.h'
                     }
                 }
@@ -115,7 +114,7 @@
                         include '**/*.cpp'
                     }
                     exportedHeaders {
-                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/mpack/include'
+                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/mpack/include'
                         include '**/*.h'
                     }
                 }
@@ -128,7 +127,7 @@
                         include '**/*.cpp'
                     }
                     exportedHeaders {
-                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/mpack/include'
+                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/mpack/include'
                         include '**/*.h'
                     }
                 }
@@ -141,13 +140,19 @@
                         include '**/*.cpp'
                     }
                     exportedHeaders {
-                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/mpack/include'
+                        srcDirs 'src/main/native/include', 'src/main/native/cpp', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/mpack/include'
                         include '**/*.h'
                     }
                 }
             }
         }
     }
+
+    exeSplitSetup = {
+        if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
+            nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries')
+        }
+    }
 }
 
 def examplesMap = [:];
@@ -184,9 +189,6 @@
     from('src/main/native/thirdparty/fmtlib/include') {
         into '/'
     }
-    from('src/main/native/thirdparty/ghc/include') {
-        into '/'
-    }
     from('src/main/native/thirdparty/json/include') {
         into '/'
     }
@@ -199,10 +201,10 @@
     from('src/main/native/thirdparty/sigslot/include') {
         into '/'
     }
-    from('src/main/native/thirdparty/tcb_span/include') {
+    from('src/main/native/thirdparty/memory/include') {
         into '/'
     }
-    from('src/main/native/thirdparty/memory/include') {
+    from('src/main/native/thirdparty/protobuf/include') {
         into '/'
     }
 }
@@ -223,6 +225,9 @@
     from('src/main/native/thirdparty/mpack/src') {
         into '/'
     }
+    from('src/main/native/thirdparty/protobuf/src') {
+        into '/'
+    }
     from('src/main/native/thirdparty/sigslot/src') {
         into '/'
     }
@@ -233,7 +238,7 @@
         all {
             it.sources.each {
                 it.exportedHeaders {
-                    srcDirs 'src/main/native/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/tcb_span/include', 'src/main/native/thirdparty/ghc/include', 'src/main/native/thirdparty/memory/include', 'src/main/native/thirdparty/mpack/include'
+                    srcDirs 'src/main/native/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/memory/include', 'src/main/native/thirdparty/mpack/include', 'src/main/native/thirdparty/protobuf/include'
                 }
             }
         }
@@ -247,6 +252,9 @@
                 targetBuildTypes 'debug'
                 binaries.all {
                     lib library: 'wpiutil', linkage: 'shared'
+                    if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
+                        nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries')
+                    }
                 }
                 sources {
                     cpp {
@@ -261,6 +269,17 @@
     }
 }
 
+model {
+    binaries {
+        all {
+            if (!(it instanceof NativeBinarySpec)) return
+                if (it.component.name != 'wpiutil' && it.component.name != 'wpiutilBase') return
+                if (it.targetPlatform.name != nativeUtils.wpi.platforms.roborio) return
+                nativeUtils.useRequiredLibrary(it, 'ni_link_libraries')
+        }
+    }
+}
+
 sourceSets {
     printlog
 }
@@ -272,9 +291,10 @@
 }
 
 dependencies {
-    api "com.fasterxml.jackson.core:jackson-annotations:2.12.4"
-    api "com.fasterxml.jackson.core:jackson-core:2.12.4"
-    api "com.fasterxml.jackson.core:jackson-databind:2.12.4"
+    api "com.fasterxml.jackson.core:jackson-annotations:2.15.2"
+    api "com.fasterxml.jackson.core:jackson-core:2.15.2"
+    api "com.fasterxml.jackson.core:jackson-databind:2.15.2"
+    api 'us.hebi.quickbuf:quickbuf-runtime:1.3.2'
 
     printlogImplementation sourceSets.main.output
 }
diff --git a/wpiutil/doc/struct.adoc b/wpiutil/doc/struct.adoc
new file mode 100644
index 0000000..cac4d4a
--- /dev/null
+++ b/wpiutil/doc/struct.adoc
@@ -0,0 +1,311 @@
+= WPILib Packed Struct Serialization Specification, Version 1.0
+WPILib Developers <wpilib@wpi.edu>
+Revision 1.0 (0x0100), 6/8/2023
+:toc:
+:toc-placement: preamble
+:sectanchors:
+
+A simple format and schema for serialization of packed fixed size structured data.
+
+[[motivation]]
+== Motivation
+
+Schema-based serialization formats such as Protobuf and Flatbuffers are extremely flexible and can handle data type evolution, complex nested data structures, variable size / repeated data, optional fields, etc. However, this flexibility comes at a cost in both serialized data size and processing overhead. Many simple data structures, such as screen coordinates or robot poses, are fixed in size and can be stored much more compactly and serialized/deserialized much more quickly, especially on embedded or real-time platforms.
+
+Simply storing a C-style packed structure is very compact and fast, but information about the layout of the structure and the meaning of each member must be separately communicated for introspection by other tools such as interactive dashboards for data analysis of individual structure members. The motivation for this standard layout and schema is to provide a standardized means to communicate this information and enable dynamic decoding.
+
+Python's struct module uses a character-based approach to describe data layout of structures, but has no provisions for naming each member to communicate intent/meaning.
+
+[[references]]
+== References
+
+[[c-struct-declaration]]
+* Struct declaration, https://en.cppreference.com/w/c/language/struct
+
+[[definitions]]
+== Definitions
+
+[[schema]]
+== Schema
+
+The schema is a text-based format with similar syntax to the list of variable declarations in a C structure. The C syntax is flexible, easy to parse, and matches the intent of specifying a fixed size structure.
+
+Each member of the struct is defined by a single declaration. Each declaration is either a standard declaration or a bit-field declaration. Declarations are separated by semicolons. The last declaration may optionally have a trailing semicolon. Empty declarations (e.g. two semicolons back-to-back or separated by only whitespace) are allowed but are ignored. Unlike C structures, every declaration must be separated by a semicolon; commas cannot be used to declare multiple members with the same type. Declarations may also start and end with whitespace.
+
+[[variable]]
+=== Standard Declaration
+
+Standard declarations declare a member of a certain type or a fixed-size array of that type. The structure of a standard declaration is:
+
+* optional enum specification (integer data types only)
+* optional whitespace
+* type name
+* whitespace
+* identifier name
+* optional array size, consisting of:
+  * optional whitespace
+  * `[`
+  * optional whitespace
+  * size of array
+  * optional whitespace
+  * `]`
+
+The type name may be one of these:
+
+[cols="1,1,3", options="header"]
+|===
+|Type Name|Description|Payload Data Contents
+|`bool`|boolean|single byte (0=false, 1=true)
+|`char`|character|single byte (assumed UTF-8)
+|`int8`|integer|1-byte (8-bit) signed value
+|`int16`|integer|2-byte (16-bit) signed value
+|`int32`|integer|4-byte (32-bit) signed value
+|`int64`|integer|8-byte (64-bit) signed value
+|`uint8`|unsigned integer|1-byte (8-bit) unsigned value
+|`uint16`|unsigned integer|2-byte (16-bit) unsigned value
+|`uint32`|unsigned integer|4-byte (32-bit) unsigned value
+|`uint64`|unsigned integer|8-byte (64-bit) unsigned value
+|`float` or `float32`|float|4-byte (32-bit) IEEE-754 value
+|`double` or `float64`|double|8-byte (64-bit) IEEE-754 value
+|===
+
+If it is not one of the above, the type name must be the name of another struct.
+
+Examples of valid standard declarations:
+
+* `bool value` (boolean value, 1 byte)
+* `double arr[4]` (array of 4 doubles, 32 bytes total)
+* `enum {a=1, b=2} int8 val` (enumerated value, 1 byte)
+
+[[enum]]
+==== Enum Specification
+
+Integer declarations may have an enum specification to provide meaning to specific values. Values that are not specified may be communicated, but have no specific defined meaning. The structure of an enum specification is:
+
+* optional `enum`
+* optional whitespace
+* `{`
+* zero or more enum values, consisting of:
+  * optional whitespace
+  * identifier
+  * optional whitespace
+  * `=`
+  * optional whitespace
+  * integer value
+  * optional whitespace
+  * comma (optional for last value)
+* optional whitespace
+* `}`
+
+Examples of valid enum specifications:
+
+* `enum{}`
+* `enum { a = 1 }`
+* `enum{a=1,b=2,}`
+* `{a=1}`
+
+Examples of invalid enum specifications:
+
+* `enum` (no `{}`)
+* `enum{=2}` (missing identifier)
+* `enum{a=1,b,c}` (missing values)
+
+[[]]
+=== Bit-field Declaration
+
+Bit-field declarations declare a member with an explicit width in bits. The structure of a bit-field declaration is:
+
+* optional enum specification (integer data types only)
+* optional whitespace
+* type name; must be boolean or one of the integer data types
+* whitespace
+* identifier name
+* optional whitespace
+* colon (`:`)
+* optional whitespace
+* integer number of bits; minimum 1; maximum 1 for boolean types; for integer types, maximum is the width of the type (e.g. 32 for int32)
+
+As with non-bit-field integer variable declarations, an enum can be specified for integer bit-fields (e.g. `enum {a=1, b=2} uint32 value : 2`).
+
+It is not possible to have an array of bit-fields.
+
+Examples of valid bit-field declarations:
+
+* `bool value : 1`
+* `enum{a=1,b=2}int8 value:2`
+
+Examples of invalid bit-field declarations:
+
+* `double val:2` (must be integer or boolean)
+* `int32 val[2]:2` (cannot be array)
+* `bool val:3` (bool must be 1 bit)
+* `int16 val:17` (bit field larger than storage size)
+
+[[layout]]
+== Data Layout
+
+Members are stored in the same order they appear in the schema. Individual members are stored in little-endian order. Members are not aligned to any particular boundary; no byte-level padding is present in the data.
+
+[source]
+----
+bool b;
+int16 i;
+----
+
+results in a 3-byte encoding:
+
+`bbbbbbbb iiiiiiii iiiiiiii`
+
+where the first `iiiiiiii` is the least significant byte of `i`.
+
+[[layout-array]]
+=== Array Data Layout
+
+For array members, the individual items of the array are stored consecutively with no padding between each item.
+
+[source]
+----
+int16 i[2];
+----
+
+results in a 4-byte encoding:
+
+`i0i0i0i0 i0i0i0i0 i1i1i1i1 i1i1i1i1`
+
+where `i0` is the first element of the array, `i1` is the second element.
+
+[[layout-nested-structure]]
+
+Nested structures also have no surrounding padding.
+
+Given the Inner schema
+
+[source]
+----
+int16 i;
+int8 x;
+----
+
+and an outer schema of
+
+[source]
+----
+char c;
+Inner s;
+bool b;
+----
+
+results in a 5-byte encoding:
+
+`cccccccc iiiiiiii iiiiiiii xxxxxxxx bbbbbbbb`
+
+[[layout-bit-field]]
+=== Bit-Field Data Layout
+
+Multiple adjacant bit-fields of the same integer type width are packed together to fit in the minimum number of multiples of that type. The bit-fields are packed, starting from the least significant bit, in the order they appear in the schema. Individual bit-fields must not span across multiple underlying types; if a bit-field is larger than the remaining space in the data type, a new element of that type is started and the bit-field starts from the least significant bit of the new element. Unused bits should be set to 0 during serialization and must be ignored during deserialization.
+
+Boolean bit-fields are always a single bit wide. The underlying data type is by default uint8, but if a boolean bit-field immediately follows a bit-field of another integer type (and fits), it is packed into that type.
+
+[source]
+----
+int8 a:4;
+int16 b:4;
+----
+
+results in a 3-byte encoding:
+
+`0000aaaa 0000bbbb 00000000`
+
+as the integer type widths are different, even though the bits would fit.
+
+[source]
+----
+int16 a:4;
+uint16 b:5;
+bool c:1;
+int16 d:7;
+----
+
+results in a 4-byte encoding:
+
+`bbbbaaaa 000000cb 0ddddddd 00000000`
+
+As `c` is packed into the preceding int16, and `d` is too large to fit in the remaining bits of the first type.
+
+[source]
+----
+uint8 a:4;
+int8 b:2;
+bool c:1;
+int16 d:1;
+----
+
+results in a 3-byte encoding:
+
+`0cbbaaaa 0000000d 00000000`
+
+as `d` is int16, versus the `int8` of the previous values.
+
+[source]
+----
+bool a:1;
+bool b:1;
+int8 c:2;
+----
+
+results in a 1-byte encoding:
+
+`0000ccba`
+
+as `c` is an int8.
+
+[source]
+----
+bool a:1;
+bool b:1;
+int16 c:2;
+----
+
+results in a 3-byte encoding:
+
+`000000ba 000000cc 00000000`
+
+as `c` is an int16.
+
+Bit-fields do not "look inside" of nested structures. Given Inner
+
+[source]
+----
+int8 a:1;
+----
+
+and outer
+
+[source]
+----
+int8 b:1;
+Outer s;
+int8 c:1;
+----
+
+the result is a 3-byte encoding:
+
+`0000000b 0000000a 0000000c`
+
+[[layout-character-arrays]]
+=== Character Array (String) Data Layout
+
+Character arrays, as with other arrays, must be fixed length. The text they contain should be UTF-8. If a string is shorter than the length of the character array, the string starts at the first byte of the array, and any unused bytes at the end of the array must be filled with 0.
+
+[source]
+----
+char s[4];
+----
+
+with a string of "a" results in:
+
+`01100001 00000000 00000000 00000000`
+
+with a string of "abcd" results in:
+
+`01100001 01100010 01100011 01100100`
diff --git a/wpiutil/examples/printlog/datalog.py b/wpiutil/examples/printlog/datalog.py
index b1035dd..0f725fd 100755
--- a/wpiutil/examples/printlog/datalog.py
+++ b/wpiutil/examples/printlog/datalog.py
@@ -5,6 +5,7 @@
 
 import array
 import struct
+import msgpack
 from typing import List, SupportsBytes
 
 __all__ = ["StartRecordData", "MetadataRecordData", "DataLogRecord", "DataLogReader"]
@@ -128,6 +129,9 @@
     def getString(self) -> str:
         return str(self.data, encoding="utf-8")
 
+    def getMsgPack(self):
+        return msgpack.unpackb(self.data)
+
     def getBooleanArray(self) -> List[bool]:
         return [x != 0 for x in self.data]
 
@@ -326,6 +330,8 @@
                         print(f"  {record.getInteger()}")
                     elif entry.type in ("string", "json"):
                         print(f"  '{record.getString()}'")
+                    elif entry.type == "msgpack":
+                        print(f"  '{record.getMsgPack()}'")
                     elif entry.type == "boolean":
                         print(f"  {record.getBoolean()}")
                     elif entry.type == "boolean[]":
diff --git a/wpiutil/examples/printlog/printlog.cpp b/wpiutil/examples/printlog/printlog.cpp
index 073a247..cb89934 100644
--- a/wpiutil/examples/printlog/printlog.cpp
+++ b/wpiutil/examples/printlog/printlog.cpp
@@ -4,8 +4,9 @@
 
 #include <ctime>
 
-#include "fmt/chrono.h"
-#include "fmt/format.h"
+#include <fmt/chrono.h>
+#include <fmt/format.h>
+
 #include "wpi/DataLogReader.h"
 #include "wpi/DenseMap.h"
 #include "wpi/MemoryBuffer.h"
diff --git a/wpiutil/examples/writelog/writelog.cpp b/wpiutil/examples/writelog/writelog.cpp
index 6fdf763..bd5e14f 100644
--- a/wpiutil/examples/writelog/writelog.cpp
+++ b/wpiutil/examples/writelog/writelog.cpp
@@ -8,7 +8,8 @@
 #include <string>
 #include <vector>
 
-#include "fmt/format.h"
+#include <fmt/format.h>
+
 #include "wpi/DataLog.h"
 
 int main(int argc, char** argv) {
diff --git a/wpiutil/src/dev/native/cpp/main.cpp b/wpiutil/src/dev/native/cpp/main.cpp
index 14ddda2..fb2a4b0 100644
--- a/wpiutil/src/dev/native/cpp/main.cpp
+++ b/wpiutil/src/dev/native/cpp/main.cpp
@@ -2,7 +2,8 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
-#include "fmt/core.h"
+#include <fmt/core.h>
+
 #include "wpi/SmallString.h"
 
 int main() {
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/ClassPreloader.java b/wpiutil/src/main/java/edu/wpi/first/util/ClassPreloader.java
new file mode 100644
index 0000000..6d8e2a9
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/ClassPreloader.java
@@ -0,0 +1,119 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+
+/**
+ * Loads classes by name. Can be used at any time, but is most commonly used to preload classes at
+ * the start of the program to avoid unpredictable delays due to lazy classloading later in program
+ * execution.
+ */
+public final class ClassPreloader {
+  private ClassPreloader() {}
+
+  /**
+   * Loads classes from an iterable.
+   *
+   * @param classNames iterable of class names
+   * @return Number of classes loaded.
+   */
+  public static int preload(Iterable<String> classNames) {
+    int count = 0;
+    for (String i : classNames) {
+      try {
+        Class.forName(i);
+        count++;
+      } catch (ClassNotFoundException e) {
+        System.out.println("Could not preload " + i);
+      }
+    }
+    return count;
+  }
+
+  /**
+   * Loads classes.
+   *
+   * @param classNames array of class names
+   * @return Number of classes loaded.
+   */
+  public static int preload(String... classNames) {
+    int count = 0;
+    for (String i : classNames) {
+      try {
+        Class.forName(i);
+        count++;
+      } catch (ClassNotFoundException e) {
+        System.out.println("Could not preload " + i);
+      }
+    }
+    return count;
+  }
+
+  /**
+   * Loads classes from a buffered reader. The input is expected to be one class name per line.
+   * Blank lines and lines starting with a semicolon are ignored.
+   *
+   * @param reader Reader
+   * @return Number of classes loaded.
+   */
+  public static int preload(BufferedReader reader) {
+    int count = 0;
+    try {
+      String line = reader.readLine();
+      while (line != null) {
+        if (!line.isEmpty() && !line.startsWith(";")) {
+          try {
+            Class.forName(line);
+            count++;
+          } catch (ClassNotFoundException e) {
+            System.out.println("Could not preload " + line);
+          }
+        }
+        line = reader.readLine();
+      }
+    } catch (IOException e) {
+      System.out.println("Error when reading preload file: " + e);
+    }
+    return count;
+  }
+
+  /**
+   * Loads classes from an input stream. The input is expected to be one class name per line. Blank
+   * lines and lines starting with a semicolon are ignored.
+   *
+   * @param stream input stream
+   * @return Number of classes loaded.
+   */
+  public static int preload(InputStream stream) {
+    return preload(new BufferedReader(new InputStreamReader(stream)));
+  }
+
+  /**
+   * Loads classes from a file. The input is expected to be one class name per line. Blank lines and
+   * lines starting with a semicolon are ignored.
+   *
+   * @param filename filename
+   * @return Number of classes loaded.
+   */
+  public static int preloadFile(String filename) {
+    try (BufferedReader reader =
+        Files.newBufferedReader(Paths.get(filename), StandardCharsets.UTF_8)) {
+      return preload(reader);
+    } catch (NoSuchFileException e) {
+      System.out.println("Could not open preload file " + filename + ": " + e);
+    } catch (IOException e) {
+      System.out.println("Could not close preload file " + filename + ": " + e);
+    }
+    return 0;
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/EventVector.java b/wpiutil/src/main/java/edu/wpi/first/util/EventVector.java
index a85379e..4d2c800 100644
--- a/wpiutil/src/main/java/edu/wpi/first/util/EventVector.java
+++ b/wpiutil/src/main/java/edu/wpi/first/util/EventVector.java
@@ -9,8 +9,8 @@
 import java.util.concurrent.locks.ReentrantLock;
 
 public class EventVector {
-  private ReentrantLock m_lock = new ReentrantLock();
-  private List<Integer> m_events = new ArrayList<>();
+  private final ReentrantLock m_lock = new ReentrantLock();
+  private final List<Integer> m_events = new ArrayList<>();
 
   /**
    * Adds an event to the event vector.
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/InterpolatingTreeMap.java b/wpiutil/src/main/java/edu/wpi/first/util/InterpolatingTreeMap.java
index ade2e5a..2c54d00 100644
--- a/wpiutil/src/main/java/edu/wpi/first/util/InterpolatingTreeMap.java
+++ b/wpiutil/src/main/java/edu/wpi/first/util/InterpolatingTreeMap.java
@@ -9,7 +9,10 @@
 /**
  * Interpolating Tree Maps are used to get values at points that are not defined by making a guess
  * from points that are defined. This uses linear interpolation.
+ *
+ * @deprecated Use {@link edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap} instead
  */
+@Deprecated(forRemoval = true, since = "2024")
 public class InterpolatingTreeMap<K extends Number, V extends Number> {
   private final TreeMap<K, V> m_map = new TreeMap<>();
 
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/WPICleaner.java b/wpiutil/src/main/java/edu/wpi/first/util/WPICleaner.java
new file mode 100644
index 0000000..0c497d4
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/WPICleaner.java
@@ -0,0 +1,28 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util;
+
+import java.lang.ref.Cleaner;
+import java.lang.ref.Cleaner.Cleanable;
+
+/** Cleaner object for WPILib objects. */
+public final class WPICleaner {
+  private WPICleaner() {
+    throw new UnsupportedOperationException("This is a utility class!");
+  }
+
+  private static final Cleaner instance = Cleaner.create();
+
+  /**
+   * Register an object with the cleaner.
+   *
+   * @param object The object to register.
+   * @param runnable The runnable to call on cleanup.
+   * @return The registered Cleanable.
+   */
+  public static Cleanable register(Object object, Runnable runnable) {
+    return instance.register(object, runnable);
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/cleanup/CleanupPool.java b/wpiutil/src/main/java/edu/wpi/first/util/cleanup/CleanupPool.java
new file mode 100644
index 0000000..fab8316
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/cleanup/CleanupPool.java
@@ -0,0 +1,55 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.cleanup;
+
+import edu.wpi.first.util.ErrorMessages;
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * An object containing a Stack of AutoCloseable objects that are closed when this object is closed.
+ */
+public class CleanupPool implements AutoCloseable {
+  // Use a Deque instead of a Stack, as Stack's iterators go the wrong way, and docs
+  // state ArrayDeque is faster anyway.
+  private final Deque<AutoCloseable> m_closers = new ArrayDeque<AutoCloseable>();
+
+  /**
+   * Registers an object in the object stack for cleanup.
+   *
+   * @param <T> The object type
+   * @param object The object to register
+   * @return The registered object
+   */
+  public <T extends AutoCloseable> T register(T object) {
+    ErrorMessages.requireNonNullParam(object, "object", "register");
+    m_closers.addFirst(object);
+    return object;
+  }
+
+  /**
+   * Removes an object from the cleanup stack.
+   *
+   * @param object the object to remove
+   */
+  public void remove(AutoCloseable object) {
+    m_closers.remove(object);
+  }
+
+  /** Closes all objects in the stack. */
+  @Override
+  @SuppressWarnings("PMD.AvoidCatchingGenericException")
+  public void close() {
+    for (AutoCloseable autoCloseable : m_closers) {
+      try {
+        autoCloseable.close();
+      } catch (Exception e) {
+        // Swallow any exceptions on close
+        e.printStackTrace();
+      }
+    }
+    m_closers.clear();
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/cleanup/ReflectionCleanup.java b/wpiutil/src/main/java/edu/wpi/first/util/cleanup/ReflectionCleanup.java
new file mode 100644
index 0000000..0803028
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/cleanup/ReflectionCleanup.java
@@ -0,0 +1,50 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.cleanup;
+
+import java.lang.reflect.Field;
+
+/**
+ * Implement this interface to have access to a `reflectionCleanup` method that can be called from
+ * your `close` method, that will use reflection to find all `AutoCloseable` instance members and
+ * close them.
+ */
+public interface ReflectionCleanup extends AutoCloseable {
+  /**
+   * Default implementation that uses reflection to find all AutoCloseable fields not marked
+   * SkipCleanup and call close() on them. Call this from your `close()` method with the class level
+   * you want to close.
+   *
+   * @param cls the class level to clean up
+   */
+  @SuppressWarnings("PMD.AvoidCatchingGenericException")
+  default void reflectionCleanup(Class<? extends ReflectionCleanup> cls) {
+    if (!cls.isAssignableFrom(getClass())) {
+      System.out.println("Passed in class is not assignable from \"this\"");
+      System.out.println("Expected something in the hierarchy of" + cls.getName());
+      System.out.println("This is " + getClass().getName());
+      return;
+    }
+    for (Field field : cls.getDeclaredFields()) {
+      if (field.isAnnotationPresent(SkipCleanup.class)) {
+        continue;
+      }
+      if (!AutoCloseable.class.isAssignableFrom(field.getType())) {
+        continue;
+      }
+      if (field.trySetAccessible()) {
+        try {
+          AutoCloseable c = (AutoCloseable) field.get(this);
+          if (c != null) {
+            c.close();
+          }
+        } catch (Exception e) {
+          // Ignore any exceptions
+          e.printStackTrace();
+        }
+      }
+    }
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/cleanup/SkipCleanup.java b/wpiutil/src/main/java/edu/wpi/first/util/cleanup/SkipCleanup.java
new file mode 100644
index 0000000..e2bc72e
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/cleanup/SkipCleanup.java
@@ -0,0 +1,14 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.cleanup;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SkipCleanup {}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLog.java b/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLog.java
index 784b8d6..97c629f 100644
--- a/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLog.java
+++ b/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLog.java
@@ -4,6 +4,15 @@
 
 package edu.wpi.first.util.datalog;
 
+import edu.wpi.first.util.WPIUtilJNI;
+import edu.wpi.first.util.protobuf.Protobuf;
+import edu.wpi.first.util.struct.Struct;
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 /**
  * A data log. The log file is created immediately upon construction with a temporary filename. The
  * file may be renamed at any time using the setFilename() function.
@@ -97,11 +106,144 @@
     DataLogJNI.pause(m_impl);
   }
 
-  /** Resumes appending of data records to the log. */
+  /**
+   * Resumes appending of data records to the log. If called after stop(), opens a new file (with
+   * random name if SetFilename was not called after stop()) and appends Start records and schema
+   * data values for all previously started entries and schemas.
+   */
   public void resume() {
     DataLogJNI.resume(m_impl);
   }
 
+  /** Stops appending all records to the log, and closes the log file. */
+  public void stop() {
+    DataLogJNI.stop(m_impl);
+  }
+
+  /**
+   * Returns whether there is a data schema already registered with the given name.
+   *
+   * @param name Name (the string passed as the data type for records using this schema)
+   * @return True if schema already registered
+   */
+  public boolean hasSchema(String name) {
+    return m_schemaMap.containsKey(name);
+  }
+
+  /**
+   * Registers a data schema. Data schemas provide information for how a certain data type string
+   * can be decoded. The type string of a data schema indicates the type of the schema itself (e.g.
+   * "protobuf" for protobuf schemas, "struct" for struct schemas, etc). In the data log, schemas
+   * are saved just like normal records, with the name being generated from the provided name:
+   * "/.schema/name". Duplicate calls to this function with the same name are silently ignored.
+   *
+   * @param name Name (the string passed as the data type for records using this schema)
+   * @param type Type of schema (e.g. "protobuf", "struct", etc)
+   * @param schema Schema data
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  public void addSchema(String name, String type, byte[] schema, long timestamp) {
+    if (m_schemaMap.putIfAbsent(name, 1) != null) {
+      return;
+    }
+    DataLogJNI.addSchema(m_impl, name, type, schema, timestamp);
+  }
+
+  /**
+   * Registers a data schema. Data schemas provide information for how a certain data type string
+   * can be decoded. The type string of a data schema indicates the type of the schema itself (e.g.
+   * "protobuf" for protobuf schemas, "struct" for struct schemas, etc). In the data log, schemas
+   * are saved just like normal records, with the name being generated from the provided name:
+   * "/.schema/name". Duplicate calls to this function with the same name are silently ignored.
+   *
+   * @param name Name (the string passed as the data type for records using this schema)
+   * @param type Type of schema (e.g. "protobuf", "struct", etc)
+   * @param schema Schema data
+   */
+  public void addSchema(String name, String type, byte[] schema) {
+    addSchema(name, type, schema, 0);
+  }
+
+  /**
+   * Registers a data schema. Data schemas provide information for how a certain data type string
+   * can be decoded. The type string of a data schema indicates the type of the schema itself (e.g.
+   * "protobuf" for protobuf schemas, "struct" for struct schemas, etc). In the data log, schemas
+   * are saved just like normal records, with the name being generated from the provided name:
+   * "/.schema/name". Duplicate calls to this function with the same name are silently ignored.
+   *
+   * @param name Name (the string passed as the data type for records using this schema)
+   * @param type Type of schema (e.g. "protobuf", "struct", etc)
+   * @param schema Schema data
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  public void addSchema(String name, String type, String schema, long timestamp) {
+    if (m_schemaMap.putIfAbsent(name, 1) != null) {
+      return;
+    }
+    DataLogJNI.addSchemaString(m_impl, name, type, schema, timestamp);
+  }
+
+  /**
+   * Registers a data schema. Data schemas provide information for how a certain data type string
+   * can be decoded. The type string of a data schema indicates the type of the schema itself (e.g.
+   * "protobuf" for protobuf schemas, "struct" for struct schemas, etc). In the data log, schemas
+   * are saved just like normal records, with the name being generated from the provided name:
+   * "/.schema/name". Duplicate calls to this function with the same name are silently ignored.
+   *
+   * @param name Name (the string passed as the data type for records using this schema)
+   * @param type Type of schema (e.g. "protobuf", "struct", etc)
+   * @param schema Schema data
+   */
+  public void addSchema(String name, String type, String schema) {
+    addSchema(name, type, schema, 0);
+  }
+
+  /**
+   * Registers a protobuf schema. Duplicate calls to this function with the same name are silently
+   * ignored.
+   *
+   * @param proto protobuf serialization object
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void addSchema(Protobuf<?, ?> proto, long timestamp) {
+    final long actualTimestamp = timestamp == 0 ? WPIUtilJNI.now() : timestamp;
+    proto.forEachDescriptor(
+        this::hasSchema,
+        (typeString, schema) ->
+            addSchema(typeString, "proto:FileDescriptorProto", schema, actualTimestamp));
+  }
+
+  /**
+   * Registers a protobuf schema. Duplicate calls to this function with the same name are silently
+   * ignored.
+   *
+   * @param proto protobuf serialization object
+   */
+  public void addSchema(Protobuf<?, ?> proto) {
+    addSchema(proto, 0);
+  }
+
+  /**
+   * Registers a struct schema. Duplicate calls to this function with the same name are silently
+   * ignored.
+   *
+   * @param struct struct serialization object
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void addSchema(Struct<?> struct, long timestamp) {
+    addSchemaImpl(struct, timestamp == 0 ? WPIUtilJNI.now() : timestamp, new HashSet<>());
+  }
+
+  /**
+   * Registers a struct schema. Duplicate calls to this function with the same name are silently
+   * ignored.
+   *
+   * @param struct struct serialization object
+   */
+  public void addSchema(Struct<?> struct) {
+    addSchema(struct, 0);
+  }
+
   /**
    * Start an entry. Duplicate names are allowed (with the same type), and result in the same index
    * being returned (start/finish are reference counted). A duplicate name with a different type
@@ -188,14 +330,52 @@
   }
 
   /**
-   * Appends a record to the log.
+   * Appends a raw record to the log.
    *
-   * @param entry Entry index, as returned by Start()
-   * @param data Data to record
+   * @param entry Entry index, as returned by start()
+   * @param data Byte array to record; will send entire array contents
    * @param timestamp Time stamp (0 to indicate now)
    */
   public void appendRaw(int entry, byte[] data, long timestamp) {
-    DataLogJNI.appendRaw(m_impl, entry, data, timestamp);
+    appendRaw(entry, data, 0, data.length, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param data Byte array to record
+   * @param start Start position of data (in byte array)
+   * @param len Length of data (must be less than or equal to data.length - start)
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void appendRaw(int entry, byte[] data, int start, int len, long timestamp) {
+    DataLogJNI.appendRaw(m_impl, entry, data, start, len, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param data Buffer to record; will send from data.position() to data.limit()
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void appendRaw(int entry, ByteBuffer data, long timestamp) {
+    int pos = data.position();
+    appendRaw(entry, data, pos, data.limit() - pos, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param data Buffer to record
+   * @param start Start position of data (in buffer)
+   * @param len Length of data (must be less than or equal to data.capacity() - start)
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void appendRaw(int entry, ByteBuffer data, int start, int len, long timestamp) {
+    DataLogJNI.appendRaw(m_impl, entry, data, start, len, timestamp);
   }
 
   @Override
@@ -204,42 +384,112 @@
     m_impl = 0;
   }
 
+  /**
+   * Appends a boolean record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param value Boolean value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendBoolean(int entry, boolean value, long timestamp) {
     DataLogJNI.appendBoolean(m_impl, entry, value, timestamp);
   }
 
+  /**
+   * Appends an integer record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param value Integer value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendInteger(int entry, long value, long timestamp) {
     DataLogJNI.appendInteger(m_impl, entry, value, timestamp);
   }
 
+  /**
+   * Appends a float record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param value Float value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendFloat(int entry, float value, long timestamp) {
     DataLogJNI.appendFloat(m_impl, entry, value, timestamp);
   }
 
+  /**
+   * Appends a double record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param value Double value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendDouble(int entry, double value, long timestamp) {
     DataLogJNI.appendDouble(m_impl, entry, value, timestamp);
   }
 
+  /**
+   * Appends a string record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param value String value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendString(int entry, String value, long timestamp) {
     DataLogJNI.appendString(m_impl, entry, value, timestamp);
   }
 
+  /**
+   * Appends a boolean array record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param arr Boolean array to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendBooleanArray(int entry, boolean[] arr, long timestamp) {
     DataLogJNI.appendBooleanArray(m_impl, entry, arr, timestamp);
   }
 
+  /**
+   * Appends an integer array record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param arr Integer array to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendIntegerArray(int entry, long[] arr, long timestamp) {
     DataLogJNI.appendIntegerArray(m_impl, entry, arr, timestamp);
   }
 
+  /**
+   * Appends a float array record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param arr Float array to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendFloatArray(int entry, float[] arr, long timestamp) {
     DataLogJNI.appendFloatArray(m_impl, entry, arr, timestamp);
   }
 
+  /**
+   * Appends a double array record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param arr Double array to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendDoubleArray(int entry, double[] arr, long timestamp) {
     DataLogJNI.appendDoubleArray(m_impl, entry, arr, timestamp);
   }
 
+  /**
+   * Appends a string array record to the log.
+   *
+   * @param entry Entry index, as returned by start()
+   * @param arr String array to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
   public void appendStringArray(int entry, String[] arr, long timestamp) {
     DataLogJNI.appendStringArray(m_impl, entry, arr, timestamp);
   }
@@ -248,5 +498,21 @@
     return m_impl;
   }
 
+  private void addSchemaImpl(Struct<?> struct, long timestamp, Set<String> seen) {
+    String typeString = struct.getTypeString();
+    if (hasSchema(typeString)) {
+      return;
+    }
+    if (!seen.add(typeString)) {
+      throw new UnsupportedOperationException(typeString + ": circular reference with " + seen);
+    }
+    addSchema(typeString, "structschema", struct.getSchema(), timestamp);
+    for (Struct<?> inner : struct.getNested()) {
+      addSchemaImpl(inner, timestamp, seen);
+    }
+    seen.remove(typeString);
+  }
+
   private long m_impl;
+  private final ConcurrentMap<String, Integer> m_schemaMap = new ConcurrentHashMap<>();
 }
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLogJNI.java b/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLogJNI.java
index 724b3d9..f94a86f 100644
--- a/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLogJNI.java
+++ b/wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLogJNI.java
@@ -5,6 +5,7 @@
 package edu.wpi.first.util.datalog;
 
 import edu.wpi.first.util.WPIUtilJNI;
+import java.nio.ByteBuffer;
 
 public class DataLogJNI extends WPIUtilJNI {
   static native long create(String dir, String filename, double period, String extraHeader);
@@ -17,6 +18,13 @@
 
   static native void resume(long impl);
 
+  static native void stop(long impl);
+
+  static native void addSchema(long impl, String name, String type, byte[] schema, long timestamp);
+
+  static native void addSchemaString(
+      long impl, String name, String type, String schema, long timestamp);
+
   static native int start(long impl, String name, String type, String metadata, long timestamp);
 
   static native void finish(long impl, int entry, long timestamp);
@@ -25,7 +33,30 @@
 
   static native void close(long impl);
 
-  static native void appendRaw(long impl, int entry, byte[] data, long timestamp);
+  static native void appendRaw(
+      long impl, int entry, byte[] data, int start, int len, long timestamp);
+
+  static void appendRaw(long impl, int entry, ByteBuffer data, int start, int len, long timestamp) {
+    if (data.isDirect()) {
+      if (start < 0) {
+        throw new IndexOutOfBoundsException("start must be >= 0");
+      }
+      if (len < 0) {
+        throw new IndexOutOfBoundsException("len must be >= 0");
+      }
+      if ((start + len) > data.capacity()) {
+        throw new IndexOutOfBoundsException("start + len must be smaller than buffer capacity");
+      }
+      appendRawBuffer(impl, entry, data, start, len, timestamp);
+    } else if (data.hasArray()) {
+      appendRaw(impl, entry, data.array(), data.arrayOffset() + start, len, timestamp);
+    } else {
+      throw new UnsupportedOperationException("ByteBuffer must be direct or have a backing array");
+    }
+  }
+
+  private static native void appendRawBuffer(
+      long impl, int entry, ByteBuffer data, int start, int len, long timestamp);
 
   static native void appendBoolean(long impl, int entry, boolean value, long timestamp);
 
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/datalog/ProtobufLogEntry.java b/wpiutil/src/main/java/edu/wpi/first/util/datalog/ProtobufLogEntry.java
new file mode 100644
index 0000000..1db2647
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/datalog/ProtobufLogEntry.java
@@ -0,0 +1,117 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.datalog;
+
+import edu.wpi.first.util.protobuf.Protobuf;
+import edu.wpi.first.util.protobuf.ProtobufBuffer;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import us.hebi.quickbuf.ProtoMessage;
+
+/**
+ * Log protobuf-encoded values.
+ *
+ * @param <T> value class
+ */
+public final class ProtobufLogEntry<T> extends DataLogEntry {
+  private ProtobufLogEntry(
+      DataLog log, String name, Protobuf<T, ?> proto, String metadata, long timestamp) {
+    super(log, name, proto.getTypeString(), metadata, timestamp);
+    m_buf = ProtobufBuffer.create(proto);
+    log.addSchema(proto, timestamp);
+  }
+
+  /**
+   * Creates a protobuf-encoded log entry.
+   *
+   * @param <T> value class (inferred from proto)
+   * @param <MessageType> protobuf message type (inferred from proto)
+   * @param log datalog
+   * @param name name of the entry
+   * @param proto protobuf serialization implementation
+   * @param metadata metadata
+   * @param timestamp entry creation timestamp (0=now)
+   * @return ProtobufLogEntry
+   */
+  public static <T, MessageType extends ProtoMessage<?>> ProtobufLogEntry<T> create(
+      DataLog log, String name, Protobuf<T, MessageType> proto, String metadata, long timestamp) {
+    return new ProtobufLogEntry<T>(log, name, proto, metadata, timestamp);
+  }
+
+  /**
+   * Creates a protobuf-encoded log entry.
+   *
+   * @param <T> value class (inferred from proto)
+   * @param <MessageType> protobuf message type (inferred from proto)
+   * @param log datalog
+   * @param name name of the entry
+   * @param proto protobuf serialization implementation
+   * @param metadata metadata
+   * @return ProtobufLogEntry
+   */
+  public static <T, MessageType extends ProtoMessage<?>> ProtobufLogEntry<T> create(
+      DataLog log, String name, Protobuf<T, MessageType> proto, String metadata) {
+    return create(log, name, proto, metadata, 0);
+  }
+
+  /**
+   * Creates a protobuf-encoded log entry.
+   *
+   * @param <T> value class (inferred from proto)
+   * @param <MessageType> protobuf message type (inferred from proto)
+   * @param log datalog
+   * @param name name of the entry
+   * @param proto protobuf serialization implementation
+   * @param timestamp entry creation timestamp (0=now)
+   * @return ProtobufLogEntry
+   */
+  public static <T, MessageType extends ProtoMessage<?>> ProtobufLogEntry<T> create(
+      DataLog log, String name, Protobuf<T, MessageType> proto, long timestamp) {
+    return create(log, name, proto, "", timestamp);
+  }
+
+  /**
+   * Creates a protobuf-encoded log entry.
+   *
+   * @param <T> value class (inferred from proto)
+   * @param <MessageType> protobuf message type (inferred from proto)
+   * @param log datalog
+   * @param name name of the entry
+   * @param proto protobuf serialization implementation
+   * @return ProtobufLogEntry
+   */
+  public static <T, MessageType extends ProtoMessage<?>> ProtobufLogEntry<T> create(
+      DataLog log, String name, Protobuf<T, MessageType> proto) {
+    return create(log, name, proto, 0);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(T value, long timestamp) {
+    try {
+      synchronized (m_buf) {
+        ByteBuffer bb = m_buf.write(value);
+        m_log.appendRaw(m_entry, bb, 0, bb.position(), timestamp);
+      }
+    } catch (IOException e) {
+      // ignore
+    }
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   */
+  public void append(T value) {
+    append(value, 0);
+  }
+
+  private final ProtobufBuffer<T, ?> m_buf;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/datalog/RawLogEntry.java b/wpiutil/src/main/java/edu/wpi/first/util/datalog/RawLogEntry.java
index 160f734..972fc03 100644
--- a/wpiutil/src/main/java/edu/wpi/first/util/datalog/RawLogEntry.java
+++ b/wpiutil/src/main/java/edu/wpi/first/util/datalog/RawLogEntry.java
@@ -4,6 +4,8 @@
 
 package edu.wpi.first.util.datalog;
 
+import java.nio.ByteBuffer;
+
 /** Log raw byte array values. */
 public class RawLogEntry extends DataLogEntry {
   public static final String kDataType = "raw";
@@ -35,7 +37,7 @@
   /**
    * Appends a record to the log.
    *
-   * @param value Value to record
+   * @param value Value to record; will send entire array contents
    * @param timestamp Time stamp (0 to indicate now)
    */
   public void append(byte[] value, long timestamp) {
@@ -45,9 +47,74 @@
   /**
    * Appends a record to the log.
    *
-   * @param value Value to record
+   * @param value Value to record; will send entire array contents
    */
   public void append(byte[] value) {
-    m_log.appendRaw(m_entry, value, 0);
+    append(value, 0);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Data to record
+   * @param start Start position of data (in byte array)
+   * @param len Length of data (must be less than or equal to value.length - offset)
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(byte[] value, int start, int len, long timestamp) {
+    m_log.appendRaw(m_entry, value, start, len, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Data to record
+   * @param start Start position of data (in byte array)
+   * @param len Length of data (must be less than or equal to value.length - offset)
+   */
+  public void append(byte[] value, int start, int len) {
+    append(value, start, len, 0);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Data to record; will send from value.position() to value.capacity()
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(ByteBuffer value, long timestamp) {
+    m_log.appendRaw(m_entry, value, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Data to record; will send from value.position() to value.capacity()
+   */
+  public void append(ByteBuffer value) {
+    append(value, 0);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Data to record
+   * @param start Start position of data (in value buffer)
+   * @param len Length of data (must be less than or equal to value.length - offset)
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(ByteBuffer value, int start, int len, long timestamp) {
+    m_log.appendRaw(m_entry, value, start, len, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Data to record
+   * @param start Start position of data (in value buffer)
+   * @param len Length of data (must be less than or equal to value.length - offset)
+   */
+  public void append(ByteBuffer value, int start, int len) {
+    append(value, start, len, 0);
   }
 }
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/datalog/StructArrayLogEntry.java b/wpiutil/src/main/java/edu/wpi/first/util/datalog/StructArrayLogEntry.java
new file mode 100644
index 0000000..0f6cb2e
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/datalog/StructArrayLogEntry.java
@@ -0,0 +1,140 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.datalog;
+
+import edu.wpi.first.util.struct.Struct;
+import edu.wpi.first.util.struct.StructBuffer;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+
+/**
+ * Log struct-encoded array values.
+ *
+ * @param <T> value class
+ */
+public final class StructArrayLogEntry<T> extends DataLogEntry {
+  private StructArrayLogEntry(
+      DataLog log, String name, Struct<T> struct, String metadata, long timestamp) {
+    super(log, name, struct.getTypeString() + "[]", metadata, timestamp);
+    m_buf = StructBuffer.create(struct);
+    log.addSchema(struct, timestamp);
+  }
+
+  /**
+   * Creates a struct-encoded array log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @param metadata metadata
+   * @param timestamp entry creation timestamp (0=now)
+   * @return StructArrayLogEntry
+   */
+  public static <T> StructArrayLogEntry<T> create(
+      DataLog log, String name, Struct<T> struct, String metadata, long timestamp) {
+    return new StructArrayLogEntry<T>(log, name, struct, metadata, timestamp);
+  }
+
+  /**
+   * Creates a struct-encoded array log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @param metadata metadata
+   * @return StructArrayLogEntry
+   */
+  public static <T> StructArrayLogEntry<T> create(
+      DataLog log, String name, Struct<T> struct, String metadata) {
+    return create(log, name, struct, metadata, 0);
+  }
+
+  /**
+   * Creates a struct-encoded array log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @param timestamp entry creation timestamp (0=now)
+   * @return StructArrayLogEntry
+   */
+  public static <T> StructArrayLogEntry<T> create(
+      DataLog log, String name, Struct<T> struct, long timestamp) {
+    return create(log, name, struct, "", timestamp);
+  }
+
+  /**
+   * Creates a struct-encoded array log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @return StructArrayLogEntry
+   */
+  public static <T> StructArrayLogEntry<T> create(DataLog log, String name, Struct<T> struct) {
+    return create(log, name, struct, 0);
+  }
+
+  /**
+   * Ensures sufficient buffer space is available for the given number of elements.
+   *
+   * @param nelem number of elements
+   */
+  public void reserve(int nelem) {
+    synchronized (m_buf) {
+      m_buf.reserve(nelem);
+    }
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(T[] value, long timestamp) {
+    synchronized (this) {
+      ByteBuffer bb = m_buf.writeArray(value);
+      m_log.appendRaw(m_entry, bb, 0, bb.position(), timestamp);
+    }
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   */
+  public void append(T[] value) {
+    append(value, 0);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(Collection<T> value, long timestamp) {
+    synchronized (m_buf) {
+      ByteBuffer bb = m_buf.writeArray(value);
+      m_log.appendRaw(m_entry, bb, 0, bb.position(), timestamp);
+    }
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   */
+  public void append(Collection<T> value) {
+    append(value, 0);
+  }
+
+  private final StructBuffer<T> m_buf;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/datalog/StructLogEntry.java b/wpiutil/src/main/java/edu/wpi/first/util/datalog/StructLogEntry.java
new file mode 100644
index 0000000..a227c32
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/datalog/StructLogEntry.java
@@ -0,0 +1,106 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.datalog;
+
+import edu.wpi.first.util.struct.Struct;
+import edu.wpi.first.util.struct.StructBuffer;
+import java.nio.ByteBuffer;
+
+/**
+ * Log struct-encoded values.
+ *
+ * @param <T> value class
+ */
+public final class StructLogEntry<T> extends DataLogEntry {
+  private StructLogEntry(
+      DataLog log, String name, Struct<T> struct, String metadata, long timestamp) {
+    super(log, name, struct.getTypeString(), metadata, timestamp);
+    m_buf = StructBuffer.create(struct);
+    log.addSchema(struct, timestamp);
+  }
+
+  /**
+   * Creates a struct-encoded log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @param metadata metadata
+   * @param timestamp entry creation timestamp (0=now)
+   * @return StructLogEntry
+   */
+  public static <T> StructLogEntry<T> create(
+      DataLog log, String name, Struct<T> struct, String metadata, long timestamp) {
+    return new StructLogEntry<T>(log, name, struct, metadata, timestamp);
+  }
+
+  /**
+   * Creates a struct-encoded log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @param metadata metadata
+   * @return StructLogEntry
+   */
+  public static <T> StructLogEntry<T> create(
+      DataLog log, String name, Struct<T> struct, String metadata) {
+    return create(log, name, struct, metadata, 0);
+  }
+
+  /**
+   * Creates a struct-encoded log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @param timestamp entry creation timestamp (0=now)
+   * @return StructLogEntry
+   */
+  public static <T> StructLogEntry<T> create(
+      DataLog log, String name, Struct<T> struct, long timestamp) {
+    return create(log, name, struct, "", timestamp);
+  }
+
+  /**
+   * Creates a struct-encoded log entry.
+   *
+   * @param <T> value class (inferred from struct)
+   * @param log datalog
+   * @param name name of the entry
+   * @param struct struct serialization implementation
+   * @return StructLogEntry
+   */
+  public static <T> StructLogEntry<T> create(DataLog log, String name, Struct<T> struct) {
+    return create(log, name, struct, 0);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  public void append(T value, long timestamp) {
+    synchronized (m_buf) {
+      ByteBuffer bb = m_buf.write(value);
+      m_log.appendRaw(m_entry, bb, 0, bb.position(), timestamp);
+    }
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param value Value to record
+   */
+  public void append(T value) {
+    append(value, 0);
+  }
+
+  private final StructBuffer<T> m_buf;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/protobuf/Protobuf.java b/wpiutil/src/main/java/edu/wpi/first/util/protobuf/Protobuf.java
new file mode 100644
index 0000000..b77db7a
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/protobuf/Protobuf.java
@@ -0,0 +1,121 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.protobuf;
+
+import java.util.function.BiConsumer;
+import java.util.function.Predicate;
+import us.hebi.quickbuf.Descriptors.Descriptor;
+import us.hebi.quickbuf.Descriptors.FileDescriptor;
+import us.hebi.quickbuf.ProtoMessage;
+
+/**
+ * Interface for Protobuf serialization.
+ *
+ * <p>This is designed for serialization of more complex data structures including forward/backwards
+ * compatibility and repeated/nested/variable length members, etc. Serialization and deserialization
+ * code is auto-generated from .proto interface descriptions (the MessageType generic parameter).
+ *
+ * <p>Idiomatically, classes that support protobuf serialization should provide a static final
+ * member named "proto" that provides an instance of an implementation of this interface.
+ *
+ * @param <T> object type
+ * @param <MessageType> protobuf message type
+ */
+public interface Protobuf<T, MessageType extends ProtoMessage<?>> {
+  /**
+   * Gets the Class object for the stored value.
+   *
+   * @return Class
+   */
+  Class<T> getTypeClass();
+
+  /**
+   * Gets the type string (e.g. for NetworkTables). This should be globally unique and start with
+   * "proto:".
+   *
+   * @return type string
+   */
+  default String getTypeString() {
+    return "proto:" + getDescriptor().getFullName();
+  }
+
+  /**
+   * Gets the protobuf descriptor.
+   *
+   * @return descriptor
+   */
+  Descriptor getDescriptor();
+
+  /**
+   * Gets the list of protobuf types referenced by this protobuf.
+   *
+   * @return list of protobuf types
+   */
+  default Protobuf<?, ?>[] getNested() {
+    return new Protobuf<?, ?>[] {};
+  }
+
+  /**
+   * Creates protobuf message.
+   *
+   * @return protobuf message
+   */
+  MessageType createMessage();
+
+  /**
+   * Deserializes an object from a protobuf message.
+   *
+   * @param msg protobuf message
+   * @return New object
+   */
+  T unpack(MessageType msg);
+
+  /**
+   * Copies the object contents into a protobuf message. Implementations should call either
+   * msg.setMember(member) or member.copyToProto(msg.getMutableMember()) for each member.
+   *
+   * @param msg protobuf message
+   * @param value object to serialize
+   */
+  void pack(MessageType msg, T value);
+
+  /**
+   * Updates the object contents from a protobuf message. Implementations should call
+   * msg.getMember(member), MemberClass.makeFromProto(msg.getMember()), or
+   * member.updateFromProto(msg.getMember()) for each member.
+   *
+   * <p>Immutable classes cannot and should not implement this function. The default implementation
+   * throws UnsupportedOperationException.
+   *
+   * @param out object to update
+   * @param msg protobuf message
+   * @throws UnsupportedOperationException if the object is immutable
+   */
+  default void unpackInto(T out, MessageType msg) {
+    throw new UnsupportedOperationException("object does not support unpackInto");
+  }
+
+  /**
+   * Loops over all protobuf descriptors including nested/referenced descriptors.
+   *
+   * @param exists function that returns false if fn should be called for the given type string
+   * @param fn function to call for each descriptor
+   */
+  default void forEachDescriptor(Predicate<String> exists, BiConsumer<String, byte[]> fn) {
+    forEachDescriptorImpl(getDescriptor().getFile(), exists, fn);
+  }
+
+  private static void forEachDescriptorImpl(
+      FileDescriptor desc, Predicate<String> exists, BiConsumer<String, byte[]> fn) {
+    String name = "proto:" + desc.getFullName();
+    if (exists.test(name)) {
+      return;
+    }
+    for (FileDescriptor dep : desc.getDependencies()) {
+      forEachDescriptorImpl(dep, exists, fn);
+    }
+    fn.accept(name, desc.toProtoBytes());
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/protobuf/ProtobufBuffer.java b/wpiutil/src/main/java/edu/wpi/first/util/protobuf/ProtobufBuffer.java
new file mode 100644
index 0000000..af3e466
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/protobuf/ProtobufBuffer.java
@@ -0,0 +1,164 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.protobuf;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import us.hebi.quickbuf.ProtoMessage;
+import us.hebi.quickbuf.ProtoSink;
+import us.hebi.quickbuf.ProtoSource;
+
+/**
+ * Reusable buffer for serialization/deserialization to/from a protobuf.
+ *
+ * @param <T> object type
+ * @param <MessageType> protobuf message type
+ */
+public final class ProtobufBuffer<T, MessageType extends ProtoMessage<?>> {
+  private ProtobufBuffer(Protobuf<T, MessageType> proto) {
+    m_buf = ByteBuffer.allocateDirect(1024);
+    m_sink = ProtoSink.newDirectSink();
+    m_sink.setOutput(m_buf);
+    m_source = ProtoSource.newDirectSource();
+    m_msg = proto.createMessage();
+    m_proto = proto;
+  }
+
+  public static <T, MessageType extends ProtoMessage<?>> ProtobufBuffer<T, MessageType> create(
+      Protobuf<T, MessageType> proto) {
+    return new ProtobufBuffer<T, MessageType>(proto);
+  }
+
+  /**
+   * Gets the protobuf object of the stored type.
+   *
+   * @return protobuf object
+   */
+  public Protobuf<T, MessageType> getProto() {
+    return m_proto;
+  }
+
+  /**
+   * Gets the type string.
+   *
+   * @return type string
+   */
+  public String getTypeString() {
+    return m_proto.getTypeString();
+  }
+
+  /**
+   * Serializes a value to a ByteBuffer. The returned ByteBuffer is a direct byte buffer with the
+   * position set to the end of the serialized data.
+   *
+   * @param value value
+   * @return byte buffer
+   * @throws IOException if serialization failed
+   */
+  public ByteBuffer write(T value) throws IOException {
+    m_msg.clearQuick();
+    m_proto.pack(m_msg, value);
+    int size = m_msg.getSerializedSize();
+    if (size < m_buf.capacity()) {
+      m_buf = ByteBuffer.allocateDirect(size * 2);
+      m_sink.setOutput(m_buf);
+    }
+    m_sink.reset();
+    m_msg.writeTo(m_sink);
+    m_buf.position(m_sink.getTotalBytesWritten());
+    return m_buf;
+  }
+
+  /**
+   * Deserializes a value from a byte array, creating a new object.
+   *
+   * @param buf byte array
+   * @param start starting location within byte array
+   * @param len length of serialized data
+   * @return new object
+   * @throws IOException if deserialization failed
+   */
+  public T read(byte[] buf, int start, int len) throws IOException {
+    m_msg.clearQuick();
+    m_source.setInput(buf, start, len);
+    m_msg.mergeFrom(m_source);
+    return m_proto.unpack(m_msg);
+  }
+
+  /**
+   * Deserializes a value from a byte array, creating a new object.
+   *
+   * @param buf byte array
+   * @return new object
+   * @throws IOException if deserialization failed
+   */
+  public T read(byte[] buf) throws IOException {
+    return read(buf, 0, buf.length);
+  }
+
+  /**
+   * Deserializes a value from a ByteBuffer, creating a new object.
+   *
+   * @param buf byte buffer
+   * @return new object
+   * @throws IOException if deserialization failed
+   */
+  public T read(ByteBuffer buf) throws IOException {
+    m_msg.clearQuick();
+    m_source.setInput(buf);
+    m_msg.mergeFrom(m_source);
+    return m_proto.unpack(m_msg);
+  }
+
+  /**
+   * Deserializes a value from a byte array into a mutable object.
+   *
+   * @param out object (will be updated with deserialized contents)
+   * @param buf byte array
+   * @param start starting location within byte array
+   * @param len length of serialized data
+   * @throws IOException if deserialization failed
+   * @throws UnsupportedOperationException if the object is immutable
+   */
+  public void readInto(T out, byte[] buf, int start, int len) throws IOException {
+    m_msg.clearQuick();
+    m_source.setInput(buf, start, len);
+    m_msg.mergeFrom(m_source);
+    m_proto.unpackInto(out, m_msg);
+  }
+
+  /**
+   * Deserializes a value from a byte array into a mutable object.
+   *
+   * @param out object (will be updated with deserialized contents)
+   * @param buf byte array
+   * @throws IOException if deserialization failed
+   * @throws UnsupportedOperationException if the object is immutable
+   */
+  public void readInto(T out, byte[] buf) throws IOException {
+    readInto(out, buf, 0, buf.length);
+  }
+
+  /**
+   * Deserializes a value from a ByteBuffer into a mutable object.
+   *
+   * @param out object (will be updated with deserialized contents)
+   * @param buf byte buffer
+   * @throws IOException if deserialization failed
+   * @throws UnsupportedOperationException if the object is immutable
+   */
+  public void readInto(T out, ByteBuffer buf) throws IOException {
+    m_msg.clearQuick();
+    m_source.setInput(buf);
+    m_msg.mergeFrom(m_source);
+    m_proto.unpackInto(out, m_msg);
+  }
+
+  private ByteBuffer m_buf;
+  private final ProtoSink m_sink;
+  private final ProtoSource m_source;
+  private final MessageType m_msg;
+  private final Protobuf<T, MessageType> m_proto;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/sendable/SendableBuilder.java b/wpiutil/src/main/java/edu/wpi/first/util/sendable/SendableBuilder.java
index a58c3a3..db822ce 100644
--- a/wpiutil/src/main/java/edu/wpi/first/util/sendable/SendableBuilder.java
+++ b/wpiutil/src/main/java/edu/wpi/first/util/sendable/SendableBuilder.java
@@ -56,6 +56,14 @@
   void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter);
 
   /**
+   * Add a constant boolean property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstBoolean(String key, boolean value);
+
+  /**
    * Add an integer property.
    *
    * @param key property name
@@ -65,6 +73,14 @@
   void addIntegerProperty(String key, LongSupplier getter, LongConsumer setter);
 
   /**
+   * Add a constant integer property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstInteger(String key, long value);
+
+  /**
    * Add a float property.
    *
    * @param key property name
@@ -74,6 +90,14 @@
   void addFloatProperty(String key, FloatSupplier getter, FloatConsumer setter);
 
   /**
+   * Add a constant float property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstFloat(String key, float value);
+
+  /**
    * Add a double property.
    *
    * @param key property name
@@ -83,6 +107,14 @@
   void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter);
 
   /**
+   * Add a constant double property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstDouble(String key, double value);
+
+  /**
    * Add a string property.
    *
    * @param key property name
@@ -92,6 +124,14 @@
   void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter);
 
   /**
+   * Add a constant string property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstString(String key, String value);
+
+  /**
    * Add a boolean array property.
    *
    * @param key property name
@@ -101,6 +141,14 @@
   void addBooleanArrayProperty(String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter);
 
   /**
+   * Add a constant boolean array property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstBooleanArray(String key, boolean[] value);
+
+  /**
    * Add an integer array property.
    *
    * @param key property name
@@ -110,6 +158,14 @@
   void addIntegerArrayProperty(String key, Supplier<long[]> getter, Consumer<long[]> setter);
 
   /**
+   * Add a constant integer property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstIntegerArray(String key, long[] value);
+
+  /**
    * Add a float array property.
    *
    * @param key property name
@@ -119,6 +175,14 @@
   void addFloatArrayProperty(String key, Supplier<float[]> getter, Consumer<float[]> setter);
 
   /**
+   * Add a constant float array property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstFloatArray(String key, float[] value);
+
+  /**
    * Add a double array property.
    *
    * @param key property name
@@ -128,6 +192,14 @@
   void addDoubleArrayProperty(String key, Supplier<double[]> getter, Consumer<double[]> setter);
 
   /**
+   * Add a constant double array property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstDoubleArray(String key, double[] value);
+
+  /**
    * Add a string array property.
    *
    * @param key property name
@@ -137,6 +209,14 @@
   void addStringArrayProperty(String key, Supplier<String[]> getter, Consumer<String[]> setter);
 
   /**
+   * Add a constant string array property.
+   *
+   * @param key property name
+   * @param value the value
+   */
+  void publishConstStringArray(String key, String[] value);
+
+  /**
    * Add a raw property.
    *
    * @param key property name
@@ -148,6 +228,15 @@
       String key, String typeString, Supplier<byte[]> getter, Consumer<byte[]> setter);
 
   /**
+   * Add a constant raw property.
+   *
+   * @param key property name
+   * @param typeString type string
+   * @param value the value
+   */
+  void publishConstRaw(String key, String typeString, byte[] value);
+
+  /**
    * Gets the kind of backend being used.
    *
    * @return Backend kind
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/BadSchemaException.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/BadSchemaException.java
new file mode 100644
index 0000000..6ff2236
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/BadSchemaException.java
@@ -0,0 +1,43 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+public class BadSchemaException extends Exception {
+  private final String m_field;
+
+  public BadSchemaException(String s) {
+    super(s);
+    m_field = "";
+  }
+
+  public BadSchemaException(String message, Throwable cause) {
+    super(message, cause);
+    m_field = "";
+  }
+
+  public BadSchemaException(Throwable cause) {
+    super(cause);
+    m_field = "";
+  }
+
+  public BadSchemaException(String field, String s) {
+    super(s);
+    m_field = field;
+  }
+
+  public BadSchemaException(String field, String message, Throwable cause) {
+    super(message, cause);
+    m_field = field;
+  }
+
+  public String getField() {
+    return m_field;
+  }
+
+  @Override
+  public String toString() {
+    return m_field.isEmpty() ? getMessage() : "field " + m_field + ": " + getMessage();
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/DynamicStruct.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/DynamicStruct.java
new file mode 100644
index 0000000..165f7db
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/DynamicStruct.java
@@ -0,0 +1,632 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ReadOnlyBufferException;
+import java.nio.charset.StandardCharsets;
+
+/** Dynamic (run-time) access to a serialized raw struct. */
+public final class DynamicStruct {
+  private DynamicStruct(StructDescriptor desc, ByteBuffer data) {
+    m_desc = desc;
+    m_data = data.order(ByteOrder.LITTLE_ENDIAN);
+  }
+
+  /**
+   * Constructs a new dynamic struct object with internal storage. The descriptor must be valid. The
+   * internal storage is allocated using ByteBuffer.allocate().
+   *
+   * @param desc struct descriptor
+   * @return dynamic struct object
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public static DynamicStruct allocate(StructDescriptor desc) {
+    return new DynamicStruct(desc, ByteBuffer.allocate(desc.getSize()));
+  }
+
+  /**
+   * Constructs a new dynamic struct object with internal storage. The descriptor must be valid. The
+   * internal storage is allocated using ByteBuffer.allocateDirect().
+   *
+   * @param desc struct descriptor
+   * @return dynamic struct object
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public static DynamicStruct allocateDirect(StructDescriptor desc) {
+    return new DynamicStruct(desc, ByteBuffer.allocateDirect(desc.getSize()));
+  }
+
+  /**
+   * Constructs a new dynamic struct object. Note: the passed data buffer is not copied.
+   * Modifications to the passed buffer will be reflected in the struct and vice-versa.
+   *
+   * @param desc struct descriptor
+   * @param data byte buffer containing serialized data starting at current position
+   * @return dynamic struct object
+   */
+  public static DynamicStruct wrap(StructDescriptor desc, ByteBuffer data) {
+    return new DynamicStruct(desc, data.slice());
+  }
+
+  /**
+   * Gets the struct descriptor.
+   *
+   * @return struct descriptor
+   */
+  public StructDescriptor getDescriptor() {
+    return m_desc;
+  }
+
+  /**
+   * Gets the serialized backing data buffer.
+   *
+   * @return data buffer
+   */
+  public ByteBuffer getBuffer() {
+    return m_data.duplicate().position(0);
+  }
+
+  /**
+   * Overwrites the entire serialized struct by copying data from a byte array.
+   *
+   * @param data replacement data for the struct
+   * @throws BufferUnderflowException if data is smaller than the struct size
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public void setData(byte[] data) {
+    if (data.length < m_desc.getSize()) {
+      throw new BufferUnderflowException();
+    }
+    m_data.position(0).put(data);
+  }
+
+  /**
+   * Overwrites the entire serialized struct by copying data from a byte buffer.
+   *
+   * @param data replacement data for the struct; copy starts from current position
+   * @throws BufferUnderflowException if remaining data is smaller than the struct size
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public void setData(ByteBuffer data) {
+    if (data.remaining() < m_desc.getSize()) {
+      throw new BufferUnderflowException();
+    }
+    int oldLimit = data.limit();
+    m_data.position(0).put(data.limit(m_desc.getSize()));
+    data.limit(oldLimit);
+  }
+
+  /**
+   * Gets a struct field descriptor by name.
+   *
+   * @param name field name
+   * @return field descriptor, or null if no field with that name exists
+   */
+  public StructFieldDescriptor findField(String name) {
+    return m_desc.findFieldByName(name);
+  }
+
+  /**
+   * Gets the value of a boolean field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return boolean field value
+   * @throws UnsupportedOperationException if field is not bool type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   */
+  public boolean getBoolField(StructFieldDescriptor field, int arrIndex) {
+    if (field.getType() != StructFieldType.kBool) {
+      throw new UnsupportedOperationException("field is not bool type");
+    }
+    return getFieldImpl(field, arrIndex) != 0;
+  }
+
+  /**
+   * Gets the value of a boolean field.
+   *
+   * @param field field descriptor
+   * @return boolean field value
+   * @throws UnsupportedOperationException if field is not bool type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public boolean getBoolField(StructFieldDescriptor field) {
+    return getBoolField(field, 0);
+  }
+
+  /**
+   * Sets the value of a boolean field.
+   *
+   * @param field field descriptor
+   * @param value boolean value
+   * @param arrIndex array index (must be less than field array size)
+   * @throws UnsupportedOperationException if field is not bool type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setBoolField(StructFieldDescriptor field, boolean value, int arrIndex) {
+    if (field.getType() != StructFieldType.kBool) {
+      throw new UnsupportedOperationException("field is not bool type");
+    }
+    setFieldImpl(field, value ? 1 : 0, arrIndex);
+  }
+
+  /**
+   * Sets the value of a boolean field.
+   *
+   * @param field field descriptor
+   * @param value boolean value
+   * @throws UnsupportedOperationException if field is not bool type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setBoolField(StructFieldDescriptor field, boolean value) {
+    setBoolField(field, value, 0);
+  }
+
+  /**
+   * Gets the value of an integer field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return integer field value
+   * @throws UnsupportedOperationException if field is not integer type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   */
+  public long getIntField(StructFieldDescriptor field, int arrIndex) {
+    if (!field.isInt() && !field.isUint()) {
+      throw new UnsupportedOperationException("field is not integer type");
+    }
+    return getFieldImpl(field, arrIndex);
+  }
+
+  /**
+   * Gets the value of an integer field.
+   *
+   * @param field field descriptor
+   * @return integer field value
+   * @throws UnsupportedOperationException if field is not integer type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public long getIntField(StructFieldDescriptor field) {
+    return getIntField(field, 0);
+  }
+
+  /**
+   * Sets the value of an integer field.
+   *
+   * @param field field descriptor
+   * @param value integer value
+   * @param arrIndex array index (must be less than field array size)
+   * @throws UnsupportedOperationException if field is not integer type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setIntField(StructFieldDescriptor field, long value, int arrIndex) {
+    if (!field.isInt() && !field.isUint()) {
+      throw new UnsupportedOperationException("field is not integer type");
+    }
+    setFieldImpl(field, value, arrIndex);
+  }
+
+  /**
+   * Sets the value of an integer field.
+   *
+   * @param field field descriptor
+   * @param value integer value
+   * @throws UnsupportedOperationException if field is not integer type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setIntField(StructFieldDescriptor field, long value) {
+    setIntField(field, value, 0);
+  }
+
+  /**
+   * Gets the value of a float field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return float field value
+   * @throws UnsupportedOperationException if field is not float type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   */
+  public float getFloatField(StructFieldDescriptor field, int arrIndex) {
+    if (field.getType() != StructFieldType.kFloat) {
+      throw new UnsupportedOperationException("field is not float type");
+    }
+    return Float.intBitsToFloat((int) getFieldImpl(field, arrIndex));
+  }
+
+  /**
+   * Gets the value of a float field.
+   *
+   * @param field field descriptor
+   * @return float field value
+   * @throws UnsupportedOperationException if field is not float type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public float getFloatField(StructFieldDescriptor field) {
+    return getFloatField(field, 0);
+  }
+
+  /**
+   * Sets the value of a float field.
+   *
+   * @param field field descriptor
+   * @param value float value
+   * @param arrIndex array index (must be less than field array size)
+   * @throws UnsupportedOperationException if field is not float type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setFloatField(StructFieldDescriptor field, float value, int arrIndex) {
+    if (field.getType() != StructFieldType.kFloat) {
+      throw new UnsupportedOperationException("field is not float type");
+    }
+    setFieldImpl(field, Float.floatToIntBits(value), arrIndex);
+  }
+
+  /**
+   * Sets the value of a float field.
+   *
+   * @param field field descriptor
+   * @param value float value
+   * @throws UnsupportedOperationException if field is not float type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setFloatField(StructFieldDescriptor field, float value) {
+    setFloatField(field, value, 0);
+  }
+
+  /**
+   * Gets the value of a double field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return double field value
+   * @throws UnsupportedOperationException if field is not double type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   */
+  public double getDoubleField(StructFieldDescriptor field, int arrIndex) {
+    if (field.getType() != StructFieldType.kDouble) {
+      throw new UnsupportedOperationException("field is not double type");
+    }
+    return Double.longBitsToDouble(getFieldImpl(field, arrIndex));
+  }
+
+  /**
+   * Gets the value of a double field.
+   *
+   * @param field field descriptor
+   * @return double field value
+   * @throws UnsupportedOperationException if field is not double type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public double getDoubleField(StructFieldDescriptor field) {
+    return getDoubleField(field, 0);
+  }
+
+  /**
+   * Sets the value of a double field.
+   *
+   * @param field field descriptor
+   * @param value double value
+   * @param arrIndex array index (must be less than field array size)
+   * @throws UnsupportedOperationException if field is not double type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setDoubleField(StructFieldDescriptor field, double value, int arrIndex) {
+    if (field.getType() != StructFieldType.kDouble) {
+      throw new UnsupportedOperationException("field is not double type");
+    }
+    setFieldImpl(field, Double.doubleToLongBits(value), arrIndex);
+  }
+
+  /**
+   * Sets the value of a double field.
+   *
+   * @param field field descriptor
+   * @param value double value
+   * @throws UnsupportedOperationException if field is not double type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setDoubleField(StructFieldDescriptor field, double value) {
+    setDoubleField(field, value, 0);
+  }
+
+  /**
+   * Gets the value of a character or character array field.
+   *
+   * @param field field descriptor
+   * @return field value
+   * @throws UnsupportedOperationException if field is not char type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public String getStringField(StructFieldDescriptor field) {
+    if (field.getType() != StructFieldType.kChar) {
+      throw new UnsupportedOperationException("field is not char type");
+    }
+    if (!field.getParent().equals(m_desc)) {
+      throw new IllegalArgumentException("field is not part of this struct");
+    }
+    if (!m_desc.isValid()) {
+      throw new IllegalStateException("struct descriptor is not valid");
+    }
+    byte[] bytes = new byte[field.m_arraySize];
+    m_data.position(field.m_offset).get(bytes, 0, field.m_arraySize);
+    return new String(bytes, StandardCharsets.UTF_8);
+  }
+
+  /**
+   * Sets the value of a character or character array field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @throws UnsupportedOperationException if field is not char type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public void setStringField(StructFieldDescriptor field, String value) {
+    if (field.getType() != StructFieldType.kChar) {
+      throw new UnsupportedOperationException("field is not char type");
+    }
+    if (!field.getParent().equals(m_desc)) {
+      throw new IllegalArgumentException("field is not part of this struct");
+    }
+    if (!m_desc.isValid()) {
+      throw new IllegalStateException("struct descriptor is not valid");
+    }
+    ByteBuffer bb = StandardCharsets.UTF_8.encode(value);
+    int len = Math.min(bb.remaining(), field.m_arraySize);
+    m_data.position(field.m_offset).put(bb.limit(len));
+    for (int i = len; i < field.m_arraySize; i++) {
+      m_data.put((byte) 0);
+    }
+  }
+
+  /**
+   * Gets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   * @throws UnsupportedOperationException if field is not of struct type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   */
+  public DynamicStruct getStructField(StructFieldDescriptor field, int arrIndex) {
+    if (field.getType() != StructFieldType.kStruct) {
+      throw new UnsupportedOperationException("field is not struct type");
+    }
+    if (!field.getParent().equals(m_desc)) {
+      throw new IllegalArgumentException("field is not part of this struct");
+    }
+    if (!m_desc.isValid()) {
+      throw new IllegalStateException("struct descriptor is not valid");
+    }
+    if (arrIndex < 0 || arrIndex >= field.m_arraySize) {
+      throw new ArrayIndexOutOfBoundsException(
+          "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")");
+    }
+    StructDescriptor struct = field.getStruct();
+    return wrap(struct, m_data.position(field.m_offset + arrIndex * struct.m_size));
+  }
+
+  /**
+   * Gets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @return field value
+   * @throws UnsupportedOperationException if field is not of struct type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   */
+  public DynamicStruct getStructField(StructFieldDescriptor field) {
+    return getStructField(field, 0);
+  }
+
+  /**
+   * Sets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @param value struct value
+   * @param arrIndex array index (must be less than field array size)
+   * @throws UnsupportedOperationException if field is not struct type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ArrayIndexOutOfBoundsException if array index is out of bounds
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setStructField(StructFieldDescriptor field, DynamicStruct value, int arrIndex) {
+    if (field.getType() != StructFieldType.kStruct) {
+      throw new UnsupportedOperationException("field is not struct type");
+    }
+    if (!field.getParent().equals(m_desc)) {
+      throw new IllegalArgumentException("field is not part of this struct");
+    }
+    if (!m_desc.isValid()) {
+      throw new IllegalStateException("struct descriptor is not valid");
+    }
+    StructDescriptor struct = field.getStruct();
+    if (!value.getDescriptor().equals(struct)) {
+      throw new IllegalArgumentException("value's struct type does not match field struct type");
+    }
+    if (!value.getDescriptor().isValid()) {
+      throw new IllegalStateException("value's struct descriptor is not valid");
+    }
+    if (arrIndex < 0 || arrIndex >= field.m_arraySize) {
+      throw new ArrayIndexOutOfBoundsException(
+          "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")");
+    }
+    m_data
+        .position(field.m_offset + arrIndex * struct.m_size)
+        .put(value.m_data.position(0).limit(value.getDescriptor().getSize()));
+  }
+
+  /**
+   * Sets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @param value struct value
+   * @throws UnsupportedOperationException if field is not struct type
+   * @throws IllegalArgumentException if field is not a member of this struct
+   * @throws IllegalStateException if struct descriptor is invalid
+   * @throws ReadOnlyBufferException if the underlying buffer is read-only
+   */
+  public void setStructField(StructFieldDescriptor field, DynamicStruct value) {
+    setStructField(field, value, 0);
+  }
+
+  private long getFieldImpl(StructFieldDescriptor field, int arrIndex) {
+    if (!field.getParent().equals(m_desc)) {
+      throw new IllegalArgumentException("field is not part of this struct");
+    }
+    if (!m_desc.isValid()) {
+      throw new IllegalStateException("struct descriptor is not valid");
+    }
+    if (arrIndex < 0 || arrIndex >= field.m_arraySize) {
+      throw new ArrayIndexOutOfBoundsException(
+          "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")");
+    }
+
+    long val;
+    switch (field.m_size) {
+      case 1:
+        val = m_data.get(field.m_offset + arrIndex);
+        break;
+      case 2:
+        val = m_data.getShort(field.m_offset + arrIndex * 2);
+        break;
+      case 4:
+        val = m_data.getInt(field.m_offset + arrIndex * 4);
+        break;
+      case 8:
+        val = m_data.getLong(field.m_offset + arrIndex * 8);
+        break;
+      default:
+        throw new IllegalStateException("invalid field size");
+    }
+
+    if (field.isUint() || field.getType() == StructFieldType.kBool) {
+      // for unsigned fields, we can simply logical shift and mask
+      return (val >>> field.m_bitShift) & field.getBitMask();
+    } else {
+      // to get sign extension, shift so the sign bit within the bitfield goes to the long's sign
+      // bit (also clearing all higher bits), then shift back down (also clearing all lower bits);
+      // since upper and lower bits are cleared with the shifts, the bitmask is unnecessary
+      return (val << (64 - field.m_bitShift - field.getBitWidth())) >> (64 - field.getBitWidth());
+    }
+  }
+
+  private void setFieldImpl(StructFieldDescriptor field, long value, int arrIndex) {
+    if (!field.getParent().equals(m_desc)) {
+      throw new IllegalArgumentException("field is not part of this struct");
+    }
+    if (!m_desc.isValid()) {
+      throw new IllegalStateException("struct descriptor is not valid");
+    }
+    if (arrIndex < 0 || arrIndex >= field.m_arraySize) {
+      throw new ArrayIndexOutOfBoundsException(
+          "arrIndex (" + arrIndex + ") is larger than array size (" + field.m_arraySize + ")");
+    }
+
+    // common case is no bit shift and no masking
+    if (!field.isBitField()) {
+      switch (field.m_size) {
+        case 1:
+          m_data.put(field.m_offset + arrIndex, (byte) value);
+          break;
+        case 2:
+          m_data.putShort(field.m_offset + arrIndex * 2, (short) value);
+          break;
+        case 4:
+          m_data.putInt(field.m_offset + arrIndex * 4, (int) value);
+          break;
+        case 8:
+          m_data.putLong(field.m_offset + arrIndex * 8, value);
+          break;
+        default:
+          throw new IllegalStateException("invalid field size");
+      }
+      return;
+    }
+
+    // handle bit shifting and masking into current value
+    switch (field.m_size) {
+      case 1:
+        {
+          byte val = m_data.get(field.m_offset + arrIndex);
+          val &= ~(field.getBitMask() << field.m_bitShift);
+          val |= (value & field.getBitMask()) << field.m_bitShift;
+          m_data.put(field.m_offset + arrIndex, val);
+          break;
+        }
+      case 2:
+        {
+          short val = m_data.getShort(field.m_offset + arrIndex * 2);
+          val &= ~(field.getBitMask() << field.m_bitShift);
+          val |= (value & field.getBitMask()) << field.m_bitShift;
+          m_data.putShort(field.m_offset + arrIndex * 2, val);
+          break;
+        }
+      case 4:
+        {
+          int val = m_data.getInt(field.m_offset + arrIndex * 4);
+          val &= ~(field.getBitMask() << field.m_bitShift);
+          val |= (value & field.getBitMask()) << field.m_bitShift;
+          m_data.putInt(field.m_offset + arrIndex * 4, val);
+          break;
+        }
+      case 8:
+        {
+          long val = m_data.getLong(field.m_offset + arrIndex * 8);
+          val &= ~(field.getBitMask() << field.m_bitShift);
+          val |= (value & field.getBitMask()) << field.m_bitShift;
+          m_data.putLong(field.m_offset + arrIndex * 8, val);
+          break;
+        }
+      default:
+        throw new IllegalStateException("invalid field size");
+    }
+  }
+
+  private final StructDescriptor m_desc;
+  private final ByteBuffer m_data;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/Struct.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/Struct.java
new file mode 100644
index 0000000..630ef8c
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/Struct.java
@@ -0,0 +1,116 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Interface for raw struct serialization.
+ *
+ * <p>This is designed for serializing small fixed-size data structures in the fastest and most
+ * compact means possible. Serialization consists of making relative put() calls to a ByteBuffer and
+ * deserialization consists of making relative get() calls from a ByteBuffer.
+ *
+ * <p>Idiomatically, classes that support raw struct serialization should provide a static final
+ * member named "struct" that provides an instance of an implementation of this interface.
+ *
+ * @param <T> object type
+ */
+public interface Struct<T> {
+  /** Serialized size of a "bool" value. */
+  int kSizeBool = 1;
+
+  /** Serialized size of an "int8" or "uint8" value. */
+  int kSizeInt8 = 1;
+
+  /** Serialized size of an "int16" or "uint16" value. */
+  int kSizeInt16 = 2;
+
+  /** Serialized size of an "int32" or "uint32" value. */
+  int kSizeInt32 = 4;
+
+  /** Serialized size of an "int64" or "uint64" value. */
+  int kSizeInt64 = 8;
+
+  /** Serialized size of an "float" or "float32" value. */
+  int kSizeFloat = 4;
+
+  /** Serialized size of an "double" or "float64" value. */
+  int kSizeDouble = 8;
+
+  /**
+   * Gets the Class object for the stored value.
+   *
+   * @return Class
+   */
+  Class<T> getTypeClass();
+
+  /**
+   * Gets the type string (e.g. for NetworkTables). This should be globally unique and start with
+   * "struct:".
+   *
+   * @return type string
+   */
+  String getTypeString();
+
+  /**
+   * Gets the serialized size (in bytes). This should always be a constant.
+   *
+   * @return serialized size
+   */
+  int getSize();
+
+  /**
+   * Gets the schema.
+   *
+   * @return schema
+   */
+  String getSchema();
+
+  /**
+   * Gets the list of struct types referenced by this struct.
+   *
+   * @return list of struct types
+   */
+  default Struct<?>[] getNested() {
+    return new Struct<?>[] {};
+  }
+
+  /**
+   * Deserializes an object from a raw struct serialized ByteBuffer starting at the current
+   * position. Will increment the ByteBuffer position by getStructSize() bytes. Will not otherwise
+   * modify the ByteBuffer (e.g. byte order will not be changed).
+   *
+   * @param bb ByteBuffer
+   * @return New object
+   */
+  T unpack(ByteBuffer bb);
+
+  /**
+   * Puts object contents to a ByteBuffer starting at the current position. Will increment the
+   * ByteBuffer position by getStructSize() bytes. Will not otherwise modify the ByteBuffer (e.g.
+   * byte order will not be changed).
+   *
+   * @param bb ByteBuffer
+   * @param value object to serialize
+   */
+  void pack(ByteBuffer bb, T value);
+
+  /**
+   * Updates object contents from a raw struct serialized ByteBuffer starting at the current
+   * position. Will increment the ByteBuffer position by getStructSize() bytes. Will not otherwise
+   * modify the ByteBuffer (e.g. byte order will not be changed).
+   *
+   * <p>Immutable classes cannot and should not implement this function. The default implementation
+   * throws UnsupportedOperationException.
+   *
+   * @param out object to update
+   * @param bb ByteBuffer
+   * @throws UnsupportedOperationException if the object is immutable
+   */
+  default void unpackInto(T out, ByteBuffer bb) {
+    throw new UnsupportedOperationException("object does not support unpackInto");
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/StructBuffer.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructBuffer.java
new file mode 100644
index 0000000..0e8aa18
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructBuffer.java
@@ -0,0 +1,224 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Collection;
+
+/**
+ * Reusable buffer for serialization/deserialization to/from a raw struct.
+ *
+ * @param <T> object type
+ */
+public final class StructBuffer<T> {
+  private StructBuffer(Struct<T> struct) {
+    m_structSize = struct.getSize();
+    m_buf = ByteBuffer.allocateDirect(m_structSize).order(ByteOrder.LITTLE_ENDIAN);
+    m_struct = struct;
+  }
+
+  public static <T> StructBuffer<T> create(Struct<T> struct) {
+    return new StructBuffer<T>(struct);
+  }
+
+  /**
+   * Gets the struct object of the stored type.
+   *
+   * @return struct object
+   */
+  public Struct<T> getStruct() {
+    return m_struct;
+  }
+
+  /**
+   * Gets the type string.
+   *
+   * @return type string
+   */
+  public String getTypeString() {
+    return m_struct.getTypeString();
+  }
+
+  /**
+   * Ensures sufficient buffer space is available for the given number of elements.
+   *
+   * @param nelem number of elements
+   */
+  public void reserve(int nelem) {
+    if ((nelem * m_structSize) > m_buf.capacity()) {
+      m_buf = ByteBuffer.allocateDirect(nelem * m_structSize).order(ByteOrder.LITTLE_ENDIAN);
+    }
+  }
+
+  /**
+   * Serializes a value to a ByteBuffer. The returned ByteBuffer is a direct byte buffer with the
+   * position set to the end of the serialized data.
+   *
+   * @param value value
+   * @return byte buffer
+   */
+  public ByteBuffer write(T value) {
+    m_buf.position(0);
+    m_struct.pack(m_buf, value);
+    return m_buf;
+  }
+
+  /**
+   * Deserializes a value from a byte array, creating a new object.
+   *
+   * @param buf byte array
+   * @param start starting location within byte array
+   * @param len length of serialized data
+   * @return new object
+   */
+  public T read(byte[] buf, int start, int len) {
+    return read(ByteBuffer.wrap(buf, start, len));
+  }
+
+  /**
+   * Deserializes a value from a byte array, creating a new object.
+   *
+   * @param buf byte array
+   * @return new object
+   */
+  public T read(byte[] buf) {
+    return read(buf, 0, buf.length);
+  }
+
+  /**
+   * Deserializes a value from a ByteBuffer, creating a new object.
+   *
+   * @param buf byte buffer
+   * @return new object
+   */
+  public T read(ByteBuffer buf) {
+    buf.order(ByteOrder.LITTLE_ENDIAN);
+    return m_struct.unpack(buf);
+  }
+
+  /**
+   * Deserializes a value from a byte array into a mutable object.
+   *
+   * @param out object (will be updated with deserialized contents)
+   * @param buf byte array
+   * @param start starting location within byte array
+   * @param len length of serialized data
+   * @throws UnsupportedOperationException if T is immutable
+   */
+  public void readInto(T out, byte[] buf, int start, int len) {
+    readInto(out, ByteBuffer.wrap(buf, start, len));
+  }
+
+  /**
+   * Deserializes a value from a byte array into a mutable object.
+   *
+   * @param out object (will be updated with deserialized contents)
+   * @param buf byte array
+   * @throws UnsupportedOperationException if T is immutable
+   */
+  public void readInto(T out, byte[] buf) {
+    readInto(out, buf, 0, buf.length);
+  }
+
+  /**
+   * Deserializes a value from a ByteBuffer into a mutable object.
+   *
+   * @param out object (will be updated with deserialized contents)
+   * @param buf byte buffer
+   * @throws UnsupportedOperationException if T is immutable
+   */
+  public void readInto(T out, ByteBuffer buf) {
+    m_struct.unpackInto(out, buf);
+  }
+
+  /**
+   * Serializes a collection of values to a ByteBuffer. The returned ByteBuffer is a direct byte
+   * buffer with the position set to the end of the serialized data.
+   *
+   * @param values values
+   * @return byte buffer
+   */
+  public ByteBuffer writeArray(Collection<T> values) {
+    m_buf.position(0);
+    if ((values.size() * m_structSize) > m_buf.capacity()) {
+      m_buf =
+          ByteBuffer.allocateDirect(values.size() * m_structSize * 2)
+              .order(ByteOrder.LITTLE_ENDIAN);
+    }
+    for (T v : values) {
+      m_struct.pack(m_buf, v);
+    }
+    return m_buf;
+  }
+
+  /**
+   * Serializes an array of values to a ByteBuffer. The returned ByteBuffer is a direct byte buffer
+   * with the position set to the end of the serialized data.
+   *
+   * @param values values
+   * @return byte buffer
+   */
+  public ByteBuffer writeArray(T[] values) {
+    m_buf.position(0);
+    if ((values.length * m_structSize) > m_buf.capacity()) {
+      m_buf =
+          ByteBuffer.allocateDirect(values.length * m_structSize * 2)
+              .order(ByteOrder.LITTLE_ENDIAN);
+    }
+    for (T v : values) {
+      m_struct.pack(m_buf, v);
+    }
+    return m_buf;
+  }
+
+  /**
+   * Deserializes an array of values from a byte array, creating an array of new objects.
+   *
+   * @param buf byte array
+   * @param start starting location within byte array
+   * @param len length of serialized data
+   * @return new object array
+   */
+  public T[] readArray(byte[] buf, int start, int len) {
+    return readArray(ByteBuffer.wrap(buf, start, len));
+  }
+
+  /**
+   * Deserializes an array of values from a byte array, creating an array of new objects.
+   *
+   * @param buf byte array
+   * @return new object array
+   */
+  public T[] readArray(byte[] buf) {
+    return readArray(buf, 0, buf.length);
+  }
+
+  /**
+   * Deserializes an array of values from a ByteBuffer, creating an array of new objects.
+   *
+   * @param buf byte buffer
+   * @return new object array
+   */
+  public T[] readArray(ByteBuffer buf) {
+    buf.order(ByteOrder.LITTLE_ENDIAN);
+    int len = buf.limit() - buf.position();
+    if ((len % m_structSize) != 0) {
+      throw new RuntimeException("buffer size not a multiple of struct size");
+    }
+    int nelem = len / m_structSize;
+    @SuppressWarnings("unchecked")
+    T[] arr = (T[]) Array.newInstance(m_struct.getTypeClass(), nelem);
+    for (int i = 0; i < nelem; i++) {
+      arr[i] = m_struct.unpack(buf);
+    }
+    return arr;
+  }
+
+  private ByteBuffer m_buf;
+  private final Struct<T> m_struct;
+  private final int m_structSize;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/StructDescriptor.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructDescriptor.java
new file mode 100644
index 0000000..438db43
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructDescriptor.java
@@ -0,0 +1,156 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/** Raw struct dynamic struct descriptor. */
+public class StructDescriptor {
+  StructDescriptor(String name) {
+    m_name = name;
+  }
+
+  /**
+   * Gets the struct name.
+   *
+   * @return name
+   */
+  public String getName() {
+    return m_name;
+  }
+
+  /**
+   * Gets the struct schema.
+   *
+   * @return schema
+   */
+  public String getSchema() {
+    return m_schema;
+  }
+
+  /**
+   * Returns whether the struct is valid (e.g. the struct is fully defined and field offsets
+   * computed).
+   *
+   * @return true if valid
+   */
+  public boolean isValid() {
+    return m_valid;
+  }
+
+  /**
+   * Returns the struct size, in bytes. Not valid unless IsValid() is true.
+   *
+   * @return size in bytes
+   * @throws IllegalStateException if descriptor is invalid
+   */
+  public int getSize() {
+    if (!m_valid) {
+      throw new IllegalStateException("descriptor is invalid");
+    }
+    return m_size;
+  }
+
+  /**
+   * Gets a field descriptor by name. Note the field cannot be accessed until the struct is valid.
+   *
+   * @param name field name
+   * @return field descriptor, or nullptr if not found
+   */
+  public StructFieldDescriptor findFieldByName(String name) {
+    return m_fieldsByName.get(name);
+  }
+
+  /**
+   * Gets all field descriptors. Note fields cannot be accessed until the struct is valid.
+   *
+   * @return field descriptors
+   */
+  public List<StructFieldDescriptor> getFields() {
+    return m_fields;
+  }
+
+  boolean checkCircular(Stack<StructDescriptor> stack) {
+    stack.push(this);
+    for (StructDescriptor ref : m_references) {
+      if (stack.contains(ref)) {
+        return false;
+      }
+      if (!ref.checkCircular(stack)) {
+        return false;
+      }
+    }
+    stack.pop();
+    return true;
+  }
+
+  void calculateOffsets(Stack<StructDescriptor> stack) {
+    int offset = 0;
+    int shift = 0;
+    int prevBitfieldSize = 0;
+    for (StructFieldDescriptor field : m_fields) {
+      if (!field.isBitField()) {
+        shift = 0; // reset shift on non-bitfield element
+        offset += prevBitfieldSize; // finish bitfield if active
+        prevBitfieldSize = 0; // previous is now not bitfield
+        field.m_offset = offset;
+        StructDescriptor struct = field.getStruct();
+        if (struct != null) {
+          if (!struct.isValid()) {
+            m_valid = false;
+            return;
+          }
+          field.m_size = struct.m_size;
+        }
+        offset += field.m_size * field.m_arraySize;
+      } else {
+        int bitWidth = field.getBitWidth();
+        if (field.getType() == StructFieldType.kBool
+            && prevBitfieldSize != 0
+            && (shift + 1) <= (prevBitfieldSize * 8)) {
+          // bool takes on size of preceding bitfield type (if it fits)
+          field.m_size = prevBitfieldSize;
+        } else if (field.m_size != prevBitfieldSize || (shift + bitWidth) > (field.m_size * 8)) {
+          shift = 0;
+          offset += prevBitfieldSize;
+        }
+        prevBitfieldSize = field.m_size;
+        field.m_offset = offset;
+        field.m_bitShift = shift;
+        shift += bitWidth;
+      }
+    }
+
+    // update struct size
+    m_size = offset + prevBitfieldSize;
+    m_valid = true;
+
+    // now that we're valid, referring types may be too
+    stack.push(this);
+    for (StructDescriptor ref : m_references) {
+      if (stack.contains(ref)) {
+        throw new IllegalStateException(
+            "internal error (inconsistent data): circular struct reference between "
+                + m_name
+                + " and "
+                + ref.m_name);
+      }
+      ref.calculateOffsets(stack);
+    }
+    stack.pop();
+  }
+
+  private final String m_name;
+  String m_schema;
+  final List<StructDescriptor> m_references = new ArrayList<>();
+  final List<StructFieldDescriptor> m_fields = new ArrayList<>();
+  final Map<String, StructFieldDescriptor> m_fieldsByName = new HashMap<>();
+  int m_size;
+  boolean m_valid;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/StructDescriptorDatabase.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructDescriptorDatabase.java
new file mode 100644
index 0000000..be7343f
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructDescriptorDatabase.java
@@ -0,0 +1,148 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import edu.wpi.first.util.struct.parser.ParseException;
+import edu.wpi.first.util.struct.parser.ParsedDeclaration;
+import edu.wpi.first.util.struct.parser.ParsedSchema;
+import edu.wpi.first.util.struct.parser.Parser;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+/** Database of raw struct dynamic descriptors. */
+public class StructDescriptorDatabase {
+  /**
+   * Adds a structure schema to the database. If the struct references other structs that have not
+   * yet been added, it will not be valid until those structs are also added.
+   *
+   * @param name structure name
+   * @param schema structure schema
+   * @return Added struct dynamic descriptor
+   * @throws BadSchemaException if schema invalid
+   */
+  public StructDescriptor add(String name, String schema) throws BadSchemaException {
+    Parser parser = new Parser(schema);
+    ParsedSchema parsed;
+    try {
+      parsed = parser.parse();
+    } catch (ParseException e) {
+      throw new BadSchemaException("parse error", e);
+    }
+
+    // turn parsed schema into descriptors
+    StructDescriptor theStruct = m_structs.computeIfAbsent(name, k -> new StructDescriptor(k));
+    theStruct.m_schema = schema;
+    theStruct.m_fields.clear();
+    boolean isValid = true;
+    for (ParsedDeclaration decl : parsed.declarations) {
+      StructFieldType type = StructFieldType.fromString(decl.typeString);
+      int size = type.size;
+
+      // bitfield checks
+      if (decl.bitWidth != 0) {
+        // only integer or boolean types are allowed
+        if (!type.isInt && !type.isUint && type != StructFieldType.kBool) {
+          throw new BadSchemaException(
+              decl.name, "type " + decl.typeString + " cannot be bitfield");
+        }
+
+        // bit width cannot be larger than field size
+        if (decl.bitWidth > (size * 8)) {
+          throw new BadSchemaException(
+              decl.name, "bit width " + decl.bitWidth + " exceeds type size");
+        }
+
+        // bit width must be 1 for booleans
+        if (type == StructFieldType.kBool && decl.bitWidth != 1) {
+          throw new BadSchemaException(decl.name, "bit width must be 1 for bool type");
+        }
+
+        // cannot combine array and bitfield (shouldn't parse, but double-check)
+        if (decl.arraySize > 1) {
+          throw new BadSchemaException(decl.name, "cannot combine array and bitfield");
+        }
+      }
+
+      // struct handling
+      StructDescriptor structDesc = null;
+      if (type == StructFieldType.kStruct) {
+        // recursive definitions are not allowed
+        if (decl.typeString.equals(name)) {
+          throw new BadSchemaException(decl.name, "recursive struct reference");
+        }
+
+        // cross-reference struct, creating a placeholder if necessary
+        StructDescriptor aStruct =
+            m_structs.computeIfAbsent(decl.typeString, k -> new StructDescriptor(k));
+
+        // if the struct isn't valid, we can't be valid either
+        if (aStruct.isValid()) {
+          size = aStruct.getSize();
+        } else {
+          isValid = false;
+        }
+
+        // add to cross-references for when the struct does become valid
+        aStruct.m_references.add(theStruct);
+        structDesc = aStruct;
+      }
+
+      // create field
+      StructFieldDescriptor fieldDesc =
+          new StructFieldDescriptor(
+              theStruct,
+              decl.name,
+              type,
+              size,
+              decl.arraySize,
+              decl.bitWidth,
+              decl.enumValues,
+              structDesc);
+      if (theStruct.m_fieldsByName.put(decl.name, fieldDesc) != null) {
+        throw new BadSchemaException(decl.name, "duplicate field name");
+      }
+
+      theStruct.m_fields.add(fieldDesc);
+    }
+
+    theStruct.m_valid = isValid;
+    Stack<StructDescriptor> stack = new Stack<>();
+    if (isValid) {
+      // we have all the info needed, so calculate field offset & shift
+      theStruct.calculateOffsets(stack);
+    } else {
+      // check for circular reference
+      if (!theStruct.checkCircular(stack)) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("circular struct reference: ");
+        boolean first = true;
+        for (StructDescriptor elem : stack) {
+          if (!first) {
+            builder.append(" <- ");
+          } else {
+            first = false;
+          }
+          builder.append(elem.getName());
+        }
+        throw new BadSchemaException(builder.toString());
+      }
+    }
+
+    return theStruct;
+  }
+
+  /**
+   * Finds a structure in the database by name.
+   *
+   * @param name structure name
+   * @return struct descriptor, or null if not found
+   */
+  public StructDescriptor find(String name) {
+    return m_structs.get(name);
+  }
+
+  private final Map<String, StructDescriptor> m_structs = new HashMap<>();
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/StructFieldDescriptor.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructFieldDescriptor.java
new file mode 100644
index 0000000..25a69a5
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructFieldDescriptor.java
@@ -0,0 +1,241 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import java.util.Map;
+
+/** Raw struct dynamic field descriptor. */
+public class StructFieldDescriptor {
+  private static int toBitWidth(int size, int bitWidth) {
+    if (bitWidth == 0) {
+      return size * 8;
+    } else {
+      return bitWidth;
+    }
+  }
+
+  private static long toBitMask(int size, int bitWidth) {
+    if (size == 0) {
+      return 0;
+    } else {
+      return -1L >>> (64 - toBitWidth(size, bitWidth));
+    }
+  }
+
+  // does not fill in offset, shift
+  StructFieldDescriptor(
+      StructDescriptor parent,
+      String name,
+      StructFieldType type,
+      int size,
+      int arraySize,
+      int bitWidth,
+      Map<String, Long> enumValues,
+      StructDescriptor structDesc) {
+    m_parent = parent;
+    m_name = name;
+    m_size = size;
+    m_arraySize = arraySize;
+    m_enum = enumValues;
+    m_struct = structDesc;
+    m_bitMask = toBitMask(size, bitWidth);
+    m_type = type;
+    m_bitWidth = toBitWidth(size, bitWidth);
+  }
+
+  /**
+   * Gets the dynamic struct this field is contained in.
+   *
+   * @return struct descriptor
+   */
+  public StructDescriptor getParent() {
+    return m_parent;
+  }
+
+  /**
+   * Gets the field name.
+   *
+   * @return field name
+   */
+  public String getName() {
+    return m_name;
+  }
+
+  /**
+   * Gets the field type.
+   *
+   * @return field type
+   */
+  public StructFieldType getType() {
+    return m_type;
+  }
+
+  /**
+   * Returns whether the field type is a signed integer.
+   *
+   * @return true if signed integer, false otherwise
+   */
+  public boolean isInt() {
+    return m_type.isInt;
+  }
+
+  /**
+   * Returns whether the field type is an unsigned integer.
+   *
+   * @return true if unsigned integer, false otherwise
+   */
+  public boolean isUint() {
+    return m_type.isUint;
+  }
+
+  /**
+   * Gets the underlying storage size of the field, in bytes.
+   *
+   * @return number of bytes
+   */
+  public int getSize() {
+    return m_size;
+  }
+
+  /**
+   * Gets the storage offset of the field, in bytes.
+   *
+   * @return number of bytes from the start of the struct
+   */
+  public int getOffset() {
+    return m_offset;
+  }
+
+  /**
+   * Gets the bit width of the field, in bits.
+   *
+   * @return number of bits
+   */
+  public int getBitWidth() {
+    return m_bitWidth == 0 ? m_size * 8 : m_bitWidth;
+  }
+
+  /**
+   * Gets the bit mask for the field. The mask is always the least significant bits (it is not
+   * shifted).
+   *
+   * @return bit mask
+   */
+  public long getBitMask() {
+    return m_bitMask;
+  }
+
+  /**
+   * Gets the bit shift for the field (LSB=0).
+   *
+   * @return number of bits
+   */
+  public int getBitShift() {
+    return m_bitShift;
+  }
+
+  /**
+   * Returns whether the field is an array.
+   *
+   * @return true if array
+   */
+  public boolean isArray() {
+    return m_arraySize > 1;
+  }
+
+  /**
+   * Gets the array size. Returns 1 if non-array.
+   *
+   * @return number of elements
+   */
+  public int getArraySize() {
+    return m_arraySize;
+  }
+
+  /**
+   * Returns whether the field has enumerated values.
+   *
+   * @return true if there are enumerated values
+   */
+  public boolean hasEnum() {
+    return m_enum != null;
+  }
+
+  /**
+   * Gets the enumerated values.
+   *
+   * @return set of enumerated values
+   */
+  public Map<String, Long> getEnumValues() {
+    return m_enum;
+  }
+
+  /**
+   * Gets the struct descriptor for a struct data type.
+   *
+   * @return struct descriptor; returns null for non-struct
+   */
+  public StructDescriptor getStruct() {
+    return m_struct;
+  }
+
+  /**
+   * Gets the minimum unsigned integer value that can be stored in this field.
+   *
+   * @return minimum value
+   */
+  public long getUintMin() {
+    return 0;
+  }
+
+  /**
+   * Gets the maximum unsigned integer value that can be stored in this field. Note this is not the
+   * actual maximum for uint64 (due to Java lacking support for 64-bit unsigned integers).
+   *
+   * @return maximum value
+   */
+  public long getUintMax() {
+    return m_bitMask;
+  }
+
+  /**
+   * Gets the minimum signed integer value that can be stored in this field.
+   *
+   * @return minimum value
+   */
+  public long getIntMin() {
+    return (-(m_bitMask >> 1)) - 1;
+  }
+
+  /**
+   * Gets the maximum signed integer value that can be stored in this field.
+   *
+   * @return maximum value
+   */
+  public long getIntMax() {
+    return m_bitMask >> 1;
+  }
+
+  /**
+   * Returns whether the field is a bitfield.
+   *
+   * @return true if bitfield
+   */
+  public boolean isBitField() {
+    return m_bitShift != 0 || m_bitWidth != (m_size * 8);
+  }
+
+  private final StructDescriptor m_parent;
+  private final String m_name;
+  int m_size;
+  int m_offset;
+  final int m_arraySize; // 1 for non-arrays
+  private final Map<String, Long> m_enum;
+  private final StructDescriptor m_struct; // null for non-structs
+  private final long m_bitMask;
+  private final StructFieldType m_type;
+  private final int m_bitWidth;
+  int m_bitShift;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/StructFieldType.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructFieldType.java
new file mode 100644
index 0000000..28d5d8e
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/StructFieldType.java
@@ -0,0 +1,67 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+/** Known data types for raw struct dynamic fields (see StructFieldDescriptor). */
+public enum StructFieldType {
+  kBool("bool", false, false, 1),
+  kChar("char", false, false, 1),
+  kInt8("int8", true, false, 1),
+  kInt16("int16", true, false, 2),
+  kInt32("int32", true, false, 4),
+  kInt64("int64", true, false, 8),
+  kUint8("uint8", false, true, 1),
+  kUint16("uint16", false, true, 2),
+  kUint32("uint32", false, true, 4),
+  kUint64("uint64", false, true, 8),
+  kFloat("float", false, false, 4),
+  kDouble("double", false, false, 8),
+  kStruct("struct", false, false, 0);
+
+  @SuppressWarnings("MemberName")
+  public final String name;
+
+  @SuppressWarnings("MemberName")
+  public final boolean isInt;
+
+  @SuppressWarnings("MemberName")
+  public final boolean isUint;
+
+  @SuppressWarnings("MemberName")
+  public final int size;
+
+  StructFieldType(String name, boolean isInt, boolean isUint, int size) {
+    this.name = name;
+    this.isInt = isInt;
+    this.isUint = isUint;
+    this.size = size;
+  }
+
+  @Override
+  public String toString() {
+    return name;
+  }
+
+  /**
+   * Get field type from string.
+   *
+   * @param str string
+   * @return field type
+   */
+  public static StructFieldType fromString(String str) {
+    for (StructFieldType type : StructFieldType.values()) {
+      if (type.name.equals(str)) {
+        return type;
+      }
+    }
+    if ("float32".equals(str)) {
+      return kFloat;
+    } else if ("float64".equals(str)) {
+      return kDouble;
+    } else {
+      return kStruct;
+    }
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/Lexer.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/Lexer.java
new file mode 100644
index 0000000..6e3cd5d
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/Lexer.java
@@ -0,0 +1,132 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+/** Raw struct schema lexer. */
+public class Lexer {
+  /**
+   * Construct a raw struct schema lexer.
+   *
+   * @param in schema
+   */
+  public Lexer(String in) {
+    m_in = in;
+  }
+
+  /**
+   * Gets the next token.
+   *
+   * @return Token kind; the token text can be retrieved using getTokenText()
+   */
+  public TokenKind scan() {
+    // skip whitespace
+    do {
+      get();
+    } while (m_current == ' ' || m_current == '\t' || m_current == '\n' || m_current == '\r');
+    m_tokenStart = m_pos - 1;
+
+    switch (m_current) {
+      case '[':
+        return TokenKind.kLeftBracket;
+      case ']':
+        return TokenKind.kRightBracket;
+      case '{':
+        return TokenKind.kLeftBrace;
+      case '}':
+        return TokenKind.kRightBrace;
+      case ':':
+        return TokenKind.kColon;
+      case ';':
+        return TokenKind.kSemicolon;
+      case ',':
+        return TokenKind.kComma;
+      case '=':
+        return TokenKind.kEquals;
+      case '-':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        return scanInteger();
+      case '\0':
+        return TokenKind.kEndOfInput;
+      default:
+        if (Character.isLetter(m_current) || m_current == '_') {
+          return scanIdentifier();
+        }
+        return TokenKind.kUnknown;
+    }
+  }
+
+  /**
+   * Gets the text of the last lexed token.
+   *
+   * @return token text
+   */
+  public String getTokenText() {
+    if (m_tokenStart >= m_in.length()) {
+      return "";
+    }
+    return m_in.substring(m_tokenStart, m_pos);
+  }
+
+  /**
+   * Gets the starting position of the last lexed token.
+   *
+   * @return position (0 = first character)
+   */
+  public int getPosition() {
+    return m_tokenStart;
+  }
+
+  private TokenKind scanInteger() {
+    do {
+      get();
+    } while (Character.isDigit(m_current));
+    unget();
+    return TokenKind.kInteger;
+  }
+
+  private TokenKind scanIdentifier() {
+    do {
+      get();
+    } while (Character.isLetterOrDigit(m_current) || m_current == '_');
+    unget();
+    return TokenKind.kIdentifier;
+  }
+
+  private void get() {
+    if (m_pos < m_in.length()) {
+      m_current = m_in.charAt(m_pos);
+    } else {
+      m_current = '\0';
+    }
+    ++m_pos;
+  }
+
+  private void unget() {
+    if (m_pos > 0) {
+      m_pos--;
+      if (m_pos < m_in.length()) {
+        m_current = m_in.charAt(m_pos);
+      } else {
+        m_current = '\0';
+      }
+    } else {
+      m_current = '\0';
+    }
+  }
+
+  final String m_in;
+  char m_current;
+  int m_tokenStart;
+  int m_pos;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParseException.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParseException.java
new file mode 100644
index 0000000..9fa843c
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParseException.java
@@ -0,0 +1,33 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+public class ParseException extends Exception {
+  private final int m_pos;
+
+  public ParseException(int pos, String s) {
+    super(s);
+    m_pos = pos;
+  }
+
+  public ParseException(int pos, String message, Throwable cause) {
+    super(message, cause);
+    m_pos = pos;
+  }
+
+  public ParseException(int pos, Throwable cause) {
+    super(cause);
+    m_pos = pos;
+  }
+
+  public int getPosition() {
+    return m_pos;
+  }
+
+  @Override
+  public String toString() {
+    return m_pos + ": " + getMessage();
+  }
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParsedDeclaration.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParsedDeclaration.java
new file mode 100644
index 0000000..8184ae5
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParsedDeclaration.java
@@ -0,0 +1,25 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+import java.util.Map;
+
+/** Raw struct schema declaration. */
+public class ParsedDeclaration {
+  @SuppressWarnings("MemberName")
+  public String typeString;
+
+  @SuppressWarnings("MemberName")
+  public String name;
+
+  @SuppressWarnings("MemberName")
+  public Map<String, Long> enumValues;
+
+  @SuppressWarnings("MemberName")
+  public int arraySize = 1;
+
+  @SuppressWarnings("MemberName")
+  public int bitWidth;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParsedSchema.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParsedSchema.java
new file mode 100644
index 0000000..2ca1753
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/ParsedSchema.java
@@ -0,0 +1,14 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Raw struct schema. */
+public class ParsedSchema {
+  @SuppressWarnings("MemberName")
+  public List<ParsedDeclaration> declarations = new ArrayList<>();
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/Parser.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/Parser.java
new file mode 100644
index 0000000..7aba1ad
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/Parser.java
@@ -0,0 +1,157 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** Raw struct schema parser. */
+public class Parser {
+  /**
+   * Construct a raw struct schema parser.
+   *
+   * @param in schema
+   */
+  public Parser(String in) {
+    m_lexer = new Lexer(in);
+  }
+
+  /**
+   * Parses the schema.
+   *
+   * @return parsed schema object
+   * @throws ParseException on parse error
+   */
+  public ParsedSchema parse() throws ParseException {
+    ParsedSchema schema = new ParsedSchema();
+    do {
+      getNextToken();
+      if (m_token == TokenKind.kSemicolon) {
+        continue;
+      }
+      if (m_token == TokenKind.kEndOfInput) {
+        break;
+      }
+      schema.declarations.add(parseDeclaration());
+    } while (m_token != TokenKind.kEndOfInput);
+    return schema;
+  }
+
+  private ParsedDeclaration parseDeclaration() throws ParseException {
+    ParsedDeclaration decl = new ParsedDeclaration();
+
+    // optional enum specification
+    if (m_token == TokenKind.kIdentifier && "enum".equals(m_lexer.getTokenText())) {
+      getNextToken();
+      expect(TokenKind.kLeftBrace);
+      decl.enumValues = parseEnum();
+      getNextToken();
+    } else if (m_token == TokenKind.kLeftBrace) {
+      decl.enumValues = parseEnum();
+      getNextToken();
+    }
+
+    // type name
+    expect(TokenKind.kIdentifier);
+    decl.typeString = m_lexer.getTokenText();
+    getNextToken();
+
+    // identifier name
+    expect(TokenKind.kIdentifier);
+    decl.name = m_lexer.getTokenText();
+    getNextToken();
+
+    // array or bit field
+    if (m_token == TokenKind.kLeftBracket) {
+      getNextToken();
+      expect(TokenKind.kInteger);
+      String valueStr = m_lexer.getTokenText();
+      int value;
+      try {
+        value = Integer.parseInt(valueStr);
+      } catch (NumberFormatException e) {
+        value = 0;
+      }
+      if (value > 0) {
+        decl.arraySize = value;
+      } else {
+        throw new ParseException(
+            m_lexer.m_pos, "array size '" + valueStr + "' is not a positive integer");
+      }
+      getNextToken();
+      expect(TokenKind.kRightBracket);
+      getNextToken();
+    } else if (m_token == TokenKind.kColon) {
+      getNextToken();
+      expect(TokenKind.kInteger);
+      String valueStr = m_lexer.getTokenText();
+      int value;
+      try {
+        value = Integer.parseInt(valueStr);
+      } catch (NumberFormatException e) {
+        value = 0;
+      }
+      if (value > 0) {
+        decl.bitWidth = value;
+      } else {
+        throw new ParseException(
+            m_lexer.m_pos, "bitfield width '" + valueStr + "' is not a positive integer");
+      }
+      getNextToken();
+    }
+
+    // declaration must end with EOF or semicolon
+    if (m_token != TokenKind.kEndOfInput) {
+      expect(TokenKind.kSemicolon);
+    }
+
+    return decl;
+  }
+
+  private Map<String, Long> parseEnum() throws ParseException {
+    Map<String, Long> map = new HashMap<>();
+
+    // we start with current = '{'
+    getNextToken();
+    while (m_token != TokenKind.kRightBrace) {
+      expect(TokenKind.kIdentifier);
+      final String name = m_lexer.getTokenText();
+      getNextToken();
+      expect(TokenKind.kEquals);
+      getNextToken();
+      expect(TokenKind.kInteger);
+      String valueStr = m_lexer.getTokenText();
+      long value;
+      try {
+        value = Long.parseLong(valueStr);
+      } catch (NumberFormatException e) {
+        throw new ParseException(m_lexer.m_pos, "could not parse enum value '" + valueStr + "'");
+      }
+      map.put(name, value);
+      getNextToken();
+      if (m_token == TokenKind.kRightBrace) {
+        break;
+      }
+      expect(TokenKind.kComma);
+      getNextToken();
+    }
+    return map;
+  }
+
+  private TokenKind getNextToken() {
+    m_token = m_lexer.scan();
+    return m_token;
+  }
+
+  private void expect(TokenKind kind) throws ParseException {
+    if (m_token != kind) {
+      throw new ParseException(
+          m_lexer.m_pos, "expected " + kind + ", got '" + m_lexer.getTokenText() + "'");
+    }
+  }
+
+  final Lexer m_lexer;
+  TokenKind m_token;
+}
diff --git a/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/TokenKind.java b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/TokenKind.java
new file mode 100644
index 0000000..85afa4a
--- /dev/null
+++ b/wpiutil/src/main/java/edu/wpi/first/util/struct/parser/TokenKind.java
@@ -0,0 +1,32 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+/** A lexed raw struct schema token. */
+public enum TokenKind {
+  kUnknown("unknown"),
+  kInteger("integer"),
+  kIdentifier("identifier"),
+  kLeftBracket("'['"),
+  kRightBracket("']'"),
+  kLeftBrace("'{'"),
+  kRightBrace("'}'"),
+  kColon("':'"),
+  kSemicolon("';'"),
+  kComma("','"),
+  kEquals("'='"),
+  kEndOfInput("<EOF>");
+
+  private final String m_name;
+
+  TokenKind(String name) {
+    this.m_name = name;
+  }
+
+  @Override
+  public String toString() {
+    return m_name;
+  }
+}
diff --git a/wpiutil/src/main/native/cpp/DataLog.cpp b/wpiutil/src/main/native/cpp/DataLog.cpp
index 7009628..d05a49e 100644
--- a/wpiutil/src/main/native/cpp/DataLog.cpp
+++ b/wpiutil/src/main/native/cpp/DataLog.cpp
@@ -26,17 +26,37 @@
 #include <random>
 #include <vector>
 
-#include "fmt/format.h"
+#include <fmt/format.h>
+
 #include "wpi/Endian.h"
 #include "wpi/Logger.h"
 #include "wpi/MathExtras.h"
+#include "wpi/SmallString.h"
 #include "wpi/fs.h"
 #include "wpi/timestamp.h"
 
 using namespace wpi::log;
 
 static constexpr size_t kBlockSize = 16 * 1024;
+static constexpr size_t kMaxBufferCount = 1024 * 1024 / kBlockSize;
+static constexpr size_t kMaxFreeCount = 256 * 1024 / kBlockSize;
 static constexpr size_t kRecordMaxHeaderSize = 17;
+static constexpr uintmax_t kMinFreeSpace = 5 * 1024 * 1024;
+
+static std::string FormatBytesSize(uintmax_t value) {
+  static constexpr uintmax_t kKiB = 1024;
+  static constexpr uintmax_t kMiB = kKiB * 1024;
+  static constexpr uintmax_t kGiB = kMiB * 1024;
+  if (value >= kGiB) {
+    return fmt::format("{:.1f} GiB", static_cast<double>(value) / kGiB);
+  } else if (value >= kMiB) {
+    return fmt::format("{:.1f} MiB", static_cast<double>(value) / kMiB);
+  } else if (value >= kKiB) {
+    return fmt::format("{:.1f} KiB", static_cast<double>(value) / kKiB);
+  } else {
+    return fmt::format("{} B", value);
+  }
+}
 
 template <typename T>
 static unsigned int WriteVarInt(uint8_t* buf, T val) {
@@ -159,7 +179,7 @@
 DataLog::~DataLog() {
   {
     std::scoped_lock lock{m_mutex};
-    m_active = false;
+    m_state = kShutdown;
     m_doFlush = true;
   }
   m_cond.notify_all();
@@ -184,12 +204,56 @@
 
 void DataLog::Pause() {
   std::scoped_lock lock{m_mutex};
-  m_paused = true;
+  m_state = kPaused;
 }
 
 void DataLog::Resume() {
   std::scoped_lock lock{m_mutex};
-  m_paused = false;
+  if (m_state == kPaused) {
+    m_state = kActive;
+  } else if (m_state == kStopped) {
+    m_state = kStart;
+  }
+}
+
+void DataLog::Stop() {
+  {
+    std::scoped_lock lock{m_mutex};
+    m_state = kStopped;
+    m_newFilename.clear();
+  }
+  m_cond.notify_all();
+}
+
+bool DataLog::HasSchema(std::string_view name) const {
+  std::scoped_lock lock{m_mutex};
+  wpi::SmallString<128> fullName{"/.schema/"};
+  fullName += name;
+  auto it = m_entries.find(fullName);
+  return it != m_entries.end();
+}
+
+void DataLog::AddSchema(std::string_view name, std::string_view type,
+                        std::span<const uint8_t> schema, int64_t timestamp) {
+  std::scoped_lock lock{m_mutex};
+  wpi::SmallString<128> fullName{"/.schema/"};
+  fullName += name;
+  auto& entryInfo = m_entries[fullName];
+  if (entryInfo.id != 0) {
+    return;  // don't add duplicates
+  }
+  entryInfo.schemaData.assign(schema.begin(), schema.end());
+  int entry = StartImpl(fullName, type, {}, timestamp);
+
+  // inline AppendRaw() without releasing lock
+  if (entry <= 0) {
+    [[unlikely]] return;  // should never happen, but check anyway
+  }
+  if (m_state != kActive && m_state != kPaused) {
+    [[unlikely]] return;
+  }
+  StartRecord(entry, timestamp, schema.size(), 0);
+  AppendImpl(schema);
 }
 
 static void WriteToFile(fs::file_t f, std::span<const uint8_t> data,
@@ -236,93 +300,201 @@
   return filename;
 }
 
-void DataLog::WriterThreadMain(std::string_view dir) {
-  std::chrono::duration<double> periodTime{m_period};
+struct DataLog::WriterThreadState {
+  explicit WriterThreadState(std::string_view dir) : dirPath{dir} {}
+  WriterThreadState(const WriterThreadState&) = delete;
+  WriterThreadState& operator=(const WriterThreadState&) = delete;
+  ~WriterThreadState() { Close(); }
 
-  std::error_code ec;
-  fs::path dirPath{dir};
-  std::string filename;
-
-  {
-    std::scoped_lock lock{m_mutex};
-    filename = std::move(m_newFilename);
-    m_newFilename.clear();
-  }
-
-  if (filename.empty()) {
-    filename = MakeRandomFilename();
-  }
-
-  // try preferred filename, or randomize it a few times, before giving up
-  fs::file_t f;
-  for (int i = 0; i < 5; ++i) {
-    // open file for append
-#ifdef _WIN32
-    // WIN32 doesn't allow combination of CreateNew and Append
-    f = fs::OpenFileForWrite(dirPath / filename, ec, fs::CD_CreateNew,
-                             fs::OF_None);
-#else
-    f = fs::OpenFileForWrite(dirPath / filename, ec, fs::CD_CreateNew,
-                             fs::OF_Append);
-#endif
-    if (ec) {
-      WPI_ERROR(m_msglog, "Could not open log file '{}': {}",
-                (dirPath / filename).string(), ec.message());
-      // try again with random filename
-      filename = MakeRandomFilename();
-    } else {
-      break;
+  void Close() {
+    if (f != fs::kInvalidFile) {
+      fs::CloseFile(f);
+      f = fs::kInvalidFile;
     }
   }
 
-  if (f == fs::kInvalidFile) {
-    WPI_ERROR(m_msglog, "Could not open log file, no log being saved");
+  void SetFilename(std::string_view fn) {
+    baseFilename = fn;
+    filename = fn;
+    path = dirPath / filename;
+    segmentCount = 1;
+  }
+
+  void IncrementFilename() {
+    fs::path basePath{baseFilename};
+    filename = fmt::format("{}.{}{}", basePath.stem().string(), ++segmentCount,
+                           basePath.extension().string());
+    path = dirPath / filename;
+  }
+
+  fs::path dirPath;
+  std::string baseFilename;
+  std::string filename;
+  fs::path path;
+  fs::file_t f = fs::kInvalidFile;
+  uintmax_t freeSpace = UINTMAX_MAX;
+  int segmentCount = 1;
+};
+
+void DataLog::StartLogFile(WriterThreadState& state) {
+  std::error_code ec;
+
+  if (state.filename.empty()) {
+    state.SetFilename(MakeRandomFilename());
+  }
+
+  // get free space
+  auto freeSpaceInfo = fs::space(state.dirPath, ec);
+  if (!ec) {
+    state.freeSpace = freeSpaceInfo.available;
   } else {
-    WPI_INFO(m_msglog, "Logging to '{}'", (dirPath / filename).string());
+    state.freeSpace = UINTMAX_MAX;
+  }
+  if (state.freeSpace < kMinFreeSpace) {
+    WPI_ERROR(m_msglog,
+              "Insufficient free space ({} available), no log being saved",
+              FormatBytesSize(state.freeSpace));
+  } else {
+    // try preferred filename, or randomize it a few times, before giving up
+    for (int i = 0; i < 5; ++i) {
+      // open file for append
+#ifdef _WIN32
+      // WIN32 doesn't allow combination of CreateNew and Append
+      state.f =
+          fs::OpenFileForWrite(state.path, ec, fs::CD_CreateNew, fs::OF_None);
+#else
+      state.f =
+          fs::OpenFileForWrite(state.path, ec, fs::CD_CreateNew, fs::OF_Append);
+#endif
+      if (ec) {
+        WPI_ERROR(m_msglog, "Could not open log file '{}': {}",
+                  state.path.string(), ec.message());
+        // try again with random filename
+        state.SetFilename(MakeRandomFilename());
+      } else {
+        break;
+      }
+    }
+
+    if (state.f == fs::kInvalidFile) {
+      WPI_ERROR(m_msglog, "Could not open log file, no log being saved");
+    } else {
+      WPI_INFO(m_msglog, "Logging to '{}' ({} free space)", state.path.string(),
+               FormatBytesSize(state.freeSpace));
+    }
   }
 
   // write header (version 1.0)
-  if (f != fs::kInvalidFile) {
+  if (state.f != fs::kInvalidFile) {
     const uint8_t header[] = {'W', 'P', 'I', 'L', 'O', 'G', 0, 1};
-    WriteToFile(f, header, filename, m_msglog);
+    WriteToFile(state.f, header, state.filename, m_msglog);
     uint8_t extraLen[4];
     support::endian::write32le(extraLen, m_extraHeader.size());
-    WriteToFile(f, extraLen, filename, m_msglog);
+    WriteToFile(state.f, extraLen, state.filename, m_msglog);
     if (m_extraHeader.size() > 0) {
-      WriteToFile(f,
+      WriteToFile(state.f,
                   {reinterpret_cast<const uint8_t*>(m_extraHeader.data()),
                    m_extraHeader.size()},
-                  filename, m_msglog);
+                  state.filename, m_msglog);
     }
   }
+}
 
+void DataLog::WriterThreadMain(std::string_view dir) {
+  std::chrono::duration<double> periodTime{m_period};
+
+  WriterThreadState state{dir};
+  {
+    std::scoped_lock lock{m_mutex};
+    state.SetFilename(m_newFilename);
+    m_newFilename.clear();
+  }
+  StartLogFile(state);
+
+  std::error_code ec;
   std::vector<Buffer> toWrite;
+  int freeSpaceCount = 0;
+  int checkExistCount = 0;
+  bool blocked = false;
+  uintmax_t written = 0;
 
   std::unique_lock lock{m_mutex};
-  while (m_active) {
+  while (m_state != kShutdown) {
     bool doFlush = false;
     auto timeoutTime = std::chrono::steady_clock::now() + periodTime;
     if (m_cond.wait_until(lock, timeoutTime) == std::cv_status::timeout) {
       doFlush = true;
     }
 
-    if (!m_newFilename.empty()) {
+    if (m_state == kStopped) {
+      state.Close();
+      continue;
+    }
+
+    bool doStart = false;
+
+    // if file was deleted, recreate it with the same name
+    if (++checkExistCount >= 10) {
+      checkExistCount = 0;
+      lock.unlock();
+      bool exists = fs::exists(state.path, ec);
+      lock.lock();
+      if (!ec && !exists) {
+        state.Close();
+        state.IncrementFilename();
+        WPI_INFO(m_msglog, "Log file deleted, recreating as fresh log '{}'",
+                 state.filename);
+        doStart = true;
+      }
+    }
+
+    // start new file if file exceeds 1.8 GB
+    if (written > 1800000000ull) {
+      state.Close();
+      state.IncrementFilename();
+      WPI_INFO(m_msglog, "Log file reached 1.8 GB, starting new file '{}'",
+               state.filename);
+      doStart = true;
+    }
+
+    if (m_state == kStart || doStart) {
+      lock.unlock();
+      StartLogFile(state);
+      lock.lock();
+      if (state.f != fs::kInvalidFile) {
+        // Emit start and schema data records
+        for (auto&& entryInfo : m_entries) {
+          AppendStartRecord(entryInfo.second.id, entryInfo.first(),
+                            entryInfo.second.type,
+                            m_entryIds[entryInfo.second.id].metadata, 0);
+          if (!entryInfo.second.schemaData.empty()) {
+            StartRecord(entryInfo.second.id, 0,
+                        entryInfo.second.schemaData.size(), 0);
+            AppendImpl(entryInfo.second.schemaData);
+          }
+        }
+      }
+      m_state = kActive;
+      written = 0;
+    }
+
+    if (!m_newFilename.empty() && state.f != fs::kInvalidFile) {
       auto newFilename = std::move(m_newFilename);
       m_newFilename.clear();
-      lock.unlock();
       // rename
-      if (filename != newFilename) {
-        fs::rename(dirPath / filename, dirPath / newFilename, ec);
+      if (state.filename != newFilename) {
+        lock.unlock();
+        fs::rename(state.path, state.dirPath / newFilename, ec);
+        lock.lock();
       }
       if (ec) {
         WPI_ERROR(m_msglog, "Could not rename log file from '{}' to '{}': {}",
-                  filename, newFilename, ec.message());
+                  state.filename, newFilename, ec.message());
       } else {
-        WPI_INFO(m_msglog, "Renamed log file from '{}' to '{}'", filename,
+        WPI_INFO(m_msglog, "Renamed log file from '{}' to '{}'", state.filename,
                  newFilename);
       }
-      filename = std::move(newFilename);
-      lock.lock();
+      state.SetFilename(newFilename);
     }
 
     if (doFlush || m_doFlush) {
@@ -334,34 +506,58 @@
       // swap outgoing with empty vector
       toWrite.swap(m_outgoing);
 
-      if (f != fs::kInvalidFile) {
+      if (state.f != fs::kInvalidFile && !blocked) {
         lock.unlock();
+
+        // update free space every 10 flushes (in case other things are writing)
+        if (++freeSpaceCount >= 10) {
+          freeSpaceCount = 0;
+          auto freeSpaceInfo = fs::space(state.dirPath, ec);
+          if (!ec) {
+            state.freeSpace = freeSpaceInfo.available;
+          } else {
+            state.freeSpace = UINTMAX_MAX;
+          }
+        }
+
         // write buffers to file
         for (auto&& buf : toWrite) {
-          WriteToFile(f, buf.GetData(), filename, m_msglog);
+          // stop writing when we go below the minimum free space
+          state.freeSpace -= buf.GetData().size();
+          written += buf.GetData().size();
+          if (state.freeSpace < kMinFreeSpace) {
+            [[unlikely]] WPI_ERROR(
+                m_msglog,
+                "Stopped logging due to low free space ({} available)",
+                FormatBytesSize(state.freeSpace));
+            blocked = true;
+            break;
+          }
+          WriteToFile(state.f, buf.GetData(), state.filename, m_msglog);
         }
 
         // sync to storage
 #if defined(__linux__)
-        ::fdatasync(f);
+        ::fdatasync(state.f);
 #elif defined(__APPLE__)
-        ::fsync(f);
+        ::fsync(state.f);
 #endif
         lock.lock();
+        if (blocked) {
+          [[unlikely]] m_state = kPaused;
+        }
       }
 
       // release buffers back to free list
       for (auto&& buf : toWrite) {
         buf.Clear();
-        m_free.emplace_back(std::move(buf));
+        if (m_free.size() < kMaxFreeCount) {
+          [[likely]] m_free.emplace_back(std::move(buf));
+        }
       }
       toWrite.resize(0);
     }
   }
-
-  if (f != fs::kInvalidFile) {
-    fs::CloseFile(f);
-  }
 }
 
 void DataLog::WriterThreadMain(
@@ -384,7 +580,7 @@
   std::vector<Buffer> toWrite;
 
   std::unique_lock lock{m_mutex};
-  while (m_active) {
+  while (m_state != kShutdown) {
     bool doFlush = false;
     auto timeoutTime = std::chrono::steady_clock::now() + periodTime;
     if (m_cond.wait_until(lock, timeoutTime) == std::cv_status::timeout) {
@@ -412,7 +608,9 @@
       // release buffers back to free list
       for (auto&& buf : toWrite) {
         buf.Clear();
-        m_free.emplace_back(std::move(buf));
+        if (m_free.size() < kMaxFreeCount) {
+          [[likely]] m_free.emplace_back(std::move(buf));
+        }
       }
       toWrite.resize(0);
     }
@@ -429,13 +627,18 @@
 int DataLog::Start(std::string_view name, std::string_view type,
                    std::string_view metadata, int64_t timestamp) {
   std::scoped_lock lock{m_mutex};
+  return StartImpl(name, type, metadata, timestamp);
+}
+
+int DataLog::StartImpl(std::string_view name, std::string_view type,
+                       std::string_view metadata, int64_t timestamp) {
   auto& entryInfo = m_entries[name];
   if (entryInfo.id == 0) {
     entryInfo.id = ++m_lastId;
   }
-  auto& savedCount = m_entryCounts[entryInfo.id];
-  ++savedCount;
-  if (savedCount > 1) {
+  auto& entryInfo2 = m_entryIds[entryInfo.id];
+  ++entryInfo2.count;
+  if (entryInfo2.count > 1) {
     if (entryInfo.type != type) {
       WPI_ERROR(m_msglog,
                 "type mismatch for '{}': was '{}', requested '{}'; ignoring",
@@ -445,15 +648,26 @@
     return entryInfo.id;
   }
   entryInfo.type = type;
+  entryInfo2.metadata = metadata;
+
+  if (m_state != kActive && m_state != kPaused) {
+    [[unlikely]] return entryInfo.id;
+  }
+
+  AppendStartRecord(entryInfo.id, name, type, metadata, timestamp);
+  return entryInfo.id;
+}
+
+void DataLog::AppendStartRecord(int id, std::string_view name,
+                                std::string_view type,
+                                std::string_view metadata, int64_t timestamp) {
   size_t strsize = name.size() + type.size() + metadata.size();
   uint8_t* buf = StartRecord(0, timestamp, 5 + 12 + strsize, 5);
   *buf++ = impl::kControlStart;
-  wpi::support::endian::write32le(buf, entryInfo.id);
+  wpi::support::endian::write32le(buf, id);
   AppendStringImpl(name);
   AppendStringImpl(type);
   AppendStringImpl(metadata);
-
-  return entryInfo.id;
 }
 
 void DataLog::Finish(int entry, int64_t timestamp) {
@@ -461,15 +675,18 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  auto& savedCount = m_entryCounts[entry];
-  if (savedCount == 0) {
+  auto& entryInfo2 = m_entryIds[entry];
+  if (entryInfo2.count == 0) {
     return;
   }
-  --savedCount;
-  if (savedCount != 0) {
+  --entryInfo2.count;
+  if (entryInfo2.count != 0) {
     return;
   }
-  m_entryCounts.erase(entry);
+  m_entryIds.erase(entry);
+  if (m_state != kActive && m_state != kPaused) {
+    [[unlikely]] return;
+  }
   uint8_t* buf = StartRecord(0, timestamp, 5, 5);
   *buf++ = impl::kControlFinish;
   wpi::support::endian::write32le(buf, entry);
@@ -481,6 +698,10 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
+  m_entryIds[entry].metadata = metadata;
+  if (m_state != kActive && m_state != kPaused) {
+    [[unlikely]] return;
+  }
   uint8_t* buf = StartRecord(0, timestamp, 5 + 4 + metadata.size(), 5);
   *buf++ = impl::kControlSetMetadata;
   wpi::support::endian::write32le(buf, entry);
@@ -491,6 +712,13 @@
   assert(size <= kBlockSize);
   if (m_outgoing.empty() || size > m_outgoing.back().GetRemaining()) {
     if (m_free.empty()) {
+      if (m_outgoing.size() >= kMaxBufferCount) {
+        [[unlikely]] WPI_ERROR(
+            m_msglog,
+            "outgoing buffers exceeded threshold, pausing logging--"
+            "consider flushing to disk more frequently (smaller period)");
+        m_state = kPaused;
+      }
       m_outgoing.emplace_back();
     } else {
       m_outgoing.emplace_back(std::move(m_free.back()));
@@ -531,8 +759,8 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   StartRecord(entry, timestamp, data.size(), 0);
   AppendImpl(data);
@@ -545,8 +773,8 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   size_t size = 0;
   for (auto&& chunk : data) {
@@ -563,8 +791,8 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   uint8_t* buf = StartRecord(entry, timestamp, 1, 1);
   buf[0] = value ? 1 : 0;
@@ -575,8 +803,8 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   uint8_t* buf = StartRecord(entry, timestamp, 8, 8);
   wpi::support::endian::write64le(buf, value);
@@ -587,15 +815,15 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   uint8_t* buf = StartRecord(entry, timestamp, 4, 4);
   if constexpr (wpi::support::endian::system_endianness() ==
                 wpi::support::little) {
     std::memcpy(buf, &value, 4);
   } else {
-    wpi::support::endian::write32le(buf, wpi::FloatToBits(value));
+    wpi::support::endian::write32le(buf, wpi::bit_cast<uint32_t>(value));
   }
 }
 
@@ -604,15 +832,15 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   uint8_t* buf = StartRecord(entry, timestamp, 8, 8);
   if constexpr (wpi::support::endian::system_endianness() ==
                 wpi::support::little) {
     std::memcpy(buf, &value, 8);
   } else {
-    wpi::support::endian::write64le(buf, wpi::DoubleToBits(value));
+    wpi::support::endian::write64le(buf, wpi::bit_cast<uint64_t>(value));
   }
 }
 
@@ -629,8 +857,8 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   StartRecord(entry, timestamp, arr.size(), 0);
   uint8_t* buf;
@@ -653,8 +881,8 @@
     return;
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   StartRecord(entry, timestamp, arr.size(), 0);
   uint8_t* buf;
@@ -688,8 +916,8 @@
       return;
     }
     std::scoped_lock lock{m_mutex};
-    if (m_paused) {
-      return;
+    if (m_state != kActive) {
+      [[unlikely]] return;
     }
     StartRecord(entry, timestamp, arr.size() * 8, 0);
     uint8_t* buf;
@@ -721,22 +949,22 @@
       return;
     }
     std::scoped_lock lock{m_mutex};
-    if (m_paused) {
-      return;
+    if (m_state != kActive) {
+      [[unlikely]] return;
     }
     StartRecord(entry, timestamp, arr.size() * 4, 0);
     uint8_t* buf;
     while ((arr.size() * 4) > kBlockSize) {
       buf = Reserve(kBlockSize);
       for (auto val : arr.subspan(0, kBlockSize / 4)) {
-        wpi::support::endian::write32le(buf, wpi::FloatToBits(val));
+        wpi::support::endian::write32le(buf, wpi::bit_cast<uint32_t>(val));
         buf += 4;
       }
       arr = arr.subspan(kBlockSize / 4);
     }
     buf = Reserve(arr.size() * 4);
     for (auto val : arr) {
-      wpi::support::endian::write32le(buf, wpi::FloatToBits(val));
+      wpi::support::endian::write32le(buf, wpi::bit_cast<uint32_t>(val));
       buf += 4;
     }
   }
@@ -754,22 +982,22 @@
       return;
     }
     std::scoped_lock lock{m_mutex};
-    if (m_paused) {
-      return;
+    if (m_state != kActive) {
+      [[unlikely]] return;
     }
     StartRecord(entry, timestamp, arr.size() * 8, 0);
     uint8_t* buf;
     while ((arr.size() * 8) > kBlockSize) {
       buf = Reserve(kBlockSize);
       for (auto val : arr.subspan(0, kBlockSize / 8)) {
-        wpi::support::endian::write64le(buf, wpi::DoubleToBits(val));
+        wpi::support::endian::write64le(buf, wpi::bit_cast<uint64_t>(val));
         buf += 8;
       }
       arr = arr.subspan(kBlockSize / 8);
     }
     buf = Reserve(arr.size() * 8);
     for (auto val : arr) {
-      wpi::support::endian::write64le(buf, wpi::DoubleToBits(val));
+      wpi::support::endian::write64le(buf, wpi::bit_cast<uint64_t>(val));
       buf += 8;
     }
   }
@@ -787,8 +1015,8 @@
     size += 4 + str.size();
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   uint8_t* buf = StartRecord(entry, timestamp, size, 4);
   wpi::support::endian::write32le(buf, arr.size());
@@ -810,12 +1038,169 @@
     size += 4 + str.size();
   }
   std::scoped_lock lock{m_mutex};
-  if (m_paused) {
-    return;
+  if (m_state != kActive) {
+    [[unlikely]] return;
   }
   uint8_t* buf = StartRecord(entry, timestamp, size, 4);
   wpi::support::endian::write32le(buf, arr.size());
-  for (auto sv : arr) {
+  for (auto&& sv : arr) {
     AppendStringImpl(sv);
   }
 }
+
+void DataLog::AppendStringArray(int entry,
+                                std::span<const WPI_DataLog_String> arr,
+                                int64_t timestamp) {
+  if (entry <= 0) {
+    return;
+  }
+  // storage: 4-byte array length, each string prefixed by 4-byte length
+  // calculate total size
+  size_t size = 4;
+  for (auto&& str : arr) {
+    size += 4 + str.len;
+  }
+  std::scoped_lock lock{m_mutex};
+  if (m_state != kActive) {
+    [[unlikely]] return;
+  }
+  uint8_t* buf = StartRecord(entry, timestamp, size, 4);
+  wpi::support::endian::write32le(buf, arr.size());
+  for (auto&& sv : arr) {
+    AppendStringImpl(sv.str);
+  }
+}
+
+extern "C" {
+
+struct WPI_DataLog* WPI_DataLog_Create(const char* dir, const char* filename,
+                                       double period, const char* extraHeader) {
+  return reinterpret_cast<WPI_DataLog*>(
+      new DataLog{dir, filename, period, extraHeader});
+}
+
+struct WPI_DataLog* WPI_DataLog_Create_Func(
+    void (*write)(void* ptr, const uint8_t* data, size_t len), void* ptr,
+    double period, const char* extraHeader) {
+  return reinterpret_cast<WPI_DataLog*>(
+      new DataLog{[=](auto data) { write(ptr, data.data(), data.size()); },
+                  period, extraHeader});
+}
+
+void WPI_DataLog_Release(struct WPI_DataLog* datalog) {
+  delete reinterpret_cast<DataLog*>(datalog);
+}
+
+void WPI_DataLog_SetFilename(struct WPI_DataLog* datalog,
+                             const char* filename) {
+  reinterpret_cast<DataLog*>(datalog)->SetFilename(filename);
+}
+
+void WPI_DataLog_Flush(struct WPI_DataLog* datalog) {
+  reinterpret_cast<DataLog*>(datalog)->Flush();
+}
+
+void WPI_DataLog_Pause(struct WPI_DataLog* datalog) {
+  reinterpret_cast<DataLog*>(datalog)->Pause();
+}
+
+void WPI_DataLog_Resume(struct WPI_DataLog* datalog) {
+  reinterpret_cast<DataLog*>(datalog)->Resume();
+}
+
+void WPI_DataLog_Stop(struct WPI_DataLog* datalog) {
+  reinterpret_cast<DataLog*>(datalog)->Stop();
+}
+
+int WPI_DataLog_Start(struct WPI_DataLog* datalog, const char* name,
+                      const char* type, const char* metadata,
+                      int64_t timestamp) {
+  return reinterpret_cast<DataLog*>(datalog)->Start(name, type, metadata,
+                                                    timestamp);
+}
+
+void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry,
+                        int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->Finish(entry, timestamp);
+}
+
+void WPI_DataLog_SetMetadata(struct WPI_DataLog* datalog, int entry,
+                             const char* metadata, int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->SetMetadata(entry, metadata, timestamp);
+}
+
+void WPI_DataLog_AppendRaw(struct WPI_DataLog* datalog, int entry,
+                           const uint8_t* data, size_t len, int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendRaw(entry, {data, len}, timestamp);
+}
+
+void WPI_DataLog_AppendBoolean(struct WPI_DataLog* datalog, int entry,
+                               int value, int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendBoolean(entry, value, timestamp);
+}
+
+void WPI_DataLog_AppendInteger(struct WPI_DataLog* datalog, int entry,
+                               int64_t value, int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendInteger(entry, value, timestamp);
+}
+
+void WPI_DataLog_AppendFloat(struct WPI_DataLog* datalog, int entry,
+                             float value, int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendFloat(entry, value, timestamp);
+}
+
+void WPI_DataLog_AppendDouble(struct WPI_DataLog* datalog, int entry,
+                              double value, int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendDouble(entry, value, timestamp);
+}
+
+void WPI_DataLog_AppendString(struct WPI_DataLog* datalog, int entry,
+                              const char* value, size_t len,
+                              int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendString(entry, {value, len},
+                                                    timestamp);
+}
+
+void WPI_DataLog_AppendBooleanArray(struct WPI_DataLog* datalog, int entry,
+                                    const int* arr, size_t len,
+                                    int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendBooleanArray(entry, {arr, len},
+                                                          timestamp);
+}
+
+void WPI_DataLog_AppendBooleanArrayByte(struct WPI_DataLog* datalog, int entry,
+                                        const uint8_t* arr, size_t len,
+                                        int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendBooleanArray(entry, {arr, len},
+                                                          timestamp);
+}
+
+void WPI_DataLog_AppendIntegerArray(struct WPI_DataLog* datalog, int entry,
+                                    const int64_t* arr, size_t len,
+                                    int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendIntegerArray(entry, {arr, len},
+                                                          timestamp);
+}
+
+void WPI_DataLog_AppendFloatArray(struct WPI_DataLog* datalog, int entry,
+                                  const float* arr, size_t len,
+                                  int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendFloatArray(entry, {arr, len},
+                                                        timestamp);
+}
+
+void WPI_DataLog_AppendDoubleArray(struct WPI_DataLog* datalog, int entry,
+                                   const double* arr, size_t len,
+                                   int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendDoubleArray(entry, {arr, len},
+                                                         timestamp);
+}
+
+void WPI_DataLog_AppendStringArray(struct WPI_DataLog* datalog, int entry,
+                                   const WPI_DataLog_String* arr, size_t len,
+                                   int64_t timestamp) {
+  reinterpret_cast<DataLog*>(datalog)->AppendStringArray(entry, {arr, len},
+                                                         timestamp);
+}
+
+}  // extern "C"
diff --git a/wpiutil/src/main/native/cpp/DataLogReader.cpp b/wpiutil/src/main/native/cpp/DataLogReader.cpp
index 96f6689..c2e1192 100644
--- a/wpiutil/src/main/native/cpp/DataLogReader.cpp
+++ b/wpiutil/src/main/native/cpp/DataLogReader.cpp
@@ -95,7 +95,7 @@
   if (m_data.size() != 4) {
     return false;
   }
-  *value = wpi::BitsToFloat(wpi::support::endian::read32le(m_data.data()));
+  *value = wpi::bit_cast<float>(wpi::support::endian::read32le(m_data.data()));
   return true;
 }
 
@@ -103,7 +103,7 @@
   if (m_data.size() != 8) {
     return false;
   }
-  *value = wpi::BitsToDouble(wpi::support::endian::read64le(m_data.data()));
+  *value = wpi::bit_cast<double>(wpi::support::endian::read64le(m_data.data()));
   return true;
 }
 
@@ -141,7 +141,7 @@
   arr->reserve(m_data.size() / 4);
   for (size_t pos = 0; pos < m_data.size(); pos += 4) {
     arr->push_back(
-        wpi::BitsToFloat(wpi::support::endian::read32le(&m_data[pos])));
+        wpi::bit_cast<float>(wpi::support::endian::read32le(&m_data[pos])));
   }
   return true;
 }
@@ -154,7 +154,7 @@
   arr->reserve(m_data.size() / 8);
   for (size_t pos = 0; pos < m_data.size(); pos += 8) {
     arr->push_back(
-        wpi::BitsToDouble(wpi::support::endian::read64le(&m_data[pos])));
+        wpi::bit_cast<double>(wpi::support::endian::read64le(&m_data[pos])));
   }
   return true;
 }
diff --git a/wpiutil/src/main/native/cpp/fs.cpp b/wpiutil/src/main/native/cpp/fs.cpp
index fad6a66..ed68297 100644
--- a/wpiutil/src/main/native/cpp/fs.cpp
+++ b/wpiutil/src/main/native/cpp/fs.cpp
@@ -43,26 +43,6 @@
 
 #endif  // _WIN32
 
-#if defined(__APPLE__)
-#include <Availability.h>
-#endif
-#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) \
-     || (defined(__cplusplus) && __cplusplus >= 201703L)) \
-    && defined(__has_include)
-#if __has_include(<filesystem>) \
-    && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
-        || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) \
-    && (defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 10 \
-        || (__GNUC__ >= 9 && __GNUC_MINOR__ >= 1))
-#define GHC_USE_STD_FS
-#endif
-#endif
-#ifndef GHC_USE_STD_FS
-// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
-#define GHC_FILESYSTEM_IMPLEMENTATION
-#include "wpi/ghc/filesystem.hpp"
-#endif
-
 #include "wpi/Errno.h"
 #include "wpi/ErrorHandling.h"
 #include "wpi/WindowsError.h"
diff --git a/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp b/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp
index 997b90b..c78c891 100644
--- a/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp
+++ b/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp
@@ -4,6 +4,9 @@
 
 #include <jni.h>
 
+#include <fmt/format.h>
+
+#include "WPIUtilJNI.h"
 #include "edu_wpi_first_util_datalog_DataLogJNI.h"
 #include "wpi/DataLog.h"
 #include "wpi/jni_util.h"
@@ -23,6 +26,18 @@
   (JNIEnv* env, jclass, jstring dir, jstring filename, jdouble period,
    jstring extraHeader)
 {
+  if (!dir) {
+    wpi::ThrowNullPointerException(env, "dir is null");
+    return 0;
+  }
+  if (!filename) {
+    wpi::ThrowNullPointerException(env, "filename is null");
+    return 0;
+  }
+  if (!extraHeader) {
+    wpi::ThrowNullPointerException(env, "extraHeader is null");
+    return 0;
+  }
   return reinterpret_cast<jlong>(new DataLog{JStringRef{env, dir},
                                              JStringRef{env, filename}, period,
                                              JStringRef{env, extraHeader}});
@@ -38,6 +53,11 @@
   (JNIEnv* env, jclass, jlong impl, jstring filename)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  if (!filename) {
+    wpi::ThrowNullPointerException(env, "filename is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->SetFilename(JStringRef{env, filename});
@@ -50,9 +70,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_flush
-  (JNIEnv*, jclass, jlong impl)
+  (JNIEnv* env, jclass, jlong impl)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->Flush();
@@ -65,9 +86,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_pause
-  (JNIEnv*, jclass, jlong impl)
+  (JNIEnv* env, jclass, jlong impl)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->Pause();
@@ -80,9 +102,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_resume
-  (JNIEnv*, jclass, jlong impl)
+  (JNIEnv* env, jclass, jlong impl)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->Resume();
@@ -90,6 +113,63 @@
 
 /*
  * Class:     edu_wpi_first_util_datalog_DataLogJNI
+ * Method:    stop
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_stop
+  (JNIEnv* env, jclass, jlong impl)
+{
+  if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  reinterpret_cast<DataLog*>(impl)->Stop();
+}
+
+/*
+ * Class:     edu_wpi_first_util_datalog_DataLogJNI
+ * Method:    addSchema
+ * Signature: (JLjava/lang/String;Ljava/lang/String;[BJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_addSchema
+  (JNIEnv* env, jclass, jlong impl, jstring name, jstring type,
+   jbyteArray schema, jlong timestamp)
+{
+  if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  reinterpret_cast<DataLog*>(impl)->AddSchema(
+      JStringRef{env, name}, JStringRef{env, type},
+      JSpan<const jbyte>{env, schema}.uarray(), timestamp);
+}
+
+/*
+ * Class:     edu_wpi_first_util_datalog_DataLogJNI
+ * Method:    addSchemaString
+ * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_addSchemaString
+  (JNIEnv* env, jclass, jlong impl, jstring name, jstring type, jstring schema,
+   jlong timestamp)
+{
+  if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  JStringRef schemaStr{env, schema};
+  std::string_view schemaView = schemaStr.str();
+  reinterpret_cast<DataLog*>(impl)->AddSchema(
+      JStringRef{env, name}, JStringRef{env, type},
+      {reinterpret_cast<const uint8_t*>(schemaView.data()), schemaView.size()},
+      timestamp);
+}
+
+/*
+ * Class:     edu_wpi_first_util_datalog_DataLogJNI
  * Method:    start
  * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;J)I
  */
@@ -99,6 +179,7 @@
    jstring metadata, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return 0;
   }
   return reinterpret_cast<DataLog*>(impl)->Start(
@@ -113,9 +194,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_finish
-  (JNIEnv*, jclass, jlong impl, jint entry, jlong timestamp)
+  (JNIEnv* env, jclass, jlong impl, jint entry, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->Finish(entry, timestamp);
@@ -132,6 +214,7 @@
    jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->SetMetadata(
@@ -153,21 +236,73 @@
 /*
  * Class:     edu_wpi_first_util_datalog_DataLogJNI
  * Method:    appendRaw
- * Signature: (JI[BJ)V
+ * Signature: (JI[BIIJ)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_appendRaw
-  (JNIEnv* env, jclass, jlong impl, jint entry, jbyteArray value,
-   jlong timestamp)
+  (JNIEnv* env, jclass, jlong impl, jint entry, jbyteArray value, jint start,
+   jint length, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
-  JByteArrayRef cvalue{env, value};
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
+    return;
+  }
+  if (start < 0) {
+    wpi::ThrowIndexOobException(env, "start must be >= 0");
+    return;
+  }
+  if (length < 0) {
+    wpi::ThrowIndexOobException(env, "length must be >= 0");
+    return;
+  }
+  CriticalJSpan<const jbyte> cvalue{env, value};
+  if (static_cast<unsigned int>(start + length) > cvalue.size()) {
+    wpi::ThrowIndexOobException(
+        env, "start + len must be smaller than array length");
+    return;
+  }
   reinterpret_cast<DataLog*>(impl)->AppendRaw(
-      entry,
-      {reinterpret_cast<const uint8_t*>(cvalue.array().data()), cvalue.size()},
-      timestamp);
+      entry, cvalue.uarray().subspan(start, length), timestamp);
+}
+
+/*
+ * Class:     edu_wpi_first_util_datalog_DataLogJNI
+ * Method:    appendRawBuffer
+ * Signature: (JILjava/lang/Object;IIJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendRawBuffer
+  (JNIEnv* env, jclass, jlong impl, jint entry, jobject value, jint start,
+   jint length, jlong timestamp)
+{
+  if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
+    return;
+  }
+  if (start < 0) {
+    wpi::ThrowIndexOobException(env, "start must be >= 0");
+    return;
+  }
+  if (length < 0) {
+    wpi::ThrowIndexOobException(env, "length must be >= 0");
+    return;
+  }
+  JSpan<const jbyte> cvalue{env, value, static_cast<size_t>(start + length)};
+  if (!cvalue) {
+    wpi::ThrowIllegalArgumentException(env,
+                                       "value must be a native ByteBuffer");
+    return;
+  }
+  reinterpret_cast<DataLog*>(impl)->AppendRaw(
+      entry, cvalue.uarray().subspan(start, length), timestamp);
 }
 
 /*
@@ -177,9 +312,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_appendBoolean
-  (JNIEnv*, jclass, jlong impl, jint entry, jboolean value, jlong timestamp)
+  (JNIEnv* env, jclass, jlong impl, jint entry, jboolean value, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendBoolean(entry, value, timestamp);
@@ -192,9 +328,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_appendInteger
-  (JNIEnv*, jclass, jlong impl, jint entry, jlong value, jlong timestamp)
+  (JNIEnv* env, jclass, jlong impl, jint entry, jlong value, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendInteger(entry, value, timestamp);
@@ -207,9 +344,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_appendFloat
-  (JNIEnv*, jclass, jlong impl, jint entry, jfloat value, jlong timestamp)
+  (JNIEnv* env, jclass, jlong impl, jint entry, jfloat value, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendFloat(entry, value, timestamp);
@@ -222,9 +360,10 @@
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_util_datalog_DataLogJNI_appendDouble
-  (JNIEnv*, jclass, jlong impl, jint entry, jdouble value, jlong timestamp)
+  (JNIEnv* env, jclass, jlong impl, jint entry, jdouble value, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendDouble(entry, value, timestamp);
@@ -240,6 +379,7 @@
   (JNIEnv* env, jclass, jlong impl, jint entry, jstring value, jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendString(entry, JStringRef{env, value},
@@ -257,10 +397,15 @@
    jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendBooleanArray(
-      entry, JBooleanArrayRef{env, value}, timestamp);
+      entry, JSpan<const jboolean>{env, value}, timestamp);
 }
 
 /*
@@ -274,19 +419,22 @@
    jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
     return;
   }
-  JLongArrayRef jarr{env, value};
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
+    return;
+  }
+  JSpan<const jlong> jarr{env, value};
   if constexpr (sizeof(jlong) == sizeof(int64_t)) {
     reinterpret_cast<DataLog*>(impl)->AppendIntegerArray(
-        entry,
-        {reinterpret_cast<const int64_t*>(jarr.array().data()),
-         jarr.array().size()},
+        entry, {reinterpret_cast<const int64_t*>(jarr.data()), jarr.size()},
         timestamp);
   } else {
     wpi::SmallVector<int64_t, 16> arr;
     arr.reserve(jarr.size());
-    for (auto v : jarr.array()) {
+    for (auto v : jarr) {
       arr.push_back(v);
     }
     reinterpret_cast<DataLog*>(impl)->AppendIntegerArray(entry, arr, timestamp);
@@ -304,10 +452,15 @@
    jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendFloatArray(
-      entry, JFloatArrayRef{env, value}, timestamp);
+      entry, JSpan<const jfloat>{env, value}, timestamp);
 }
 
 /*
@@ -321,10 +474,15 @@
    jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
     return;
   }
   reinterpret_cast<DataLog*>(impl)->AppendDoubleArray(
-      entry, JDoubleArrayRef{env, value}, timestamp);
+      entry, JSpan<const jdouble>{env, value}, timestamp);
 }
 
 /*
@@ -338,6 +496,11 @@
    jlong timestamp)
 {
   if (impl == 0) {
+    wpi::ThrowNullPointerException(env, "impl is null");
+    return;
+  }
+  if (!value) {
+    wpi::ThrowNullPointerException(env, "value is null");
     return;
   }
   size_t len = env->GetArrayLength(value);
@@ -347,6 +510,8 @@
     JLocal<jstring> elem{
         env, static_cast<jstring>(env->GetObjectArrayElement(value, i))};
     if (!elem) {
+      wpi::ThrowNullPointerException(
+          env, fmt::format("string at element {} is null", i));
       return;
     }
     arr.emplace_back(JStringRef{env, elem}.str());
diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
index 5fa4ddf..eb55fd0 100644
--- a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
+++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
@@ -2,10 +2,13 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
+#include "WPIUtilJNI.h"
+
 #include <jni.h>
 
+#include <fmt/format.h>
+
 #include "edu_wpi_first_util_WPIUtilJNI.h"
-#include "fmt/format.h"
 #include "wpi/Synchronization.h"
 #include "wpi/jni_util.h"
 #include "wpi/timestamp.h"
@@ -15,7 +18,28 @@
 static bool mockTimeEnabled = false;
 static uint64_t mockNow = 0;
 
+static JException illegalArgEx;
+static JException indexOobEx;
 static JException interruptedEx;
+static JException nullPointerEx;
+
+static const JExceptionInit exceptions[] = {
+    {"java/lang/IllegalArgumentException", &illegalArgEx},
+    {"java/lang/IndexOutOfBoundsException", &indexOobEx},
+    {"java/lang/InterruptedException", &interruptedEx},
+    {"java/lang/NullPointerException", &nullPointerEx}};
+
+void wpi::ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg) {
+  illegalArgEx.Throw(env, msg);
+}
+
+void wpi::ThrowIndexOobException(JNIEnv* env, std::string_view msg) {
+  indexOobEx.Throw(env, msg);
+}
+
+void wpi::ThrowNullPointerException(JNIEnv* env, std::string_view msg) {
+  nullPointerEx.Throw(env, msg);
+}
 
 extern "C" {
 
@@ -25,9 +49,11 @@
     return JNI_ERR;
   }
 
-  interruptedEx = JException(env, "java/lang/InterruptedException");
-  if (!interruptedEx) {
-    return JNI_ERR;
+  for (auto& c : exceptions) {
+    *c.cls = JException(env, c.name);
+    if (!*c.cls) {
+      return JNI_ERR;
+    }
   }
 
   return JNI_VERSION_1_6;
@@ -39,7 +65,9 @@
     return;
   }
 
-  interruptedEx.free(env);
+  for (auto& c : exceptions) {
+    c.cls->free(env);
+  }
 }
 
 /*
@@ -51,7 +79,7 @@
 Java_edu_wpi_first_util_WPIUtilJNI_writeStderr
   (JNIEnv* env, jclass, jstring str)
 {
-  fmt::print(stderr, "{}", JStringRef{env, str});
+  fmt::print(stderr, "{}", JStringRef{env, str}.str());
 }
 
 /*
@@ -63,8 +91,12 @@
 Java_edu_wpi_first_util_WPIUtilJNI_enableMockTime
   (JNIEnv*, jclass)
 {
+#ifdef __FRC_ROBORIO__
+  fmt::print(stderr, "WPIUtil: Mocking time is not available on the Rio\n");
+#else
   mockTimeEnabled = true;
   wpi::SetNowImpl([] { return mockNow; });
+#endif
 }
 
 /*
@@ -244,11 +276,11 @@
 Java_edu_wpi_first_util_WPIUtilJNI_waitForObjects
   (JNIEnv* env, jclass, jintArray handles)
 {
-  JIntArrayRef handlesArr{env, handles};
+  JSpan<const jint> handlesArr{env, handles};
   wpi::SmallVector<WPI_Handle, 8> signaledBuf;
   signaledBuf.resize(handlesArr.size());
   std::span<const WPI_Handle> handlesArr2{
-      reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
+      reinterpret_cast<const WPI_Handle*>(handlesArr.data()),
       handlesArr.size()};
 
   auto signaled = wpi::WaitForObjects(handlesArr2, signaledBuf);
@@ -268,11 +300,11 @@
 Java_edu_wpi_first_util_WPIUtilJNI_waitForObjectsTimeout
   (JNIEnv* env, jclass, jintArray handles, jdouble timeout)
 {
-  JIntArrayRef handlesArr{env, handles};
+  JSpan<const jint> handlesArr{env, handles};
   wpi::SmallVector<WPI_Handle, 8> signaledBuf;
   signaledBuf.resize(handlesArr.size());
   std::span<const WPI_Handle> handlesArr2{
-      reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
+      reinterpret_cast<const WPI_Handle*>(handlesArr.data()),
       handlesArr.size()};
 
   bool timedOut;
diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.h b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.h
new file mode 100644
index 0000000..541064f
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.h
@@ -0,0 +1,17 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <jni.h>
+
+#include <string_view>
+
+namespace wpi {
+
+void ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg);
+void ThrowIndexOobException(JNIEnv* env, std::string_view msg);
+void ThrowNullPointerException(JNIEnv* env, std::string_view msg);
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp b/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp
new file mode 100644
index 0000000..4f2a616
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp
@@ -0,0 +1,194 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/protobuf/Protobuf.h"
+
+#include <fmt/format.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/message.h>
+
+#include "wpi/SmallVector.h"
+
+using namespace wpi;
+
+using google::protobuf::Arena;
+using google::protobuf::FileDescriptor;
+using google::protobuf::FileDescriptorProto;
+
+namespace {
+class VectorOutputStream final
+    : public google::protobuf::io::ZeroCopyOutputStream {
+ public:
+  // Create a StringOutputStream which appends bytes to the given string.
+  // The string remains property of the caller, but it is mutated in arbitrary
+  // ways and MUST NOT be accessed in any way until you're done with the
+  // stream. Either be sure there's no further usage, or (safest) destroy the
+  // stream before using the contents.
+  //
+  // Hint:  If you call target->reserve(n) before creating the stream,
+  //   the first call to Next() will return at least n bytes of buffer
+  //   space.
+  explicit VectorOutputStream(std::vector<uint8_t>& target) : target_{target} {}
+  VectorOutputStream(const VectorOutputStream&) = delete;
+  ~VectorOutputStream() override = default;
+
+  VectorOutputStream& operator=(const VectorOutputStream&) = delete;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override { target_.resize(target_.size() - count); }
+  int64_t ByteCount() const override { return target_.size(); }
+
+ private:
+  static constexpr size_t kMinimumSize = 16;
+
+  std::vector<uint8_t>& target_;
+};
+
+class SmallVectorOutputStream final
+    : public google::protobuf::io::ZeroCopyOutputStream {
+ public:
+  // Create a StringOutputStream which appends bytes to the given string.
+  // The string remains property of the caller, but it is mutated in arbitrary
+  // ways and MUST NOT be accessed in any way until you're done with the
+  // stream. Either be sure there's no further usage, or (safest) destroy the
+  // stream before using the contents.
+  //
+  // Hint:  If you call target->reserve(n) before creating the stream,
+  //   the first call to Next() will return at least n bytes of buffer
+  //   space.
+  explicit SmallVectorOutputStream(wpi::SmallVectorImpl<uint8_t>& target)
+      : target_{target} {
+    target.resize(0);
+  }
+  SmallVectorOutputStream(const SmallVectorOutputStream&) = delete;
+  ~SmallVectorOutputStream() override = default;
+
+  SmallVectorOutputStream& operator=(const SmallVectorOutputStream&) = delete;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override { target_.resize(target_.size() - count); }
+  int64_t ByteCount() const override { return target_.size(); }
+
+ private:
+  static constexpr size_t kMinimumSize = 16;
+
+  wpi::SmallVectorImpl<uint8_t>& target_;
+};
+}  // namespace
+
+bool VectorOutputStream::Next(void** data, int* size) {
+  size_t old_size = target_.size();
+
+  // Grow the string.
+  size_t new_size;
+  if (old_size < target_.capacity()) {
+    // Resize to match its capacity, since we can get away
+    // without a memory allocation this way.
+    new_size = target_.capacity();
+  } else {
+    // Size has reached capacity, try to double it.
+    new_size = old_size * 2;
+  }
+  // Avoid integer overflow in returned '*size'.
+  new_size = (std::min)(new_size, old_size + (std::numeric_limits<int>::max)());
+  // Increase the size, also make sure that it is at least kMinimumSize.
+  target_.resize((std::max)(new_size, kMinimumSize));
+
+  *data = target_.data() + old_size;
+  *size = target_.size() - old_size;
+  return true;
+}
+
+bool SmallVectorOutputStream::Next(void** data, int* size) {
+  size_t old_size = target_.size();
+
+  // Grow the string.
+  size_t new_size;
+  if (old_size < target_.capacity()) {
+    // Resize to match its capacity, since we can get away
+    // without a memory allocation this way.
+    new_size = target_.capacity();
+  } else {
+    // Size has reached capacity, try to double it.
+    new_size = old_size * 2;
+  }
+  // Avoid integer overflow in returned '*size'.
+  new_size = (std::min)(new_size, old_size + (std::numeric_limits<int>::max)());
+  // Increase the size, also make sure that it is at least kMinimumSize.
+  target_.resize_for_overwrite((std::max)(new_size, kMinimumSize));
+
+  *data = target_.data() + old_size;
+  *size = target_.size() - old_size;
+  return true;
+}
+
+void detail::DeleteProtobuf(google::protobuf::Message* msg) {
+  if (msg && !msg->GetArena()) {
+    delete msg;
+  }
+}
+
+bool detail::ParseProtobuf(google::protobuf::Message* msg,
+                           std::span<const uint8_t> data) {
+  return msg->ParseFromArray(data.data(), data.size());
+}
+
+bool detail::SerializeProtobuf(wpi::SmallVectorImpl<uint8_t>& out,
+                               const google::protobuf::Message& msg) {
+  SmallVectorOutputStream stream{out};
+  return msg.SerializeToZeroCopyStream(&stream);
+}
+
+bool detail::SerializeProtobuf(std::vector<uint8_t>& out,
+                               const google::protobuf::Message& msg) {
+  VectorOutputStream stream{out};
+  return msg.SerializeToZeroCopyStream(&stream);
+}
+
+std::string detail::GetTypeString(const google::protobuf::Message& msg) {
+  return fmt::format("proto:{}", msg.GetDescriptor()->full_name());
+}
+
+static void ForEachProtobufDescriptorImpl(
+    const FileDescriptor* desc,
+    function_ref<bool(std::string_view typeString)> exists,
+    function_ref<void(std::string_view typeString,
+                      std::span<const uint8_t> schema)>
+        fn,
+    Arena* arena, FileDescriptorProto** descproto) {
+  std::string name = fmt::format("proto:{}", desc->name());
+  if (exists(name)) {
+    return;
+  }
+  for (int i = 0, ndep = desc->dependency_count(); i < ndep; ++i) {
+    ForEachProtobufDescriptorImpl(desc->dependency(i), exists, fn, arena,
+                                  descproto);
+  }
+  if (!*descproto) {
+    *descproto = Arena::CreateMessage<FileDescriptorProto>(arena);
+  }
+  (*descproto)->Clear();
+  desc->CopyTo(*descproto);
+  SmallVector<uint8_t, 128> buf;
+  detail::SerializeProtobuf(buf, **descproto);
+  fn(name, buf);
+}
+
+void detail::ForEachProtobufDescriptor(
+    const google::protobuf::Message& msg,
+    function_ref<bool(std::string_view filename)> exists,
+    function_ref<void(std::string_view filename,
+                      std::span<const uint8_t> descriptor)>
+        fn) {
+  FileDescriptorProto* descproto = nullptr;
+  ForEachProtobufDescriptorImpl(msg.GetDescriptor()->file(), exists, fn,
+                                msg.GetArena(), &descproto);
+  if (descproto && !msg.GetArena()) {
+    delete descproto;
+  }
+}
diff --git a/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp b/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp
new file mode 100644
index 0000000..144bd03
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp
@@ -0,0 +1,131 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/protobuf/ProtobufMessageDatabase.h"
+
+#include <google/protobuf/descriptor.h>
+
+using namespace wpi;
+
+using google::protobuf::Arena;
+using google::protobuf::FileDescriptorProto;
+using google::protobuf::Message;
+
+bool ProtobufMessageDatabase::Add(std::string_view filename,
+                                  std::span<const uint8_t> data) {
+  auto& file = m_files[filename];
+  bool needsRebuild = false;
+  if (file.complete) {
+    file.complete = false;
+
+    m_msgs.clear();
+    m_factory.reset();
+
+    // rebuild the pool EXCEPT for this descriptor
+    m_pool = std::make_unique<google::protobuf::DescriptorPool>();
+
+    for (auto&& p : m_files) {
+      p.second.inPool = false;
+    }
+
+    needsRebuild = true;
+  }
+
+  if (!file.proto) {
+    file.proto = std::unique_ptr<FileDescriptorProto>{
+        Arena::CreateMessage<FileDescriptorProto>(nullptr)};
+  } else {
+    // replacing an existing one; remove any previously existing refs
+    for (auto&& dep : file.proto->dependency()) {
+      auto& depFile = m_files[dep];
+      std::erase(depFile.uses, filename);
+    }
+    file.proto->Clear();
+  }
+
+  // parse data
+  if (!file.proto->ParseFromArray(data.data(), data.size())) {
+    return false;
+  }
+
+  // rebuild if necessary; we do this after the parse due to dependencies
+  if (needsRebuild) {
+    for (auto&& p : m_files) {
+      if (p.second.complete && !p.second.inPool) {
+        Rebuild(p.second);
+      }
+    }
+
+    // clear messages and reset factory; Find() will recreate as needed
+    m_factory = std::make_unique<google::protobuf::DynamicMessageFactory>();
+  }
+
+  // build this one
+  Build(filename, file);
+  return true;
+}
+
+Message* ProtobufMessageDatabase::Find(std::string_view name) const {
+  // cached
+  auto& msg = m_msgs[name];
+  if (msg) {
+    return msg.get();
+  }
+
+  // need to create it
+  auto desc = m_pool->FindMessageTypeByName(std::string{name});
+  if (!desc) {
+    return nullptr;
+  }
+  msg = std::unique_ptr<Message>{m_factory->GetPrototype(desc)->New(nullptr)};
+  return msg.get();
+}
+
+void ProtobufMessageDatabase::Build(std::string_view filename,
+                                    ProtoFile& file) {
+  if (file.complete) {
+    return;
+  }
+  // are all of the dependencies complete?
+  bool complete = true;
+  for (auto&& dep : file.proto->dependency()) {
+    auto& depFile = m_files[dep];
+    if (!depFile.complete) {
+      complete = false;
+    }
+    depFile.uses.emplace_back(filename);
+  }
+  if (!complete) {
+    return;
+  }
+
+  // add to pool
+  if (!m_pool->BuildFile(*file.proto)) {
+    return;
+  }
+  file.inPool = true;
+  file.complete = true;
+
+  // recursively validate all uses
+  for (auto&& use : file.uses) {
+    Build(use, m_files[use]);
+  }
+}
+
+bool ProtobufMessageDatabase::Rebuild(ProtoFile& file) {
+  for (auto&& dep : file.proto->dependency()) {
+    auto& depFile = m_files[dep];
+    if (!depFile.inPool) {
+      if (!Rebuild(depFile)) {
+        return false;
+      }
+    }
+  }
+  if (!m_pool->BuildFile(*file.proto)) {
+    return false;
+  }
+  file.inPool = true;
+  file.complete = true;
+  return true;
+}
diff --git a/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp b/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp
index 2c591e9..7a1e0b0 100644
--- a/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp
+++ b/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp
@@ -6,7 +6,8 @@
 
 #include <memory>
 
-#include "fmt/format.h"
+#include <fmt/format.h>
+
 #include "wpi/DenseMap.h"
 #include "wpi/SmallVector.h"
 #include "wpi/UidVector.h"
diff --git a/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp b/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp
new file mode 100644
index 0000000..7ae9271
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp
@@ -0,0 +1,444 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/struct/DynamicStruct.h"
+
+#include <algorithm>
+
+#include <fmt/format.h>
+
+#include "wpi/Endian.h"
+#include "wpi/SmallString.h"
+#include "wpi/SmallVector.h"
+#include "wpi/raw_ostream.h"
+#include "wpi/struct/SchemaParser.h"
+
+using namespace wpi;
+
+static size_t TypeToSize(StructFieldType type) {
+  switch (type) {
+    case StructFieldType::kBool:
+    case StructFieldType::kChar:
+    case StructFieldType::kInt8:
+    case StructFieldType::kUint8:
+      return 1;
+    case StructFieldType::kInt16:
+    case StructFieldType::kUint16:
+      return 2;
+    case StructFieldType::kInt32:
+    case StructFieldType::kUint32:
+    case StructFieldType::kFloat:
+      return 4;
+    case StructFieldType::kInt64:
+    case StructFieldType::kUint64:
+    case StructFieldType::kDouble:
+      return 8;
+    default:
+      return 0;
+  }
+}
+
+static StructFieldType TypeStringToType(std::string_view str) {
+  if (str == "bool") {
+    return StructFieldType::kBool;
+  } else if (str == "char") {
+    return StructFieldType::kChar;
+  } else if (str == "int8") {
+    return StructFieldType::kInt8;
+  } else if (str == "int16") {
+    return StructFieldType::kInt16;
+  } else if (str == "int32") {
+    return StructFieldType::kInt32;
+  } else if (str == "int64") {
+    return StructFieldType::kInt64;
+  } else if (str == "uint8") {
+    return StructFieldType::kUint8;
+  } else if (str == "uint16") {
+    return StructFieldType::kUint16;
+  } else if (str == "uint32") {
+    return StructFieldType::kUint32;
+  } else if (str == "uint64") {
+    return StructFieldType::kUint64;
+  } else if (str == "float" || str == "float32") {
+    return StructFieldType::kFloat;
+  } else if (str == "double" || str == "float64") {
+    return StructFieldType::kDouble;
+  } else {
+    return StructFieldType::kStruct;
+  }
+}
+
+static inline unsigned int ToBitWidth(size_t size, unsigned int bitWidth) {
+  if (bitWidth == 0) {
+    return size * 8;
+  } else {
+    return bitWidth;
+  }
+}
+
+static inline uint64_t ToBitMask(size_t size, unsigned int bitWidth) {
+  if (size == 0) {
+    return 0;
+  } else {
+    return UINT64_MAX >> (64 - ToBitWidth(size, bitWidth));
+  }
+}
+
+StructFieldDescriptor::StructFieldDescriptor(
+    const StructDescriptor* parent, std::string_view name, StructFieldType type,
+    size_t size, size_t arraySize, unsigned int bitWidth, EnumValues enumValues,
+    const StructDescriptor* structDesc, const private_init&)
+    : m_parent{parent},
+      m_name{name},
+      m_size{size},
+      m_arraySize{arraySize},
+      m_enum{std::move(enumValues)},
+      m_struct{structDesc},
+      m_bitMask{ToBitMask(size, bitWidth)},
+      m_type{type},
+      m_bitWidth{ToBitWidth(size, bitWidth)} {}
+
+const StructFieldDescriptor* StructDescriptor::FindFieldByName(
+    std::string_view name) const {
+  auto it = m_fieldsByName.find(name);
+  if (it == m_fieldsByName.end()) {
+    return nullptr;
+  }
+  return &m_fields[it->second];
+}
+
+bool StructDescriptor::CheckCircular(
+    wpi::SmallVectorImpl<const StructDescriptor*>& stack) const {
+  stack.emplace_back(this);
+  for (auto&& ref : m_references) {
+    if (std::find(stack.begin(), stack.end(), ref) != stack.end()) {
+      [[unlikely]] return false;
+    }
+    if (!ref->CheckCircular(stack)) {
+      [[unlikely]] return false;
+    }
+  }
+  stack.pop_back();
+  return true;
+}
+
+std::string StructDescriptor::CalculateOffsets(
+    wpi::SmallVectorImpl<const StructDescriptor*>& stack) {
+  size_t offset = 0;
+  unsigned int shift = 0;
+  size_t prevBitfieldSize = 0;
+  for (auto&& field : m_fields) {
+    if (!field.IsBitField()) {
+      [[likely]] shift = 0;        // reset shift on non-bitfield element
+      offset += prevBitfieldSize;  // finish bitfield if active
+      prevBitfieldSize = 0;        // previous is now not bitfield
+      field.m_offset = offset;
+      if (field.m_struct) {
+        if (!field.m_struct->IsValid()) {
+          m_valid = false;
+          [[unlikely]] return {};
+        }
+        field.m_size = field.m_struct->m_size;
+      }
+      offset += field.m_size * field.m_arraySize;
+    } else {
+      if (field.m_type == StructFieldType::kBool && prevBitfieldSize != 0 &&
+          (shift + 1) <= (prevBitfieldSize * 8)) {
+        // bool takes on size of preceding bitfield type (if it fits)
+        field.m_size = prevBitfieldSize;
+      } else if (field.m_size != prevBitfieldSize ||
+                 (shift + field.m_bitWidth) > (field.m_size * 8)) {
+        shift = 0;
+        offset += prevBitfieldSize;
+      }
+      prevBitfieldSize = field.m_size;
+      field.m_offset = offset;
+      field.m_bitShift = shift;
+      shift += field.m_bitWidth;
+    }
+  }
+
+  // update struct size
+  m_size = offset + prevBitfieldSize;
+  m_valid = true;
+
+  // now that we're valid, referring types may be too
+  stack.emplace_back(this);
+  for (auto&& ref : m_references) {
+    if (std::find(stack.begin(), stack.end(), ref) != stack.end()) {
+      [[unlikely]] return fmt::format(
+          "internal error (inconsistent data): circular struct reference "
+          "between {} and {}",
+          m_name, ref->m_name);
+    }
+    auto err = ref->CalculateOffsets(stack);
+    if (!err.empty()) {
+      [[unlikely]] return err;
+    }
+  }
+  stack.pop_back();
+  return {};
+}
+
+const StructDescriptor* StructDescriptorDatabase::Add(std::string_view name,
+                                                      std::string_view schema,
+                                                      std::string* err) {
+  structparser::Parser parser{schema};
+  structparser::ParsedSchema parsed;
+  if (!parser.Parse(&parsed)) {
+    *err = fmt::format("parse error: {}", parser.GetError());
+    [[unlikely]] return nullptr;
+  }
+
+  // turn parsed schema into descriptors
+  auto& theStruct = m_structs[name];
+  if (!theStruct) {
+    theStruct = std::make_unique<StructDescriptor>(
+        name, StructDescriptor::private_init{});
+  }
+  theStruct->m_schema = schema;
+  theStruct->m_fields.clear();
+  theStruct->m_fields.reserve(parsed.declarations.size());
+  bool isValid = true;
+  for (auto&& decl : parsed.declarations) {
+    auto type = TypeStringToType(decl.typeString);
+    size_t size = TypeToSize(type);
+
+    // bitfield checks
+    if (decl.bitWidth != 0) {
+      // only integer or boolean types are allowed
+      if (type == StructFieldType::kChar || type == StructFieldType::kFloat ||
+          type == StructFieldType::kDouble ||
+          type == StructFieldType::kStruct) {
+        *err = fmt::format("field {}: type {} cannot be bitfield", decl.name,
+                           decl.typeString);
+        [[unlikely]] return nullptr;
+      }
+
+      // bit width cannot be larger than field size
+      if (decl.bitWidth > (size * 8)) {
+        *err = fmt::format("field {}: bit width {} exceeds type size",
+                           decl.name, decl.bitWidth);
+        [[unlikely]] return nullptr;
+      }
+
+      // bit width must be 1 for booleans
+      if (type == StructFieldType::kBool && decl.bitWidth != 1) {
+        *err = fmt::format("field {}: bit width must be 1 for bool type",
+                           decl.name);
+        [[unlikely]] return nullptr;
+      }
+
+      // cannot combine array and bitfield (shouldn't parse, but double-check)
+      if (decl.arraySize > 1) {
+        *err = fmt::format("field {}: cannot combine array and bitfield",
+                           decl.name);
+        [[unlikely]] return nullptr;
+      }
+    }
+
+    // struct handling
+    const StructDescriptor* structDesc = nullptr;
+    if (type == StructFieldType::kStruct) {
+      // recursive definitions are not allowed
+      if (decl.typeString == name) {
+        *err = fmt::format("field {}: recursive struct reference", decl.name);
+        [[unlikely]] return nullptr;
+      }
+
+      // cross-reference struct, creating a placeholder if necessary
+      auto& aStruct = m_structs[decl.typeString];
+      if (!aStruct) {
+        aStruct = std::make_unique<StructDescriptor>(
+            decl.typeString, StructDescriptor::private_init{});
+      }
+
+      // if the struct isn't valid, we can't be valid either
+      if (aStruct->IsValid()) {
+        size = aStruct->GetSize();
+      } else {
+        isValid = false;
+      }
+
+      // add to cross-references for when the struct does become valid
+      aStruct->m_references.emplace_back(theStruct.get());
+      structDesc = aStruct.get();
+    }
+
+    // create field
+    if (!theStruct->m_fieldsByName
+             .insert({decl.name, theStruct->m_fields.size()})
+             .second) {
+      *err = fmt::format("duplicate field {}", decl.name);
+      [[unlikely]] return nullptr;
+    }
+
+    theStruct->m_fields.emplace_back(theStruct.get(), decl.name, type, size,
+                                     decl.arraySize, decl.bitWidth,
+                                     std::move(decl.enumValues), structDesc,
+                                     StructFieldDescriptor::private_init{});
+  }
+
+  theStruct->m_valid = isValid;
+  if (isValid) {
+    // we have all the info needed, so calculate field offset & shift
+    wpi::SmallVector<const StructDescriptor*, 16> stack;
+    auto err2 = theStruct->CalculateOffsets(stack);
+    if (!err2.empty()) {
+      *err = std::move(err2);
+      [[unlikely]] return nullptr;
+    }
+  } else {
+    // check for circular reference
+    wpi::SmallVector<const StructDescriptor*, 16> stack;
+    if (!theStruct->CheckCircular(stack)) {
+      wpi::SmallString<128> buf;
+      wpi::raw_svector_ostream os{buf};
+      for (auto&& elem : stack) {
+        if (!buf.empty()) {
+          os << " <- ";
+        }
+        os << elem->GetName();
+      }
+      *err = fmt::format("circular struct reference: {}", os.str());
+      [[unlikely]] return nullptr;
+    }
+  }
+
+  return theStruct.get();
+}
+
+const StructDescriptor* StructDescriptorDatabase::Find(
+    std::string_view name) const {
+  auto it = m_structs.find(name);
+  if (it == m_structs.end()) {
+    return nullptr;
+  }
+  return it->second.get();
+}
+
+uint64_t DynamicStruct::GetFieldImpl(const StructFieldDescriptor* field,
+                                     size_t arrIndex) const {
+  assert(field->m_parent == m_desc);
+  assert(m_desc->IsValid());
+  assert(arrIndex < field->m_arraySize);
+  uint64_t val;
+  switch (field->m_size) {
+    case 1:
+      val = m_data[field->m_offset + arrIndex];
+      break;
+    case 2:
+      val = support::endian::read16le(&m_data[field->m_offset + arrIndex * 2]);
+      break;
+    case 4:
+      val = support::endian::read32le(&m_data[field->m_offset + arrIndex * 4]);
+      break;
+    case 8:
+      val = support::endian::read64le(&m_data[field->m_offset + arrIndex * 8]);
+      break;
+    default:
+      assert(false && "invalid field size");
+      return 0;
+  }
+  return (val >> field->m_bitShift) & field->m_bitMask;
+}
+
+void MutableDynamicStruct::SetData(std::span<const uint8_t> data) {
+  assert(data.size() >= m_desc->GetSize());
+  std::copy(data.begin(), data.begin() + m_desc->GetSize(), m_data.begin());
+}
+
+void MutableDynamicStruct::SetStringField(const StructFieldDescriptor* field,
+                                          std::string_view value) {
+  assert(field->m_type == StructFieldType::kChar);
+  assert(field->m_parent == m_desc);
+  assert(m_desc->IsValid());
+  size_t len = (std::min)(field->m_arraySize, value.size());
+  std::copy(value.begin(), value.begin() + len,
+            reinterpret_cast<char*>(&m_data[field->m_offset]));
+  std::fill(&m_data[field->m_offset + len],
+            &m_data[field->m_offset + field->m_arraySize], 0);
+}
+
+void MutableDynamicStruct::SetStructField(const StructFieldDescriptor* field,
+                                          const DynamicStruct& value,
+                                          size_t arrIndex) {
+  assert(field->m_type == StructFieldType::kStruct);
+  assert(field->m_parent == m_desc);
+  assert(m_desc->IsValid());
+  assert(value.GetDescriptor() == field->m_struct);
+  assert(value.GetDescriptor()->IsValid());
+  assert(arrIndex < field->m_arraySize);
+  auto source = value.GetData();
+  size_t len = field->m_struct->GetSize();
+  std::copy(source.begin(), source.begin() + len,
+            m_data.begin() + field->m_offset + arrIndex * len);
+}
+
+void MutableDynamicStruct::SetFieldImpl(const StructFieldDescriptor* field,
+                                        uint64_t value, size_t arrIndex) {
+  assert(field->m_parent == m_desc);
+  assert(m_desc->IsValid());
+  assert(arrIndex < field->m_arraySize);
+
+  // common case is no bit shift and no masking
+  if (!field->IsBitField()) {
+    switch (field->m_size) {
+      case 1:
+        m_data[field->m_offset + arrIndex] = value;
+        break;
+      case 2:
+        support::endian::write16le(&m_data[field->m_offset + arrIndex * 2],
+                                   value);
+        break;
+      case 4:
+        support::endian::write32le(&m_data[field->m_offset + arrIndex * 4],
+                                   value);
+        break;
+      case 8:
+        support::endian::write64le(&m_data[field->m_offset + arrIndex * 8],
+                                   value);
+        break;
+      default:
+        assert(false && "invalid field size");
+    }
+    return;
+  }
+
+  // handle bit shifting and masking into current value
+  switch (field->m_size) {
+    case 1: {
+      uint8_t* data = &m_data[field->m_offset + arrIndex];
+      *data &= ~(field->m_bitMask << field->m_bitShift);
+      *data |= (value & field->m_bitMask) << field->m_bitShift;
+      break;
+    }
+    case 2: {
+      uint8_t* data = &m_data[field->m_offset + arrIndex * 2];
+      uint16_t val = support::endian::read16le(data);
+      val &= ~(field->m_bitMask << field->m_bitShift);
+      val |= (value & field->m_bitMask) << field->m_bitShift;
+      support::endian::write16le(data, val);
+      break;
+    }
+    case 4: {
+      uint8_t* data = &m_data[field->m_offset + arrIndex * 4];
+      uint32_t val = support::endian::read32le(data);
+      val &= ~(field->m_bitMask << field->m_bitShift);
+      val |= (value & field->m_bitMask) << field->m_bitShift;
+      support::endian::write32le(data, val);
+      break;
+    }
+    case 8: {
+      uint8_t* data = &m_data[field->m_offset + arrIndex * 8];
+      uint64_t val = support::endian::read64le(data);
+      val &= ~(field->m_bitMask << field->m_bitShift);
+      val |= (value & field->m_bitMask) << field->m_bitShift;
+      support::endian::write64le(data, val);
+      break;
+    }
+    default:
+      assert(false && "invalid field size");
+  }
+}
diff --git a/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp b/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp
new file mode 100644
index 0000000..347019e
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp
@@ -0,0 +1,238 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/struct/SchemaParser.h"
+
+#include <fmt/format.h>
+
+#include "wpi/StringExtras.h"
+
+using namespace wpi::structparser;
+
+std::string_view wpi::structparser::ToString(Token::Kind kind) {
+  switch (kind) {
+    case Token::kInteger:
+      return "integer";
+    case Token::kIdentifier:
+      return "identifier";
+    case Token::kLeftBracket:
+      return "'['";
+    case Token::kRightBracket:
+      return "']'";
+    case Token::kLeftBrace:
+      return "'{'";
+    case Token::kRightBrace:
+      return "'}'";
+    case Token::kColon:
+      return "':'";
+    case Token::kSemicolon:
+      return "';'";
+    case Token::kComma:
+      return "','";
+    case Token::kEquals:
+      return "'='";
+    case Token::kEndOfInput:
+      return "<EOF>";
+    default:
+      return "unknown";
+  }
+}
+
+Token Lexer::Scan() {
+  // skip whitespace
+  do {
+    Get();
+  } while (m_current == ' ' || m_current == '\t' || m_current == '\n' ||
+           m_current == '\r');
+  m_tokenStart = m_pos - 1;
+
+  switch (m_current) {
+    case '[':
+      return MakeToken(Token::kLeftBracket);
+    case ']':
+      return MakeToken(Token::kRightBracket);
+    case '{':
+      return MakeToken(Token::kLeftBrace);
+    case '}':
+      return MakeToken(Token::kRightBrace);
+    case ':':
+      return MakeToken(Token::kColon);
+    case ';':
+      return MakeToken(Token::kSemicolon);
+    case ',':
+      return MakeToken(Token::kComma);
+    case '=':
+      return MakeToken(Token::kEquals);
+    case '-':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      return ScanInteger();
+    case -1:
+      return {Token::kEndOfInput, {}};
+    default:
+      if (isAlpha(m_current) || m_current == '_') {
+        [[likely]] return ScanIdentifier();
+      }
+      return MakeToken(Token::kUnknown);
+  }
+}
+
+Token Lexer::ScanInteger() {
+  do {
+    Get();
+  } while (isDigit(m_current));
+  Unget();
+  return MakeToken(Token::kInteger);
+}
+
+Token Lexer::ScanIdentifier() {
+  do {
+    Get();
+  } while (isAlnum(m_current) || m_current == '_');
+  Unget();
+  return MakeToken(Token::kIdentifier);
+}
+
+void Parser::FailExpect(Token::Kind desired) {
+  Fail(fmt::format("expected {}, got '{}'", ToString(desired), m_token.text));
+}
+
+void Parser::Fail(std::string_view msg) {
+  m_error = fmt::format("{}: {}", m_lexer.GetPosition(), msg);
+}
+
+bool Parser::Parse(ParsedSchema* out) {
+  do {
+    GetNextToken();
+    if (m_token.Is(Token::kSemicolon)) {
+      continue;
+    }
+    if (m_token.Is(Token::kEndOfInput)) {
+      break;
+    }
+    if (!ParseDeclaration(&out->declarations.emplace_back())) {
+      [[unlikely]] return false;
+    }
+  } while (m_token.kind != Token::kEndOfInput);
+  return true;
+}
+
+bool Parser::ParseDeclaration(ParsedDeclaration* out) {
+  // optional enum specification
+  if (m_token.Is(Token::kIdentifier) && m_token.text == "enum") {
+    GetNextToken();
+    if (!Expect(Token::kLeftBrace)) {
+      [[unlikely]] return false;
+    }
+    if (!ParseEnum(&out->enumValues)) {
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+  } else if (m_token.Is(Token::kLeftBrace)) {
+    if (!ParseEnum(&out->enumValues)) {
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+  }
+
+  // type name
+  if (!Expect(Token::kIdentifier)) {
+    [[unlikely]] return false;
+  }
+  out->typeString = m_token.text;
+  GetNextToken();
+
+  // identifier name
+  if (!Expect(Token::kIdentifier)) {
+    [[unlikely]] return false;
+  }
+  out->name = m_token.text;
+  GetNextToken();
+
+  // array or bit field
+  if (m_token.Is(Token::kLeftBracket)) {
+    GetNextToken();
+    if (!Expect(Token::kInteger)) {
+      [[unlikely]] return false;
+    }
+    auto val = parse_integer<uint64_t>(m_token.text, 10);
+    if (val && *val > 0) {
+      out->arraySize = *val;
+    } else {
+      Fail(fmt::format("array size '{}' is not a positive integer",
+                       m_token.text));
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+    if (!Expect(Token::kRightBracket)) {
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+  } else if (m_token.Is(Token::kColon)) {
+    GetNextToken();
+    if (!Expect(Token::kInteger)) {
+      [[unlikely]] return false;
+    }
+    auto val = parse_integer<unsigned int>(m_token.text, 10);
+    if (val && *val > 0) {
+      out->bitWidth = *val;
+    } else {
+      Fail(fmt::format("bitfield width '{}' is not a positive integer",
+                       m_token.text));
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+  }
+
+  // declaration must end with EOF or semicolon
+  if (m_token.Is(Token::kEndOfInput)) {
+    return true;
+  }
+  return Expect(Token::kSemicolon);
+}
+
+bool Parser::ParseEnum(EnumValues* out) {
+  // we start with current = '{'
+  GetNextToken();
+  while (!m_token.Is(Token::kRightBrace)) {
+    if (!Expect(Token::kIdentifier)) {
+      [[unlikely]] return false;
+    }
+    std::string name;
+    name = m_token.text;
+    GetNextToken();
+    if (!Expect(Token::kEquals)) {
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+    if (!Expect(Token::kInteger)) {
+      [[unlikely]] return false;
+    }
+    int64_t value;
+    if (auto val = parse_integer<int64_t>(m_token.text, 10)) {
+      value = *val;
+    } else {
+      Fail(fmt::format("could not parse enum value '{}'", m_token.text));
+      [[unlikely]] return false;
+    }
+    out->emplace_back(std::move(name), value);
+    GetNextToken();
+    if (m_token.Is(Token::kRightBrace)) {
+      break;
+    }
+    if (!Expect(Token::kComma)) {
+      [[unlikely]] return false;
+    }
+    GetNextToken();
+  }
+  return true;
+}
diff --git a/wpiutil/src/main/native/cpp/timestamp.cpp b/wpiutil/src/main/native/cpp/timestamp.cpp
index 521197f..c7e2fa9 100644
--- a/wpiutil/src/main/native/cpp/timestamp.cpp
+++ b/wpiutil/src/main/native/cpp/timestamp.cpp
@@ -6,6 +6,25 @@
 
 #include <atomic>
 
+#ifdef __FRC_ROBORIO__
+#include <stdint.h>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#include <FRC_FPGA_ChipObject/RoboRIO_FRC_ChipObject_Aliases.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/nInterfaceGlobals.h>
+#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tHMB.h>
+#include <FRC_NetworkCommunication/LoadOut.h>
+#pragma GCC diagnostic pop
+namespace fpga {
+using namespace nFPGA;
+using namespace nRoboRIO_FPGANamespace;
+}  // namespace fpga
+#include <memory>
+
+#include "dlfcn.h"
+#endif
+
 #ifdef _WIN32
 #include <windows.h>
 
@@ -15,6 +34,85 @@
 #include <chrono>
 #endif
 
+#include <cstdio>
+
+#include <fmt/format.h>
+
+#ifdef __FRC_ROBORIO__
+namespace {
+static constexpr const char hmbName[] = "HMB_0_RAM";
+static constexpr int timestampLowerOffset = 0xF0;
+static constexpr int timestampUpperOffset = 0xF1;
+static constexpr int hmbTimestampOffset = 5;  // 5 us offset
+using NiFpga_CloseHmbFunc = NiFpga_Status (*)(const NiFpga_Session session,
+                                              const char* memoryName);
+using NiFpga_OpenHmbFunc = NiFpga_Status (*)(const NiFpga_Session session,
+                                             const char* memoryName,
+                                             size_t* memorySize,
+                                             void** virtualAddress);
+struct HMBHolder {
+  ~HMBHolder() {
+    if (hmb) {
+      closeHmb(hmb->getSystemInterface()->getHandle(), hmbName);
+      dlclose(niFpga);
+    }
+  }
+  explicit operator bool() const { return hmb != nullptr; }
+  void Configure() {
+    nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
+        nLoadOut::getTargetClass();
+    int32_t status = 0;
+    hmb.reset(fpga::tHMB::create(&status));
+    niFpga = dlopen("libNiFpga.so", RTLD_LAZY);
+    if (!niFpga) {
+      hmb = nullptr;
+      return;
+    }
+    NiFpga_OpenHmbFunc openHmb = reinterpret_cast<NiFpga_OpenHmbFunc>(
+        dlsym(niFpga, "NiFpgaDll_OpenHmb"));
+    closeHmb = reinterpret_cast<NiFpga_CloseHmbFunc>(
+        dlsym(niFpga, "NiFpgaDll_CloseHmb"));
+    if (openHmb == nullptr || closeHmb == nullptr) {
+      closeHmb = nullptr;
+      dlclose(niFpga);
+      hmb = nullptr;
+      return;
+    }
+    size_t hmbBufferSize = 0;
+    status =
+        openHmb(hmb->getSystemInterface()->getHandle(), hmbName, &hmbBufferSize,
+                reinterpret_cast<void**>(const_cast<uint32_t**>(&hmbBuffer)));
+    if (status != 0) {
+      closeHmb = nullptr;
+      dlclose(niFpga);
+      hmb = nullptr;
+      return;
+    }
+    auto cfg = hmb->readConfig(&status);
+    cfg.Enables_Timestamp = 1;
+    hmb->writeConfig(cfg, &status);
+  }
+  void Reset() {
+    if (hmb) {
+      std::unique_ptr<fpga::tHMB> oldHmb;
+      oldHmb.swap(hmb);
+      closeHmb(oldHmb->getSystemInterface()->getHandle(), hmbName);
+      closeHmb = nullptr;
+      hmbBuffer = nullptr;
+      oldHmb.reset();
+      dlclose(niFpga);
+      niFpga = nullptr;
+    }
+  }
+  std::unique_ptr<fpga::tHMB> hmb;
+  void* niFpga = nullptr;
+  NiFpga_CloseHmbFunc closeHmb = nullptr;
+  volatile uint32_t* hmbBuffer = nullptr;
+};
+static HMBHolder hmb;
+}  // namespace
+#endif
+
 // offset in microseconds
 static uint64_t time_since_epoch() noexcept {
 #ifdef _WIN32
@@ -22,7 +120,7 @@
   uint64_t tmpres = 0;
   // 100-nanosecond intervals since January 1, 1601 (UTC)
   // which means 0.1 us
-  GetSystemTimeAsFileTime(&ft);
+  GetSystemTimePreciseAsFileTime(&ft);
   tmpres |= ft.dwHighDateTime;
   tmpres <<= 32;
   tmpres |= ft.dwLowDateTime;
@@ -88,12 +186,56 @@
 
 static std::atomic<uint64_t (*)()> now_impl{wpi::NowDefault};
 
+void wpi::impl::SetupNowRio() {
+#ifdef __FRC_ROBORIO__
+  if (!hmb) {
+    hmb.Configure();
+  }
+#endif
+}
+
+void wpi::impl::ShutdownNowRio() {
+#ifdef __FRC_ROBORIO__
+  hmb.Reset();
+#endif
+}
+
 void wpi::SetNowImpl(uint64_t (*func)(void)) {
   now_impl = func ? func : NowDefault;
 }
 
 uint64_t wpi::Now() {
+#ifdef __FRC_ROBORIO__
+  // Same code as HAL_GetFPGATime()
+  if (!hmb) {
+    std::fputs(
+        "FPGA not yet configured in wpi::Now(). Time will not be correct",
+        stderr);
+    std::fflush(stderr);
+    return 0;
+  }
+
+  asm("dmb");
+  uint64_t upper1 = hmb.hmbBuffer[timestampUpperOffset];
+  asm("dmb");
+  uint32_t lower = hmb.hmbBuffer[timestampLowerOffset];
+  asm("dmb");
+  uint64_t upper2 = hmb.hmbBuffer[timestampUpperOffset];
+
+  if (upper1 != upper2) {
+    // Rolled over between the lower call, reread lower
+    asm("dmb");
+    lower = hmb.hmbBuffer[timestampLowerOffset];
+  }
+  // 5 is added here because the time to write from the FPGA
+  // to the HMB buffer is longer then the time to read
+  // from the time register. This would cause register based
+  // timestamps to be ahead of HMB timestamps, which could
+  // be very bad.
+  return (upper2 << 32) + lower + hmbTimestampOffset;
+#else
   return (now_impl.load())();
+#endif
 }
 
 uint64_t wpi::GetSystemTime() {
@@ -102,6 +244,14 @@
 
 extern "C" {
 
+void WPI_Impl_SetupNowRio(void) {
+  return wpi::impl::SetupNowRio();
+}
+
+void WPI_Impl_ShutdownNowRio(void) {
+  return wpi::impl::ShutdownNowRio();
+}
+
 uint64_t WPI_NowDefault(void) {
   return wpi::NowDefault();
 }
diff --git a/wpiutil/src/main/native/include/wpi/Base64.h b/wpiutil/src/main/native/include/wpi/Base64.h
index c410bd0..858ff73 100644
--- a/wpiutil/src/main/native/include/wpi/Base64.h
+++ b/wpiutil/src/main/native/include/wpi/Base64.h
@@ -5,6 +5,8 @@
 #ifndef WPIUTIL_WPI_BASE64_H_
 #define WPIUTIL_WPI_BASE64_H_
 
+#include <stdint.h>
+
 #include <cstddef>
 #include <span>
 #include <string>
diff --git a/wpiutil/src/main/native/include/wpi/DataLog.h b/wpiutil/src/main/native/include/wpi/DataLog.h
index cac273c..99db964 100644
--- a/wpiutil/src/main/native/include/wpi/DataLog.h
+++ b/wpiutil/src/main/native/include/wpi/DataLog.h
@@ -6,19 +6,42 @@
 
 #include <stdint.h>
 
+#ifdef __cplusplus
+#include <concepts>
 #include <functional>
 #include <initializer_list>
 #include <memory>
+#include <ranges>
 #include <span>
 #include <string>
 #include <string_view>
 #include <thread>
+#include <utility>
 #include <vector>
+#include <version>
 
 #include "wpi/DenseMap.h"
+#include "wpi/SmallVector.h"
 #include "wpi/StringMap.h"
 #include "wpi/condition_variable.h"
 #include "wpi/mutex.h"
+#include "wpi/protobuf/Protobuf.h"
+#include "wpi/struct/Struct.h"
+#include "wpi/timestamp.h"
+#endif  // __cplusplus
+
+/**
+ * A datalog string (for use with string array).
+ */
+struct WPI_DataLog_String {
+  /** Contents. */
+  const char* str;
+
+  /** Length. */
+  size_t len;
+};
+
+#ifdef __cplusplus
 
 namespace wpi {
 class Logger;
@@ -151,11 +174,108 @@
   void Pause();
 
   /**
-   * Resumes appending of data records to the log.
+   * Resumes appending of data records to the log.  If called after Stop(),
+   * opens a new file (with random name if SetFilename was not called after
+   * Stop()) and appends Start records and schema data values for all previously
+   * started entries and schemas.
    */
   void Resume();
 
   /**
+   * Stops appending all records to the log, and closes the log file.
+   */
+  void Stop();
+
+  /**
+   * Returns whether there is a data schema already registered with the given
+   * name.
+   *
+   * @param name Name (the string passed as the data type for records using this
+   *             schema)
+   * @return True if schema already registered
+   */
+  bool HasSchema(std::string_view name) const;
+
+  /**
+   * Registers a data schema.  Data schemas provide information for how a
+   * certain data type string can be decoded.  The type string of a data schema
+   * indicates the type of the schema itself (e.g. "protobuf" for protobuf
+   * schemas, "struct" for struct schemas, etc). In the data log, schemas are
+   * saved just like normal records, with the name being generated from the
+   * provided name: "/.schema/<name>".  Duplicate calls to this function with
+   * the same name are silently ignored.
+   *
+   * @param name Name (the string passed as the data type for records using this
+   *             schema)
+   * @param type Type of schema (e.g. "protobuf", "struct", etc)
+   * @param schema Schema data
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  void AddSchema(std::string_view name, std::string_view type,
+                 std::span<const uint8_t> schema, int64_t timestamp = 0);
+
+  /**
+   * Registers a data schema.  Data schemas provide information for how a
+   * certain data type string can be decoded.  The type string of a data schema
+   * indicates the type of the schema itself (e.g. "protobuf" for protobuf
+   * schemas, "struct" for struct schemas, etc). In the data log, schemas are
+   * saved just like normal records, with the name being generated from the
+   * provided name: "/.schema/<name>".  Duplicate calls to this function with
+   * the same name are silently ignored.
+   *
+   * @param name Name (the string passed as the data type for records using this
+   *             schema)
+   * @param type Type of schema (e.g. "protobuf", "struct", etc)
+   * @param schema Schema data
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  void AddSchema(std::string_view name, std::string_view type,
+                 std::string_view schema, int64_t timestamp = 0) {
+    AddSchema(
+        name, type,
+        std::span<const uint8_t>{
+            reinterpret_cast<const uint8_t*>(schema.data()), schema.size()},
+        timestamp);
+  }
+
+  /**
+   * Registers a protobuf schema. Duplicate calls to this function with the same
+   * name are silently ignored.
+   *
+   * @tparam T protobuf serializable type
+   * @param msg protobuf message
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  template <ProtobufSerializable T>
+  void AddProtobufSchema(ProtobufMessage<T>& msg, int64_t timestamp = 0) {
+    if (timestamp == 0) {
+      timestamp = Now();
+    }
+    msg.ForEachProtobufDescriptor(
+        [this](auto typeString) { return HasSchema(typeString); },
+        [this, timestamp](auto typeString, auto schema) {
+          AddSchema(typeString, "proto:FileDescriptorProto", schema, timestamp);
+        });
+  }
+
+  /**
+   * Registers a struct schema. Duplicate calls to this function with the same
+   * name are silently ignored.
+   *
+   * @tparam T struct serializable type
+   * @param timestamp Time stamp (0 to indicate now)
+   */
+  template <StructSerializable T>
+  void AddStructSchema(int64_t timestamp = 0) {
+    if (timestamp == 0) {
+      timestamp = Now();
+    }
+    ForEachStructSchema<T>([this, timestamp](auto typeString, auto schema) {
+      AddSchema(typeString, "structschema", schema, timestamp);
+    });
+  }
+
+  /**
    * Start an entry.  Duplicate names are allowed (with the same type), and
    * result in the same index being returned (Start/Finish are reference
    * counted).  A duplicate name with a different type will result in an error
@@ -190,64 +310,189 @@
   void SetMetadata(int entry, std::string_view metadata, int64_t timestamp = 0);
 
   /**
-   * Appends a record to the log.
+   * Appends a raw record to the log.
    *
    * @param entry Entry index, as returned by Start()
-   * @param data Data to record
+   * @param data Byte array to record
    * @param timestamp Time stamp (may be 0 to indicate now)
    */
   void AppendRaw(int entry, std::span<const uint8_t> data, int64_t timestamp);
 
   /**
-   * Appends a record to the log.
+   * Appends a raw record to the log.
    *
    * @param entry Entry index, as returned by Start()
-   * @param data Data to record
+   * @param data Byte array to record
    * @param timestamp Time stamp (may be 0 to indicate now)
    */
   void AppendRaw2(int entry, std::span<const std::span<const uint8_t>> data,
                   int64_t timestamp);
 
+  /**
+   * Appends a boolean record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param value Boolean value to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendBoolean(int entry, bool value, int64_t timestamp);
+
+  /**
+   * Appends an integer record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param value Integer value to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendInteger(int entry, int64_t value, int64_t timestamp);
+
+  /**
+   * Appends a float record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param value Float value to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendFloat(int entry, float value, int64_t timestamp);
+
+  /**
+   * Appends a double record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param value Double value to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendDouble(int entry, double value, int64_t timestamp);
+
+  /**
+   * Appends a string record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param value String value to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendString(int entry, std::string_view value, int64_t timestamp);
+
+  /**
+   * Appends a boolean array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr Boolean array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendBooleanArray(int entry, std::span<const bool> arr,
                           int64_t timestamp);
+
+  /**
+   * Appends a boolean array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr Boolean array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendBooleanArray(int entry, std::span<const int> arr,
                           int64_t timestamp);
+
+  /**
+   * Appends a boolean array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr Boolean array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendBooleanArray(int entry, std::span<const uint8_t> arr,
                           int64_t timestamp);
+
+  /**
+   * Appends an integer array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr Integer array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendIntegerArray(int entry, std::span<const int64_t> arr,
                           int64_t timestamp);
+
+  /**
+   * Appends a float array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr Float array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendFloatArray(int entry, std::span<const float> arr,
                         int64_t timestamp);
+
+  /**
+   * Appends a double array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr Double array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendDoubleArray(int entry, std::span<const double> arr,
                          int64_t timestamp);
+
+  /**
+   * Appends a string array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr String array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendStringArray(int entry, std::span<const std::string> arr,
                          int64_t timestamp);
+
+  /**
+   * Appends a string array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr String array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
   void AppendStringArray(int entry, std::span<const std::string_view> arr,
                          int64_t timestamp);
 
+  /**
+   * Appends a string array record to the log.
+   *
+   * @param entry Entry index, as returned by Start()
+   * @param arr String array to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  void AppendStringArray(int entry, std::span<const WPI_DataLog_String> arr,
+                         int64_t timestamp);
+
  private:
+  struct WriterThreadState;
+
+  void StartLogFile(WriterThreadState& state);
   void WriterThreadMain(std::string_view dir);
   void WriterThreadMain(
       std::function<void(std::span<const uint8_t> data)> write);
 
   // must be called with m_mutex held
+  int StartImpl(std::string_view name, std::string_view type,
+                std::string_view metadata, int64_t timestamp);
   uint8_t* StartRecord(uint32_t entry, uint64_t timestamp, uint32_t payloadSize,
                        size_t reserveSize);
   uint8_t* Reserve(size_t size);
   void AppendImpl(std::span<const uint8_t> data);
   void AppendStringImpl(std::string_view str);
+  void AppendStartRecord(int id, std::string_view name, std::string_view type,
+                         std::string_view metadata, int64_t timestamp);
 
   wpi::Logger& m_msglog;
   mutable wpi::mutex m_mutex;
   wpi::condition_variable m_cond;
-  bool m_active{true};
   bool m_doFlush{false};
-  bool m_paused{false};
+  enum State {
+    kStart,
+    kActive,
+    kPaused,
+    kStopped,
+    kShutdown,
+  } m_state = kActive;
   double m_period;
   std::string m_extraHeader;
   std::string m_newFilename;
@@ -256,10 +501,15 @@
   std::vector<Buffer> m_outgoing;
   struct EntryInfo {
     std::string type;
+    std::vector<uint8_t> schemaData;  // only set for schema entries
     int id{0};
   };
   wpi::StringMap<EntryInfo> m_entries;
-  wpi::DenseMap<int, unsigned int> m_entryCounts;
+  struct EntryInfo2 {
+    std::string metadata;
+    unsigned int count;
+  };
+  wpi::DenseMap<int, EntryInfo2> m_entryIds;
   int m_lastId = 0;
   std::thread m_thread;
 };
@@ -693,4 +943,401 @@
   }
 };
 
+/**
+ * Log raw struct serializable objects.
+ */
+template <StructSerializable T>
+class StructLogEntry : public DataLogEntry {
+  using S = Struct<T>;
+
+ public:
+  StructLogEntry() = default;
+  StructLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+      : StructLogEntry{log, name, {}, timestamp} {}
+  StructLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+                 int64_t timestamp = 0) {
+    m_log = &log;
+    log.AddStructSchema<T>(timestamp);
+    m_entry = log.Start(name, S::kTypeString, metadata, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param data Data to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  void Append(const T& data, int64_t timestamp = 0) {
+    uint8_t buf[S::kSize];
+    S::Pack(buf, data);
+    m_log->AppendRaw(m_entry, buf, timestamp);
+  }
+};
+
+/**
+ * Log raw struct serializable array of objects.
+ */
+template <StructSerializable T>
+class StructArrayLogEntry : public DataLogEntry {
+  using S = Struct<T>;
+
+ public:
+  StructArrayLogEntry() = default;
+  StructArrayLogEntry(DataLog& log, std::string_view name,
+                      int64_t timestamp = 0)
+      : StructArrayLogEntry{log, name, {}, timestamp} {}
+  StructArrayLogEntry(DataLog& log, std::string_view name,
+                      std::string_view metadata, int64_t timestamp = 0) {
+    m_log = &log;
+    log.AddStructSchema<T>(timestamp);
+    m_entry =
+        log.Start(name, MakeStructArrayTypeString<T, std::dynamic_extent>(),
+                  metadata, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param data Data to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  template <typename U>
+#if __cpp_lib_ranges >= 201911L
+    requires std::ranges::range<U> &&
+             std::convertible_to<std::ranges::range_value_t<U>, T>
+#endif
+  void Append(U&& data, int64_t timestamp = 0) {
+    m_buf.Write(std::forward<U>(data), [&](auto bytes) {
+      m_log->AppendRaw(m_entry, bytes, timestamp);
+    });
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param data Data to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  void Append(std::span<const T> data, int64_t timestamp = 0) {
+    m_buf.Write(
+        data, [&](auto bytes) { m_log->AppendRaw(m_entry, bytes, timestamp); });
+  }
+
+ private:
+  StructArrayBuffer<T> m_buf;
+};
+
+/**
+ * Log protobuf serializable objects.
+ */
+template <ProtobufSerializable T>
+class ProtobufLogEntry : public DataLogEntry {
+  using P = Protobuf<T>;
+
+ public:
+  ProtobufLogEntry() = default;
+  ProtobufLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+      : ProtobufLogEntry{log, name, {}, timestamp} {}
+  ProtobufLogEntry(DataLog& log, std::string_view name,
+                   std::string_view metadata, int64_t timestamp = 0) {
+    m_log = &log;
+    log.AddProtobufSchema<T>(m_msg, timestamp);
+    m_entry = log.Start(name, m_msg.GetTypeString(), metadata, timestamp);
+  }
+
+  /**
+   * Appends a record to the log.
+   *
+   * @param data Data to record
+   * @param timestamp Time stamp (may be 0 to indicate now)
+   */
+  void Append(const T& data, int64_t timestamp = 0) {
+    SmallVector<uint8_t, 128> buf;
+    {
+      std::scoped_lock lock{m_mutex};
+      m_msg.Pack(buf, data);
+    }
+    m_log->AppendRaw(m_entry, buf, timestamp);
+  }
+
+ private:
+  wpi::mutex m_mutex;
+  ProtobufMessage<T> m_msg;
+};
+
 }  // namespace wpi::log
+
+extern "C" {
+#endif  // __cplusplus
+
+/** C-compatible data log (opaque struct). */
+struct WPI_DataLog;
+
+/**
+ * Construct a new Data Log.  The log will be initially created with a
+ * temporary filename.
+ *
+ * @param dir directory to store the log
+ * @param filename filename to use; if none provided, a random filename is
+ *                 generated of the form "wpilog_{}.wpilog"
+ * @param period time between automatic flushes to disk, in seconds;
+ *               this is a time/storage tradeoff
+ * @param extraHeader extra header data
+ */
+struct WPI_DataLog* WPI_DataLog_Create(const char* dir, const char* filename,
+                                       double period, const char* extraHeader);
+
+/**
+ * Construct a new Data Log that passes its output to the provided function
+ * rather than a file.  The write function will be called on a separate
+ * background thread and may block.  The write function is called with an
+ * empty data array (data=NULL, len=0) when the thread is terminating.
+ *
+ * @param write write function
+ * @param ptr pointer to pass to write function ptr parameter
+ * @param period time between automatic calls to write, in seconds;
+ *               this is a time/storage tradeoff
+ * @param extraHeader extra header data
+ */
+struct WPI_DataLog* WPI_DataLog_Create_Func(
+    void (*write)(void* ptr, const uint8_t* data, size_t len), void* ptr,
+    double period, const char* extraHeader);
+
+/**
+ * Releases a data log object. Closes the file and returns resources to the
+ * system.
+ *
+ * @param datalog data log
+ */
+void WPI_DataLog_Release(struct WPI_DataLog* datalog);
+
+/**
+ * Change log filename.
+ *
+ * @param datalog data log
+ * @param filename filename
+ */
+void WPI_DataLog_SetFilename(struct WPI_DataLog* datalog, const char* filename);
+
+/**
+ * Explicitly flushes the log data to disk.
+ *
+ * @param datalog data log
+ */
+void WPI_DataLog_Flush(struct WPI_DataLog* datalog);
+
+/**
+ * Pauses appending of data records to the log.  While paused, no data records
+ * are saved (e.g. AppendX is a no-op).  Has no effect on entry starts /
+ * finishes / metadata changes.
+ *
+ * @param datalog data log
+ */
+void WPI_DataLog_Pause(struct WPI_DataLog* datalog);
+
+/**
+ * Resumes appending of data records to the log.  If called after Stop(),
+ * opens a new file (with random name if SetFilename was not called after
+ * Stop()) and appends Start records and schema data values for all previously
+ * started entries and schemas.
+ *
+ * @param datalog data log
+ */
+void WPI_DataLog_Resume(struct WPI_DataLog* datalog);
+
+/**
+ * Stops appending all records to the log, and closes the log file.
+ *
+ * @param datalog data log
+ */
+void WPI_DataLog_Stop(struct WPI_DataLog* datalog);
+
+/**
+ * Start an entry.  Duplicate names are allowed (with the same type), and
+ * result in the same index being returned (Start/Finish are reference
+ * counted).  A duplicate name with a different type will result in an error
+ * message being printed to the console and 0 being returned (which will be
+ * ignored by the Append functions).
+ *
+ * @param datalog data log
+ * @param name Name
+ * @param type Data type
+ * @param metadata Initial metadata (e.g. data properties)
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ *
+ * @return Entry index
+ */
+int WPI_DataLog_Start(struct WPI_DataLog* datalog, const char* name,
+                      const char* type, const char* metadata,
+                      int64_t timestamp);
+
+/**
+ * Finish an entry.
+ *
+ * @param datalog data log
+ * @param entry Entry index
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_Finish(struct WPI_DataLog* datalog, int entry,
+                        int64_t timestamp);
+
+/**
+ * Updates the metadata for an entry.
+ *
+ * @param datalog data log
+ * @param entry Entry index
+ * @param metadata New metadata for the entry
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_SetMetadata(struct WPI_DataLog* datalog, int entry,
+                             const char* metadata, int64_t timestamp);
+
+/**
+ * Appends a raw record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param data Byte array to record
+ * @param len Length of byte array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendRaw(struct WPI_DataLog* datalog, int entry,
+                           const uint8_t* data, size_t len, int64_t timestamp);
+
+/**
+ * Appends a boolean record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param value Boolean value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendBoolean(struct WPI_DataLog* datalog, int entry,
+                               int value, int64_t timestamp);
+
+/**
+ * Appends an integer record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param value Integer value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendInteger(struct WPI_DataLog* datalog, int entry,
+                               int64_t value, int64_t timestamp);
+
+/**
+ * Appends a float record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param value Float value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendFloat(struct WPI_DataLog* datalog, int entry,
+                             float value, int64_t timestamp);
+
+/**
+ * Appends a double record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param value Double value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendDouble(struct WPI_DataLog* datalog, int entry,
+                              double value, int64_t timestamp);
+
+/**
+ * Appends a string record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param value String value to record
+ * @param len Length of string
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendString(struct WPI_DataLog* datalog, int entry,
+                              const char* value, size_t len, int64_t timestamp);
+
+/**
+ * Appends a boolean array record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param arr Boolean array to record
+ * @param len Number of elements in array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendBooleanArray(struct WPI_DataLog* datalog, int entry,
+                                    const int* arr, size_t len,
+                                    int64_t timestamp);
+
+/**
+ * Appends a boolean array record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param arr Boolean array to record
+ * @param len Number of elements in array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendBooleanArrayByte(struct WPI_DataLog* datalog, int entry,
+                                        const uint8_t* arr, size_t len,
+                                        int64_t timestamp);
+
+/**
+ * Appends an integer array record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param arr Integer array to record
+ * @param len Number of elements in array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendIntegerArray(struct WPI_DataLog* datalog, int entry,
+                                    const int64_t* arr, size_t len,
+                                    int64_t timestamp);
+
+/**
+ * Appends a float array record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param arr Float array to record
+ * @param len Number of elements in array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendFloatArray(struct WPI_DataLog* datalog, int entry,
+                                  const float* arr, size_t len,
+                                  int64_t timestamp);
+
+/**
+ * Appends a double array record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param arr Double array to record
+ * @param len Number of elements in array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendDoubleArray(struct WPI_DataLog* datalog, int entry,
+                                   const double* arr, size_t len,
+                                   int64_t timestamp);
+
+/**
+ * Appends a string array record to the log.
+ *
+ * @param datalog data log
+ * @param entry Entry index, as returned by WPI_DataLog_Start()
+ * @param arr String array to record
+ * @param len Number of elements in array
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+void WPI_DataLog_AppendStringArray(struct WPI_DataLog* datalog, int entry,
+                                   const WPI_DataLog_String* arr, size_t len,
+                                   int64_t timestamp);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
diff --git a/wpiutil/src/main/native/include/wpi/DecayedDerivedFrom.h b/wpiutil/src/main/native/include/wpi/DecayedDerivedFrom.h
new file mode 100644
index 0000000..c776c9c
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/DecayedDerivedFrom.h
@@ -0,0 +1,17 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <concepts>
+#include <type_traits>
+
+namespace wpi {
+
+template <class Derived, class Base>
+concept DecayedDerivedFrom =
+    std::derived_from<std::decay_t<Derived>, std::decay_t<Base>> &&
+    std::convertible_to<std::decay_t<Derived>*, std::decay_t<Base>*>;
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/Logger.h b/wpiutil/src/main/native/include/wpi/Logger.h
index 883336f..01a02fd 100644
--- a/wpiutil/src/main/native/include/wpi/Logger.h
+++ b/wpiutil/src/main/native/include/wpi/Logger.h
@@ -8,7 +8,7 @@
 #include <functional>
 #include <utility>
 
-#include "fmt/format.h"
+#include <fmt/format.h>
 
 namespace wpi {
 
@@ -79,24 +79,6 @@
   WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, format __VA_OPT__(, ) __VA_ARGS__)
 #define WPI_INFO(inst, format, ...) \
   WPI_LOG(inst, ::wpi::WPI_LOG_INFO, format __VA_OPT__(, ) __VA_ARGS__)
-
-#ifdef NDEBUG
-#define WPI_DEBUG(inst, format, ...) \
-  do {                               \
-  } while (0)
-#define WPI_DEBUG1(inst, format, ...) \
-  do {                                \
-  } while (0)
-#define WPI_DEBUG2(inst, format, ...) \
-  do {                                \
-  } while (0)
-#define WPI_DEBUG3(inst, format, ...) \
-  do {                                \
-  } while (0)
-#define WPI_DEBUG4(inst, format, ...) \
-  do {                                \
-  } while (0)
-#else
 #define WPI_DEBUG(inst, format, ...) \
   WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, format __VA_OPT__(, ) __VA_ARGS__)
 #define WPI_DEBUG1(inst, format, ...) \
@@ -107,7 +89,6 @@
   WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, format __VA_OPT__(, ) __VA_ARGS__)
 #define WPI_DEBUG4(inst, format, ...) \
   WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, format __VA_OPT__(, ) __VA_ARGS__)
-#endif
 
 }  // namespace wpi
 
diff --git a/wpiutil/src/main/native/include/wpi/MappedFileRegion.h b/wpiutil/src/main/native/include/wpi/MappedFileRegion.h
index 05e487e..33d3bb9 100644
--- a/wpiutil/src/main/native/include/wpi/MappedFileRegion.h
+++ b/wpiutil/src/main/native/include/wpi/MappedFileRegion.h
@@ -59,19 +59,13 @@
     return *this;
   }
 
-  explicit operator bool() const {
-    return m_mapping != nullptr;
-  }
+  explicit operator bool() const { return m_mapping != nullptr; }
 
   void Flush();
   void Unmap();
 
-  uint64_t size() const {
-    return m_size;
-  }
-  uint8_t* data() const {
-    return static_cast<uint8_t*>(m_mapping);
-  }
+  uint64_t size() const { return m_size; }
+  uint8_t* data() const { return static_cast<uint8_t*>(m_mapping); }
   const uint8_t* const_data() const {
     return static_cast<const uint8_t*>(m_mapping);
   }
diff --git a/wpiutil/src/main/native/include/wpi/SpanExtras.h b/wpiutil/src/main/native/include/wpi/SpanExtras.h
index aa7b9ab..790a66f 100644
--- a/wpiutil/src/main/native/include/wpi/SpanExtras.h
+++ b/wpiutil/src/main/native/include/wpi/SpanExtras.h
@@ -10,19 +10,49 @@
 namespace wpi {
 
 /// Drop the first \p N elements of the array.
-template <typename T>
-constexpr std::span<T> drop_front(std::span<T> in,
+template <typename T, size_t N>
+constexpr std::span<T> drop_front(std::span<T, N> in,
                                   typename std::span<T>::size_type n = 1) {
   assert(in.size() >= n && "Dropping more elements than exist");
   return in.subspan(n, in.size() - n);
 }
 
 /// Drop the last \p N elements of the array.
-template <typename T>
-constexpr std::span<T> drop_back(std::span<T> in,
+template <typename T, size_t N>
+constexpr std::span<T> drop_back(std::span<T, N> in,
                                  typename std::span<T>::size_type n = 1) {
   assert(in.size() >= n && "Dropping more elements than exist");
   return in.subspan(0, in.size() - n);
 }
 
+/**
+ * Returns a span equal to @p in but with only the first @p n
+ * elements remaining.  If @p n is greater than the length of the
+ * span, the entire span is returned.
+ */
+template <typename T, size_t N>
+constexpr std::span<T> take_front(std::span<T, N> in,
+                                  typename std::span<T>::size_type n = 1) {
+  auto length = in.size();
+  if (n >= length) {
+    return in;
+  }
+  return drop_back(in, length - n);
+}
+
+/**
+ * Returns a span equal to @p in but with only the last @p n
+ * elements remaining.  If @p n is greater than the length of the
+ * span, the entire span is returned.
+ */
+template <typename T, size_t N>
+constexpr std::span<T> take_back(std::span<T, N> in,
+                                 typename std::span<T>::size_type n = 1) {
+  auto length = in.size();
+  if (n >= length) {
+    return in;
+  }
+  return drop_front(in, length - n);
+}
+
 }  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/SymbolExports.h b/wpiutil/src/main/native/include/wpi/SymbolExports.h
index 9ffc936..41495ad 100644
--- a/wpiutil/src/main/native/include/wpi/SymbolExports.h
+++ b/wpiutil/src/main/native/include/wpi/SymbolExports.h
@@ -5,7 +5,9 @@
 #pragma once
 
 #ifdef _WIN32
+#ifdef _MSC_VER
 #pragma warning(disable : 4251)
+#endif
 
 #ifdef WPILIB_EXPORTS
 #ifdef __GNUC__
diff --git a/wpiutil/src/main/native/include/wpi/Synchronization.h b/wpiutil/src/main/native/include/wpi/Synchronization.h
index 4ac3c8c..62a79ef 100644
--- a/wpiutil/src/main/native/include/wpi/Synchronization.h
+++ b/wpiutil/src/main/native/include/wpi/Synchronization.h
@@ -209,10 +209,9 @@
  * Sets up signaling for an arbitrary handle.  With this function, any handle
  * can operate like an event handle.
  *
- * @param handle handle
+ * @param handle Event handle
  * @param manualReset true for manual reset, false for automatic reset
  * @param initialState true to make the handle initially in signaled state
- * @return Event handle
  */
 void CreateSignalObject(WPI_Handle handle, bool manualReset = false,
                         bool initialState = false);
diff --git a/wpiutil/src/main/native/include/wpi/array.h b/wpiutil/src/main/native/include/wpi/array.h
index cfbb7b0..d6711f1 100644
--- a/wpiutil/src/main/native/include/wpi/array.h
+++ b/wpiutil/src/main/native/include/wpi/array.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <array>
+#include <concepts>
 #include <cstddef>
 #include <tuple>
 #include <utility>
@@ -26,11 +27,10 @@
  public:
   constexpr explicit array(empty_array_t) {}
 
-  template <typename... Ts>
+  template <std::convertible_to<T>... Ts>
+    requires(1 + sizeof...(Ts) == N)
   constexpr array(T arg, Ts&&... args)  // NOLINT
-      : std::array<T, N>{std::forward<T>(arg), std::forward<Ts>(args)...} {
-    static_assert(1 + sizeof...(args) == N, "Dimension mismatch");
-  }
+      : std::array<T, N>{std::forward<T>(arg), std::forward<Ts>(args)...} {}
 
   constexpr array(const array<T, N>&) = default;
   constexpr array& operator=(const array<T, N>&) = default;
@@ -56,33 +56,32 @@
   }
 };
 
-template <typename T, typename... Ts>
-array(T, Ts...) -> array<std::enable_if_t<(std::is_same_v<T, Ts> && ...), T>,
-                         1 + sizeof...(Ts)>;
+template <typename T, std::convertible_to<T>... Ts>
+array(T, Ts...) -> array<T, 1 + sizeof...(Ts)>;
 
 }  // namespace wpi
 
 template <size_t I, typename T, size_t N>
+  requires(I < N)
 constexpr T& get(wpi::array<T, N>& arr) noexcept {
-  static_assert(I < N, "array index is within bounds");
   return std::get<I>(static_cast<std::array<T, N>>(arr));
 }
 
 template <size_t I, typename T, size_t N>
+  requires(I < N)
 constexpr T&& get(wpi::array<T, N>&& arr) noexcept {
-  static_assert(I < N, "array index is within bounds");
   return std::move(std::get<I>(arr));
 }
 
 template <size_t I, typename T, size_t N>
+  requires(I < N)
 constexpr const T& get(const wpi::array<T, N>& arr) noexcept {
-  static_assert(I < N, "array index is within bounds");
   return std::get<I>(static_cast<std::array<T, N>>(arr));
 }
 
 template <size_t I, typename T, size_t N>
+  requires(I < N)
 constexpr const T&& get(const wpi::array<T, N>&& arr) noexcept {
-  static_assert(I < N, "array index is within bounds");
   return std::move(std::get<I>(arr));
 }
 
@@ -94,8 +93,8 @@
 
 // Partial specialization for wpi::array
 template <size_t I, typename T, size_t N>
+  requires(I < N)
 struct tuple_element<I, wpi::array<T, N>> {
-  static_assert(I < N, "index is out of bounds");
   using type = T;
 };
 }  // namespace std
diff --git a/wpiutil/src/main/native/include/wpi/ct_string.h b/wpiutil/src/main/native/include/wpi/ct_string.h
new file mode 100644
index 0000000..9f0ef90
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/ct_string.h
@@ -0,0 +1,168 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <array>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <string_view>
+
+namespace wpi {
+
+// derived from:
+// https://codereview.stackexchange.com/questions/282514/string-literals-concatenation-with-support-for-dynamic-strings
+
+/**
+ * Fixed length string (array of character) for compile time use.
+ *
+ * @tparam N number of characters
+ * @tparam Char character type
+ * @tparam Traits character traits
+ */
+template <typename Char, typename Traits, size_t N>
+  requires(N < (std::numeric_limits<size_t>::max)())
+struct ct_string {
+  std::array<Char, N + 1> chars;
+
+  template <size_t M>
+    requires(M <= (N + 1))
+  consteval ct_string(Char const (&s)[M]) {  // NOLINT
+    if constexpr (M == (N + 1)) {
+      if (s[N] != Char{}) {
+        throw std::logic_error{"char array not null terminated"};
+      }
+    }
+
+    // avoid dependency on <algorithm>
+    // auto p = std::ranges::copy(s, chars.begin()).out;
+    auto p = chars.begin();
+    for (auto c : s) {
+      *p++ = c;
+    }
+    // std::ranges::fill() isn't constexpr on GCC 11
+    while (p != chars.end()) {
+      *p++ = Char{};
+    }
+  }
+
+  explicit consteval ct_string(std::basic_string_view<Char, Traits> s) {
+    // avoid dependency on <algorithm>
+    // auto p = std::ranges::copy(s, chars.begin()).out;
+    auto p = chars.begin();
+    for (auto c : s) {
+      *p++ = c;
+    }
+    // std::ranges::fill() isn't constexpr on GCC 11
+    while (p != chars.end()) {
+      *p++ = Char{};
+    }
+  }
+
+  constexpr auto size() const noexcept { return N; }
+
+  constexpr auto begin() const noexcept { return chars.begin(); }
+  constexpr auto end() const noexcept { return chars.begin() + N; }
+
+  constexpr auto data() const noexcept { return chars.data(); }
+  constexpr auto c_str() const noexcept { return chars.data(); }
+
+  constexpr operator std::basic_string_view<Char, Traits>()  // NOLINT
+      const noexcept {
+    return std::basic_string_view<Char, Traits>{chars.data(), N};
+  }
+};
+
+template <typename Char, size_t M>
+ct_string(Char const (&s)[M]) -> ct_string<Char, std::char_traits<Char>, M - 1>;
+
+inline namespace literals {
+template <ct_string S>
+consteval auto operator""_ct_string() {
+  return S;
+}
+}  // namespace literals
+
+template <typename Char, typename Traits, size_t N1, size_t N2>
+consteval auto operator+(ct_string<Char, Traits, N1> const& s1,
+                         ct_string<Char, Traits, N2> const& s2) noexcept {
+  return Concat(s1, s2);
+}
+
+/**
+ * Concatenates multiple fixed_strings into a larger fixed_string at compile
+ * time.
+ *
+ * @param s1 first string
+ * @param s second and later strings
+ * @return concatenated string
+ */
+template <typename Char, typename Traits, size_t N1, size_t... N>
+consteval auto Concat(ct_string<Char, Traits, N1> const& s1,
+                      ct_string<Char, Traits, N> const&... s) {
+  // Need a dummy array to instantiate a ct_string.
+  constexpr Char dummy[1] = {};
+  auto res = ct_string<Char, Traits, (N1 + ... + N)>{dummy};
+
+  auto p = res.chars.begin();
+  auto append = [&p](auto&& s) {
+    // avoid dependency on <algorithm>
+    // p = std::ranges::copy(s, p).out;
+    for (auto c : s) {
+      *p++ = c;
+    }
+  };
+
+  (append(s1), ..., append(s));
+
+  return res;
+}
+
+// derived from:
+// https://github.com/tcsullivan/constexpr-to-string/blob/master/to_string.hpp
+
+/**
+ * Converts any integral to a ct_string at compile-time.
+ *
+ * @tparam N number to convert
+ * @tparam Base desired base, can be from 2 to 36
+ * @tparam Char character type
+ * @tparam Traits character traits
+ */
+template <intmax_t N, int Base = 10, typename Char = char,
+          typename Traits = std::char_traits<Char>>
+  requires(Base >= 2 && Base <= 36)
+consteval auto NumToCtString() {
+  constexpr char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  auto buflen = [] {
+    size_t len = N > 0 ? 0 : 1;
+    for (auto n = N; n; len++, n /= Base) {
+    }
+    return len;
+  };
+  constexpr size_t size = buflen();
+
+  constexpr Char dummy[1] = {};
+  auto res = ct_string<Char, Traits, size>{dummy};
+
+  auto ptr = res.chars.data() + size;
+  if (N != 0) {
+    for (auto n = N; n; n /= Base) {
+      *--ptr = digits[(N < 0 ? -1 : 1) * (n % Base)];
+    }
+    if (N < 0) {
+      *--ptr = '-';
+    }
+  } else {
+    res.chars[0] = '0';
+  }
+
+  return res;
+}
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/deprecated.h b/wpiutil/src/main/native/include/wpi/deprecated.h
index c5b4af2..ccd6bba 100644
--- a/wpiutil/src/main/native/include/wpi/deprecated.h
+++ b/wpiutil/src/main/native/include/wpi/deprecated.h
@@ -16,6 +16,8 @@
       _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
 #elif defined(_WIN32)
 #define WPI_IGNORE_DEPRECATED _Pragma("warning(disable : 4996)")
+#else
+#define WPI_IGNORE_DEPRECATED
 #endif
 
 #endif
@@ -25,6 +27,8 @@
 #define WPI_UNIGNORE_DEPRECATED _Pragma("GCC diagnostic pop")
 #elif defined(_WIN32)
 #define WPI_UNIGNORE_DEPRECATED _Pragma("warning(default : 4996)")
+#else
+#define WPI_UNIGNORE_DEPRECATED
 #endif
 #endif
 
diff --git a/wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h b/wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
index 024e04c..6177859 100644
--- a/wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
+++ b/wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
@@ -5,7 +5,8 @@
 #ifndef WPIUTIL_WPI_FMT_RAW_OSTREAM_H_
 #define WPIUTIL_WPI_FMT_RAW_OSTREAM_H_
 
-#include "fmt/format.h"
+#include <fmt/format.h>
+
 #include "wpi/raw_ostream.h"
 
 FMT_BEGIN_NAMESPACE
diff --git a/wpiutil/src/main/native/include/wpi/fs.h b/wpiutil/src/main/native/include/wpi/fs.h
index 587a23c..47de1d5 100644
--- a/wpiutil/src/main/native/include/wpi/fs.h
+++ b/wpiutil/src/main/native/include/wpi/fs.h
@@ -13,43 +13,17 @@
 
 #pragma once
 
+#include <filesystem>
+#include <fstream>
 #include <string_view>
 #include <system_error>
 
-#if defined(__APPLE__)
-#include <Availability.h>
-#endif
-#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) \
-     || (defined(__cplusplus) && __cplusplus >= 201703L)) \
-    && defined(__has_include)
-#if __has_include(<filesystem>) \
-    && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
-        || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) \
-    && (defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 10 \
-        || (__GNUC__ >= 9 && __GNUC_MINOR__ >= 1))
-#define GHC_USE_STD_FS
-#include <filesystem>
 namespace fs {
+
 using namespace std::filesystem;
 using ifstream = std::ifstream;
 using ofstream = std::ofstream;
 using fstream = std::fstream;
-}  // namespace fs
-#endif
-#endif
-#ifndef GHC_USE_STD_FS
-// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
-#define GHC_FILESYSTEM_FWD
-#include "wpi/ghc/filesystem.hpp"
-namespace fs {
-using namespace ghc::filesystem;
-using ifstream = ghc::filesystem::ifstream;
-using ofstream = ghc::filesystem::ofstream;
-using fstream = ghc::filesystem::fstream;
-}  // namespace fs
-#endif
-
-namespace fs {
 
 #if defined(_WIN32)
 // A Win32 HANDLE is a typedef of void*
diff --git a/wpiutil/src/main/native/include/wpi/jni_util.h b/wpiutil/src/main/native/include/wpi/jni_util.h
index 8d50fdd..31bdf93 100644
--- a/wpiutil/src/main/native/include/wpi/jni_util.h
+++ b/wpiutil/src/main/native/include/wpi/jni_util.h
@@ -7,14 +7,16 @@
 
 #include <jni.h>
 
+#include <concepts>
 #include <queue>
 #include <span>
 #include <string>
 #include <string_view>
-#include <type_traits>
 #include <utility>
 #include <vector>
 
+#include <fmt/core.h>
+
 #include "wpi/ConvertUTF.h"
 #include "wpi/SafeThread.h"
 #include "wpi/SmallString.h"
@@ -158,8 +160,8 @@
         env->ReleaseStringCritical(str, chars);
       }
     } else {
-      errs() << "JStringRef was passed a null pointer at \n"
-             << GetJavaStackTrace(env);
+      fmt::print(stderr, "JStringRef was passed a null pointer at\n",
+                 GetJavaStackTrace(env));
     }
     // Ensure str is null-terminated.
     m_str.push_back('\0');
@@ -175,208 +177,242 @@
   SmallString<128> m_str;
 };
 
-// Details for J*ArrayRef and CriticalJ*ArrayRef
 namespace detail {
 
-template <typename C, typename T>
-class JArrayRefInner {
+template <typename T>
+struct ArrayHelper {};
+
+#define WPI_JNI_ARRAYHELPER(T, F)                                             \
+  template <>                                                                 \
+  struct ArrayHelper<T> {                                                     \
+    using jarray_type = T##Array;                                             \
+    static T* GetArrayElements(JNIEnv* env, jarray_type jarr) {               \
+      return env->Get##F##ArrayElements(jarr, nullptr);                       \
+    }                                                                         \
+    static void ReleaseArrayElements(JNIEnv* env, jarray_type jarr, T* elems, \
+                                     jint mode) {                             \
+      env->Release##F##ArrayElements(jarr, elems, mode);                      \
+    }                                                                         \
+  };
+
+WPI_JNI_ARRAYHELPER(jboolean, Boolean)
+WPI_JNI_ARRAYHELPER(jbyte, Byte)
+WPI_JNI_ARRAYHELPER(jshort, Short)
+WPI_JNI_ARRAYHELPER(jint, Int)
+WPI_JNI_ARRAYHELPER(jlong, Long)
+WPI_JNI_ARRAYHELPER(jfloat, Float)
+WPI_JNI_ARRAYHELPER(jdouble, Double)
+
+#undef WPI_JNI_ARRAYHELPER
+
+template <typename T>
+concept JArrayType =
+    requires { typename ArrayHelper<std::remove_cv_t<T>>::jarray_type; };
+
+template <typename CvSrc, typename Dest>
+struct copy_cv {
+ private:
+  using U0 = std::remove_cv_t<Dest>;
+  using U1 = std::conditional_t<std::is_const_v<CvSrc>, const U0, U0>;
+  using U2 = std::conditional_t<std::is_volatile_v<CvSrc>, volatile U1, U1>;
+
  public:
-  operator std::span<const T>() const {  // NOLINT
-    return static_cast<const C*>(this)->array();
-  }
+  using type = U2;
 };
 
-/**
- * Specialization of JArrayRefBase to provide std::string_view conversion
- * and span<const uint8_t> conversion.
- */
-template <typename C>
-class JArrayRefInner<C, jbyte> {
- public:
-  operator std::string_view() const { return str(); }
+template <typename CvSrc, typename Dest>
+using copy_cv_t = typename copy_cv<CvSrc, Dest>::type;
 
-  std::string_view str() const {
-    auto arr = static_cast<const C*>(this)->array();
+template <typename From, typename To>
+constexpr bool is_qualification_convertible_v =
+    !(std::is_const_v<From> && !std::is_const_v<To>)&&!(
+        std::is_volatile_v<From> && !std::is_volatile_v<To>);
+
+/**
+ * Helper class for working with JNI arrays.
+ *
+ * This class exposes an is_valid() member and an explicit conversion to bool
+ * which indicate if the span is valid. Operations on invalid spans are
+ * undefined.
+ *
+ * Note that Set<PrimitiveType>ArrayRegion may be faster for pure writes since
+ * it avoids copying the elements from Java to C++.
+ *
+ * @tparam T The element type of the array (e.g., jdouble).
+ * @tparam IsCritical If true, Get/ReleasePrimitiveArrayCritical will be used
+ * instead of Get/Release\<PrimitiveType\>ArrayElements.
+ * @tparam Size The number of elements in the span.
+ */
+template <JArrayType T, bool IsCritical, size_t Size = std::dynamic_extent>
+class JSpanBase {
+  using ArrHelper = ArrayHelper<std::remove_cv_t<T>>;
+  using jarray_type = typename ArrHelper::jarray_type;
+
+ public:
+  JSpanBase(const JSpanBase&) = delete;
+  JSpanBase& operator=(const JSpanBase&) = delete;
+
+  JSpanBase(JSpanBase&& other)
+      : m_valid{other.m_valid},
+        m_env{other.m_env},
+        m_jarr{other.m_jarr},
+        m_size{other.m_size},
+        m_elements{other.m_elements} {
+    other.m_jarr = nullptr;
+    other.m_elements = nullptr;
+  }
+
+  JSpanBase& operator=(JSpanBase&& other) {
+    m_valid = other.m_valid;
+    m_env = other.m_env;
+    m_jarr = other.m_jarr;
+    m_size = other.m_size;
+    m_elements = other.m_elements;
+    other.m_valid = false;
+    other.m_jarr = nullptr;
+    other.m_elements = nullptr;
+    return *this;
+  }
+
+  JSpanBase(JNIEnv* env, jobject bb, size_t size)
+    requires(!IsCritical)
+      : m_valid{Size == std::dynamic_extent || size == Size},
+        m_env{env},
+        m_jarr{nullptr},
+        m_size{size},
+        m_elements{static_cast<std::remove_cv_t<T>*>(
+            bb ? env->GetDirectBufferAddress(bb) : nullptr)} {
+    if (!bb) {
+      fmt::print(stderr, "JSpan was passed a null pointer at\n",
+                 GetJavaStackTrace(env));
+    }
+  }
+
+  JSpanBase(JNIEnv* env, jarray_type jarr, size_t size)
+      : m_valid{Size == std::dynamic_extent || size == Size},
+        m_env{env},
+        m_jarr{jarr},
+        m_size{size},
+        m_elements{nullptr} {
+    if (jarr) {
+      if constexpr (IsCritical) {
+        m_elements = static_cast<std::remove_cv_t<T>*>(
+            env->GetPrimitiveArrayCritical(jarr, nullptr));
+      } else {
+        m_elements = ArrHelper::GetArrayElements(env, jarr);
+      }
+    } else {
+      fmt::print(stderr, "JSpan was passed a null pointer at\n",
+                 GetJavaStackTrace(env));
+    }
+  }
+
+  JSpanBase(JNIEnv* env, jarray_type jarr)
+      : JSpanBase(env, jarr, jarr ? env->GetArrayLength(jarr) : 0) {}
+
+  ~JSpanBase() {
+    if (m_jarr && m_elements) {
+      constexpr jint mode = std::is_const_v<T> ? JNI_ABORT : 0;
+      if constexpr (IsCritical) {
+        m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, mode);
+      } else {
+        ArrHelper::ReleaseArrayElements(m_env, m_jarr, m_elements, mode);
+      }
+    }
+  }
+
+  operator std::span<T, Size>() const { return array(); }
+
+  std::span<T, Size> array() const {
+    // If Size is dynamic_extent, can return empty span
+    // Unfortunately, sized spans will return a span over nullptr if m_elements
+    // is nullptr
+    if constexpr (Size == std::dynamic_extent) {
+      if (!m_elements) {
+        return {};
+      }
+    }
+    return std::span<T, Size>{m_elements, m_size};
+  }
+
+  T* begin() const { return m_elements; }
+
+  T* end() const { return m_elements + m_size; }
+
+  bool is_valid() const { return m_valid && m_elements != nullptr; }
+
+  explicit operator bool() const { return is_valid(); }
+
+  T* data() const { return m_elements; }
+
+  size_t size() const { return m_size; }
+
+  const T& operator[](size_t i) const { return m_elements[i]; }
+
+  T& operator[](size_t i)
+    requires(!std::is_const_v<T>)
+  {
+    return m_elements[i];
+  }
+
+  // Provide std::string_view and span<const uint8_t> conversions for jbyte
+
+  operator std::string_view() const
+    requires std::is_same_v<std::remove_cv_t<T>, jbyte>
+  {
+    return str();
+  }
+
+  std::string_view str() const
+    requires std::is_same_v<std::remove_cv_t<T>, jbyte>
+  {
+    auto arr = array();
     if (arr.empty()) {
       return {};
     }
     return {reinterpret_cast<const char*>(arr.data()), arr.size()};
   }
 
-  std::span<const uint8_t> uarray() const {
-    auto arr = static_cast<const C*>(this)->array();
+  std::span<copy_cv_t<T, uint8_t>, Size> uarray() const
+    requires std::is_same_v<std::remove_cv_t<T>, jbyte>
+  {
+    auto arr = array();
     if (arr.empty()) {
       return {};
     }
     return {reinterpret_cast<const uint8_t*>(arr.data()), arr.size()};
   }
-};
 
-/**
- * Specialization of JArrayRefBase to handle both "long long" and "long" on
- * 64-bit systems.
- */
-template <typename C>
-class JArrayRefInner<C, jlong> {
- public:
-  template <typename U,
-            typename = std::enable_if_t<sizeof(U) == sizeof(jlong) &&
-                                        std::is_integral_v<U>>>
-  operator std::span<const U>() const {  // NOLINT
-    auto arr = static_cast<const C*>(this)->array();
+  // Support both "long long" and "long" on 64-bit systems
+
+  template <typename U>
+    requires(sizeof(U) == sizeof(jlong) && std::integral<U> &&
+             is_qualification_convertible_v<T, U>)
+  operator std::span<U, Size>() const
+    requires std::is_same_v<std::remove_cv_t<T>, jlong>
+  {
+    auto arr = array();
     if (arr.empty()) {
       return {};
     }
-    return {reinterpret_cast<const U*>(arr.data()), arr.size()};
-  }
-};
-
-/**
- * Base class for J*ArrayRef and CriticalJ*ArrayRef
- */
-template <typename T>
-class JArrayRefBase : public JArrayRefInner<JArrayRefBase<T>, T> {
- public:
-  explicit operator bool() const { return this->m_elements != nullptr; }
-
-  std::span<const T> array() const {
-    if (!this->m_elements) {
-      return {};
-    }
-    return {this->m_elements, this->m_size};
+    return {reinterpret_cast<U*>(arr.data()), arr.size()};
   }
 
-  size_t size() const { return this->m_size; }
-  T& operator[](size_t i) { return this->m_elements[i]; }
-  const T& operator[](size_t i) const { return this->m_elements[i]; }
-
-  JArrayRefBase(const JArrayRefBase&) = delete;
-  JArrayRefBase& operator=(const JArrayRefBase&) = delete;
-
-  JArrayRefBase(JArrayRefBase&& oth)
-      : m_env(oth.m_env),
-        m_jarr(oth.m_jarr),
-        m_size(oth.m_size),
-        m_elements(oth.m_elements) {
-    oth.m_jarr = nullptr;
-    oth.m_elements = nullptr;
-  }
-
-  JArrayRefBase& operator=(JArrayRefBase&& oth) {
-    this->m_env = oth.m_env;
-    this->m_jarr = oth.m_jarr;
-    this->m_size = oth.m_size;
-    this->m_elements = oth.m_elements;
-    oth.m_jarr = nullptr;
-    oth.m_elements = nullptr;
-    return *this;
-  }
-
- protected:
-  JArrayRefBase(JNIEnv* env, T* elements, size_t size) {
-    this->m_env = env;
-    this->m_jarr = nullptr;
-    this->m_size = size;
-    this->m_elements = elements;
-  }
-
-  JArrayRefBase(JNIEnv* env, jarray jarr, size_t size) {
-    this->m_env = env;
-    this->m_jarr = jarr;
-    this->m_size = size;
-    this->m_elements = nullptr;
-  }
-
-  JArrayRefBase(JNIEnv* env, jarray jarr)
-      : JArrayRefBase(env, jarr, jarr ? env->GetArrayLength(jarr) : 0) {}
-
+ private:
+  bool m_valid;
   JNIEnv* m_env;
-  jarray m_jarr = nullptr;
+  jarray_type m_jarr = nullptr;
   size_t m_size;
-  T* m_elements;
+  std::remove_cv_t<T>* m_elements;
 };
 
 }  // namespace detail
 
-// Java array / DirectBuffer reference.
+template <typename T, size_t Extent = std::dynamic_extent>
+using JSpan = detail::JSpanBase<T, false, Extent>;
 
-#define WPI_JNI_JARRAYREF(T, F)                                                \
-  class J##F##ArrayRef : public detail::JArrayRefBase<T> {                     \
-   public:                                                                     \
-    J##F##ArrayRef(JNIEnv* env, jobject bb, int len)                           \
-        : detail::JArrayRefBase<T>(                                            \
-              env,                                                             \
-              static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \
-              len) {                                                           \
-      if (!bb) {                                                               \
-        errs() << "JArrayRef was passed a null pointer at \n"                  \
-               << GetJavaStackTrace(env);                                      \
-      }                                                                        \
-    }                                                                          \
-    J##F##ArrayRef(JNIEnv* env, T##Array jarr, int len)                        \
-        : detail::JArrayRefBase<T>(env, jarr, len) {                           \
-      if (jarr) {                                                              \
-        m_elements = env->Get##F##ArrayElements(jarr, nullptr);                \
-      } else {                                                                 \
-        errs() << "JArrayRef was passed a null pointer at \n"                  \
-               << GetJavaStackTrace(env);                                      \
-      }                                                                        \
-    }                                                                          \
-    J##F##ArrayRef(JNIEnv* env, T##Array jarr)                                 \
-        : detail::JArrayRefBase<T>(env, jarr) {                                \
-      if (jarr) {                                                              \
-        m_elements = env->Get##F##ArrayElements(jarr, nullptr);                \
-      } else {                                                                 \
-        errs() << "JArrayRef was passed a null pointer at \n"                  \
-               << GetJavaStackTrace(env);                                      \
-      }                                                                        \
-    }                                                                          \
-    ~J##F##ArrayRef() {                                                        \
-      if (m_jarr && m_elements) {                                              \
-        m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr),        \
-                                         m_elements, JNI_ABORT);               \
-      }                                                                        \
-    }                                                                          \
-  };                                                                           \
-                                                                               \
-  class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> {             \
-   public:                                                                     \
-    CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr, int len)                \
-        : detail::JArrayRefBase<T>(env, jarr, len) {                           \
-      if (jarr) {                                                              \
-        m_elements =                                                           \
-            static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr));    \
-      } else {                                                                 \
-        errs() << "JArrayRef was passed a null pointer at \n"                  \
-               << GetJavaStackTrace(env);                                      \
-      }                                                                        \
-    }                                                                          \
-    CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr)                         \
-        : detail::JArrayRefBase<T>(env, jarr) {                                \
-      if (jarr) {                                                              \
-        m_elements =                                                           \
-            static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr));    \
-      } else {                                                                 \
-        errs() << "JArrayRef was passed a null pointer at \n"                  \
-               << GetJavaStackTrace(env);                                      \
-      }                                                                        \
-    }                                                                          \
-    ~CriticalJ##F##ArrayRef() {                                                \
-      if (m_jarr && m_elements) {                                              \
-        m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT);   \
-      }                                                                        \
-    }                                                                          \
-  };
-
-WPI_JNI_JARRAYREF(jboolean, Boolean)
-WPI_JNI_JARRAYREF(jbyte, Byte)
-WPI_JNI_JARRAYREF(jshort, Short)
-WPI_JNI_JARRAYREF(jint, Int)
-WPI_JNI_JARRAYREF(jlong, Long)
-WPI_JNI_JARRAYREF(jfloat, Float)
-WPI_JNI_JARRAYREF(jdouble, Double)
-
-#undef WPI_JNI_JARRAYREF
+template <typename T, size_t Extent = std::dynamic_extent>
+using CriticalJSpan = detail::JSpanBase<T, true, Extent>;
 
 //
 // Conversions from C++ to Java objects
@@ -397,46 +433,38 @@
 // details for MakeJIntArray
 namespace detail {
 
-/**
- * Slow path (get primitive array and set individual elements).
- *
- * This is used if the input type is not an integer of the same size (note
- * signed/unsigned is ignored).
- */
-template <typename T,
-          bool = (std::is_integral<T>::value && sizeof(jint) == sizeof(T))>
+template <typename T>
 struct ConvertIntArray {
   static jintArray ToJava(JNIEnv* env, std::span<const T> arr) {
-    jintArray jarr = env->NewIntArray(arr.size());
-    if (!jarr) {
-      return nullptr;
+    if constexpr (sizeof(T) == sizeof(jint) && std::integral<T>) {
+      // Fast path (use SetIntArrayRegion).
+      jintArray jarr = env->NewIntArray(arr.size());
+      if (!jarr) {
+        return nullptr;
+      }
+      env->SetIntArrayRegion(jarr, 0, arr.size(),
+                             reinterpret_cast<const jint*>(arr.data()));
+      return jarr;
+    } else {
+      // Slow path (get primitive array and set individual elements).
+      //
+      // This is used if the input type is not an integer of the same size (note
+      // signed/unsigned is ignored).
+      jintArray jarr = env->NewIntArray(arr.size());
+      if (!jarr) {
+        return nullptr;
+      }
+      jint* elements =
+          static_cast<jint*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
+      if (!elements) {
+        return nullptr;
+      }
+      for (size_t i = 0; i < arr.size(); ++i) {
+        elements[i] = static_cast<jint>(arr[i]);
+      }
+      env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
+      return jarr;
     }
-    jint* elements =
-        static_cast<jint*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
-    if (!elements) {
-      return nullptr;
-    }
-    for (size_t i = 0; i < arr.size(); ++i) {
-      elements[i] = static_cast<jint>(arr[i]);
-    }
-    env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
-    return jarr;
-  }
-};
-
-/**
- * Fast path (use SetIntArrayRegion).
- */
-template <typename T>
-struct ConvertIntArray<T, true> {
-  static jintArray ToJava(JNIEnv* env, std::span<const T> arr) {
-    jintArray jarr = env->NewIntArray(arr.size());
-    if (!jarr) {
-      return nullptr;
-    }
-    env->SetIntArrayRegion(jarr, 0, arr.size(),
-                           reinterpret_cast<const jint*>(arr.data()));
-    return jarr;
   }
 };
 
@@ -574,9 +602,9 @@
 
 #undef WPI_JNI_MAKEJARRAY
 
-template <class T, typename = std::enable_if_t<
-                       sizeof(typename T::value_type) == sizeof(jlong) &&
-                       std::is_integral_v<typename T::value_type>>>
+template <class T>
+  requires(sizeof(typename T::value_type) == sizeof(jlong) &&
+           std::integral<typename T::value_type>)
 inline jlongArray MakeJLongArray(JNIEnv* env, const T& arr) {
   jlongArray jarr = env->NewLongArray(arr.size());
   if (!jarr) {
diff --git a/wpiutil/src/main/native/include/wpi/priority_queue.h b/wpiutil/src/main/native/include/wpi/priority_queue.h
index 4610aba..af68374 100644
--- a/wpiutil/src/main/native/include/wpi/priority_queue.h
+++ b/wpiutil/src/main/native/include/wpi/priority_queue.h
@@ -6,6 +6,7 @@
 #define WPIUTIL_WPI_PRIORITY_QUEUE_H_
 
 #include <algorithm>
+#include <concepts>
 #include <functional>
 #include <utility>
 #include <vector>
@@ -22,11 +23,9 @@
  */
 template <typename T, typename Sequence = std::vector<T>,
           typename Compare = std::less<typename Sequence::value_type>>
+  requires std::same_as<T, typename Sequence::value_type>
 class priority_queue {
  public:
-  static_assert(std::is_same_v<T, typename Sequence::value_type>,
-                "value_type must be the same as the underlying container");
-
   using value_type = typename Sequence::value_type;
   using reference = typename Sequence::reference;
   using const_reference = typename Sequence::const_reference;
@@ -34,10 +33,9 @@
   using container_type = Sequence;
   using value_compare = Compare;
 
-  template <typename Seq = Sequence,
-            typename Requires = typename std::enable_if_t<
-                std::is_default_constructible<Compare>{} &&
-                std::is_default_constructible<Seq>{}>>
+  template <typename Seq = Sequence>
+    requires std::default_initializable<Compare> &&
+             std::default_initializable<Seq>
   priority_queue() {}
 
   priority_queue(const Compare& comp, const Sequence& c) : c(c), comp(comp) {
@@ -65,7 +63,10 @@
     std::make_heap(c.begin(), c.end(), comp);
   }
 
-  [[nodiscard]] bool empty() const { return c.empty(); }
+  [[nodiscard]]
+  bool empty() const {
+    return c.empty();
+  }
 
   size_type size() const { return c.size(); }
 
diff --git a/wpiutil/src/main/native/include/wpi/protobuf/Protobuf.h b/wpiutil/src/main/native/include/wpi/protobuf/Protobuf.h
new file mode 100644
index 0000000..4eedcca
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/protobuf/Protobuf.h
@@ -0,0 +1,260 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <concepts>
+#include <optional>
+#include <span>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include "wpi/function_ref.h"
+
+namespace google::protobuf {
+class Arena;
+class Message;
+}  // namespace google::protobuf
+
+namespace wpi {
+
+template <typename T>
+class SmallVectorImpl;
+
+/**
+ * Protobuf serialization template. Unspecialized class has no members; only
+ * specializations of this class are useful, and only if they meet the
+ * ProtobufSerializable concept.
+ *
+ * @tparam T type to serialize/deserialize
+ */
+template <typename T>
+struct Protobuf {};
+
+/**
+ * Specifies that a type is capable of protobuf serialization and
+ * deserialization.
+ *
+ * This is designed for serializing complex flexible data structures using
+ * code generated from a .proto file. Serialization consists of writing
+ * values into a mutable protobuf Message and deserialization consists of
+ * reading values from an immutable protobuf Message.
+ *
+ * Implementations must define a template specialization for wpi::Protobuf with
+ * T being the type that is being serialized/deserialized, with the following
+ * static members (as enforced by this concept):
+ * - google::protobuf::Message* New(google::protobuf::Arena*): create a protobuf
+ *   message
+ * - T Unpack(const google::protobuf::Message&): function for deserialization
+ * - void Pack(google::protobuf::Message*, T&& value): function for
+ *   serialization
+ *
+ * To avoid pulling in the protobuf headers, these functions use
+ * google::protobuf::Message instead of a more specific type; implementations
+ * will need to static_cast to the correct type as created by New().
+ *
+ * Additionally: In a static block, call StructRegistry.registerClass() to
+ * register the class
+ */
+template <typename T>
+concept ProtobufSerializable = requires(
+    google::protobuf::Arena* arena, const google::protobuf::Message& inmsg,
+    google::protobuf::Message* outmsg, const T& value) {
+  typename Protobuf<typename std::remove_cvref_t<T>>;
+  {
+    Protobuf<typename std::remove_cvref_t<T>>::New(arena)
+  } -> std::same_as<google::protobuf::Message*>;
+  {
+    Protobuf<typename std::remove_cvref_t<T>>::Unpack(inmsg)
+  } -> std::same_as<typename std::remove_cvref_t<T>>;
+  Protobuf<typename std::remove_cvref_t<T>>::Pack(outmsg, value);
+};
+
+/**
+ * Specifies that a type is capable of in-place protobuf deserialization.
+ *
+ * In addition to meeting ProtobufSerializable, implementations must define a
+ * wpi::Protobuf<T> static member
+ * `void UnpackInto(T*, const google::protobuf::Message&)` to update the
+ * pointed-to T with the contents of the message.
+ */
+template <typename T>
+concept MutableProtobufSerializable =
+    ProtobufSerializable<T> &&
+    requires(T* out, const google::protobuf::Message& msg) {
+      Protobuf<typename std::remove_cvref_t<T>>::UnpackInto(out, msg);
+    };
+
+/**
+ * Unpack a serialized protobuf message.
+ *
+ * @tparam T object type
+ * @param msg protobuf message
+ * @return Deserialized object
+ */
+template <ProtobufSerializable T>
+inline T UnpackProtobuf(const google::protobuf::Message& msg) {
+  return Protobuf<T>::Unpack(msg);
+}
+
+/**
+ * Pack a serialized protobuf message.
+ *
+ * @param msg protobuf message (mutable, output)
+ * @param value object
+ */
+template <ProtobufSerializable T>
+inline void PackProtobuf(google::protobuf::Message* msg, const T& value) {
+  Protobuf<typename std::remove_cvref_t<T>>::Pack(msg, value);
+}
+
+/**
+ * Unpack a serialized struct into an existing object, overwriting its contents.
+ *
+ * @param out object (output)
+ * @param msg protobuf message
+ */
+template <ProtobufSerializable T>
+inline void UnpackProtobufInto(T* out, const google::protobuf::Message& msg) {
+  if constexpr (MutableProtobufSerializable<T>) {
+    Protobuf<T>::UnpackInto(out, msg);
+  } else {
+    *out = UnpackProtobuf<T>(msg);
+  }
+}
+
+// these detail functions avoid the need to include protobuf headers
+namespace detail {
+void DeleteProtobuf(google::protobuf::Message* msg);
+bool ParseProtobuf(google::protobuf::Message* msg,
+                   std::span<const uint8_t> data);
+bool SerializeProtobuf(wpi::SmallVectorImpl<uint8_t>& out,
+                       const google::protobuf::Message& msg);
+bool SerializeProtobuf(std::vector<uint8_t>& out,
+                       const google::protobuf::Message& msg);
+std::string GetTypeString(const google::protobuf::Message& msg);
+void ForEachProtobufDescriptor(
+    const google::protobuf::Message& msg,
+    function_ref<bool(std::string_view filename)> wants,
+    function_ref<void(std::string_view filename,
+                      std::span<const uint8_t> descriptor)>
+        fn);
+}  // namespace detail
+
+/**
+ * Owning wrapper (ala std::unique_ptr) for google::protobuf::Message* that does
+ * not require the protobuf headers be included. Note this object is not thread
+ * safe; users of this object are required to provide any necessary thread
+ * safety.
+ *
+ * @tparam T serialized object type
+ */
+template <ProtobufSerializable T>
+class ProtobufMessage {
+ public:
+  explicit ProtobufMessage(google::protobuf::Arena* arena = nullptr)
+      : m_msg{Protobuf<T>::New(arena)} {}
+  ~ProtobufMessage() { detail::DeleteProtobuf(m_msg); }
+  ProtobufMessage(const ProtobufMessage&) = delete;
+  ProtobufMessage& operator=(const ProtobufMessage&) = delete;
+  ProtobufMessage(ProtobufMessage&& rhs) : m_msg{rhs.m_msg} {
+    rhs.m_msg = nullptr;
+  }
+  ProtobufMessage& operator=(ProtobufMessage&& rhs) {
+    std::swap(m_msg, rhs.m_msg);
+    return *this;
+  }
+
+  /**
+   * Gets the stored message object.
+   *
+   * @return google::protobuf::Message*
+   */
+  google::protobuf::Message* GetMessage() { return m_msg; }
+  const google::protobuf::Message* GetMessage() const { return m_msg; }
+
+  /**
+   * Unpacks from a byte array.
+   *
+   * @param data byte array
+   * @return Optional; empty if parsing failed
+   */
+  std::optional<T> Unpack(std::span<const uint8_t> data) {
+    if (!detail::ParseProtobuf(m_msg, data)) {
+      return std::nullopt;
+    }
+    return Protobuf<T>::Unpack(*m_msg);
+  }
+
+  /**
+   * Unpacks from a byte array into an existing object.
+   *
+   * @param[out] out output object
+   * @param[in] data byte array
+   * @return true if successful
+   */
+  bool UnpackInto(T* out, std::span<const uint8_t> data) {
+    if (!detail::ParseProtobuf(m_msg, data)) {
+      return false;
+    }
+    UnpackProtobufInto(out, *m_msg);
+    return true;
+  }
+
+  /**
+   * Packs object into a SmallVector.
+   *
+   * @param[out] out output bytes
+   * @param[in] value value
+   * @return true if successful
+   */
+  bool Pack(wpi::SmallVectorImpl<uint8_t>& out, const T& value) {
+    Protobuf<T>::Pack(m_msg, value);
+    return detail::SerializeProtobuf(out, *m_msg);
+  }
+
+  /**
+   * Packs object into a std::vector.
+   *
+   * @param[out] out output bytes
+   * @param[in] value value
+   * @return true if successful
+   */
+  bool Pack(std::vector<uint8_t>& out, const T& value) {
+    Protobuf<T>::Pack(m_msg, value);
+    return detail::SerializeProtobuf(out, *m_msg);
+  }
+
+  /**
+   * Gets the type string for the message.
+   *
+   * @return type string
+   */
+  std::string GetTypeString() const { return detail::GetTypeString(*m_msg); }
+
+  /**
+   * Loops over all protobuf descriptors including nested/referenced
+   * descriptors.
+   *
+   * @param exists function that returns false if fn should be called for the
+   *               given type string
+   * @param fn function to call for each descriptor
+   */
+  void ForEachProtobufDescriptor(
+      function_ref<bool(std::string_view filename)> exists,
+      function_ref<void(std::string_view filename,
+                        std::span<const uint8_t> descriptor)>
+          fn) {
+    detail::ForEachProtobufDescriptor(*m_msg, exists, fn);
+  }
+
+ private:
+  google::protobuf::Message* m_msg = nullptr;
+};
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/protobuf/ProtobufMessageDatabase.h b/wpiutil/src/main/native/include/wpi/protobuf/ProtobufMessageDatabase.h
new file mode 100644
index 0000000..f1ab105
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/protobuf/ProtobufMessageDatabase.h
@@ -0,0 +1,77 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+#include <span>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+
+#include "wpi/StringMap.h"
+
+namespace wpi {
+
+/**
+ * Database of protobuf dynamic messages. Unlike the protobuf descriptor pools
+ * and databases, this gracefully handles adding descriptors out of order and
+ * descriptors being replaced.
+ */
+class ProtobufMessageDatabase {
+ public:
+  /**
+   * Adds a file descriptor to the database. If the file references other
+   * files that have not yet been added, no messages in that file will be
+   * available until those files are added. Replaces any existing file with
+   * the same name.
+   *
+   * @param filename filename
+   * @param data FileDescriptorProto serialized data
+   * @return False if could not parse data
+   */
+  bool Add(std::string_view filename, std::span<const uint8_t> data);
+
+  /**
+   * Finds a message in the database by name.
+   *
+   * @param name type name
+   * @return protobuf message, or nullptr if not found
+   */
+  google::protobuf::Message* Find(std::string_view name) const;
+
+  /**
+   * Gets message factory.
+   *
+   * @return message factory
+   */
+  google::protobuf::MessageFactory* GetMessageFactory() {
+    return m_factory.get();
+  }
+
+ private:
+  struct ProtoFile {
+    std::unique_ptr<google::protobuf::FileDescriptorProto> proto;
+    std::vector<std::string> uses;
+    bool complete = false;
+    bool inPool = false;
+  };
+
+  void Build(std::string_view filename, ProtoFile& file);
+  bool Rebuild(ProtoFile& file);
+
+  std::unique_ptr<google::protobuf::DescriptorPool> m_pool =
+      std::make_unique<google::protobuf::DescriptorPool>();
+  std::unique_ptr<google::protobuf::DynamicMessageFactory> m_factory =
+      std::make_unique<google::protobuf::DynamicMessageFactory>();
+  wpi::StringMap<ProtoFile> m_files;  // indexed by filename
+  // indexed by type string
+  mutable wpi::StringMap<std::unique_ptr<google::protobuf::Message>> m_msgs;
+};
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h b/wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
index 2287b73..4115420 100644
--- a/wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
+++ b/wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
@@ -60,6 +60,14 @@
                                   std::function<void(bool)> setter) = 0;
 
   /**
+   * Add a constant boolean property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstBoolean(std::string_view key, bool value) = 0;
+
+  /**
    * Add an integer property.
    *
    * @param key     property name
@@ -71,6 +79,14 @@
                                   std::function<void(int64_t)> setter) = 0;
 
   /**
+   * Add a constant integer property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstInteger(std::string_view key, int64_t value) = 0;
+
+  /**
    * Add a float property.
    *
    * @param key     property name
@@ -82,6 +98,14 @@
                                 std::function<void(float)> setter) = 0;
 
   /**
+   * Add a constant float property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstFloat(std::string_view key, float value) = 0;
+
+  /**
    * Add a double property.
    *
    * @param key     property name
@@ -93,6 +117,14 @@
                                  std::function<void(double)> setter) = 0;
 
   /**
+   * Add a constant double property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstDouble(std::string_view key, double value) = 0;
+
+  /**
    * Add a string property.
    *
    * @param key     property name
@@ -104,6 +136,15 @@
       std::function<void(std::string_view)> setter) = 0;
 
   /**
+   * Add a constant string property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstString(std::string_view key,
+                                  std::string_view value) = 0;
+
+  /**
    * Add a boolean array property.
    *
    * @param key     property name
@@ -115,6 +156,15 @@
       std::function<void(std::span<const int>)> setter) = 0;
 
   /**
+   * Add a constant boolean array property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstBooleanArray(std::string_view key,
+                                        std::span<const int> value) = 0;
+
+  /**
    * Add an integer array property.
    *
    * @param key     property name
@@ -126,6 +176,15 @@
       std::function<void(std::span<const int64_t>)> setter) = 0;
 
   /**
+   * Add a constant integer array property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstIntegerArray(std::string_view key,
+                                        std::span<const int64_t> value) = 0;
+
+  /**
    * Add a float array property.
    *
    * @param key     property name
@@ -137,6 +196,15 @@
       std::function<void(std::span<const float>)> setter) = 0;
 
   /**
+   * Add a constant float array property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstFloatArray(std::string_view key,
+                                      std::span<const float> value) = 0;
+
+  /**
    * Add a double array property.
    *
    * @param key     property name
@@ -148,6 +216,15 @@
       std::function<void(std::span<const double>)> setter) = 0;
 
   /**
+   * Add a constant double array property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstDoubleArray(std::string_view key,
+                                       std::span<const double> value) = 0;
+
+  /**
    * Add a string array property.
    *
    * @param key     property name
@@ -159,6 +236,15 @@
       std::function<void(std::span<const std::string>)> setter) = 0;
 
   /**
+   * Add a constant string array property.
+   *
+   * @param key     property name
+   * @param value   the value
+   */
+  virtual void PublishConstStringArray(std::string_view key,
+                                       std::span<const std::string> value) = 0;
+
+  /**
    * Add a raw property.
    *
    * @param key         property name
@@ -172,6 +258,17 @@
       std::function<void(std::span<const uint8_t>)> setter) = 0;
 
   /**
+   * Add a constant raw property.
+   *
+   * @param key     property name
+   * @param typeString  type string
+   * @param value   the value
+   */
+  virtual void PublishConstRaw(std::string_view key,
+                               std::string_view typeString,
+                               std::span<const uint8_t> value) = 0;
+
+  /**
    * Add a string property (SmallString form).
    *
    * @param key     property name
diff --git a/wpiutil/src/main/native/include/wpi/struct/DynamicStruct.h b/wpiutil/src/main/native/include/wpi/struct/DynamicStruct.h
new file mode 100644
index 0000000..b88894c
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/struct/DynamicStruct.h
@@ -0,0 +1,682 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <cassert>
+#include <memory>
+#include <span>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include "wpi/MathExtras.h"
+#include "wpi/StringMap.h"
+#include "wpi/bit.h"
+
+namespace wpi {
+
+template <typename T>
+class SmallVectorImpl;
+
+class DynamicStruct;
+class MutableDynamicStruct;
+class StructDescriptor;
+class StructDescriptorDatabase;
+
+/**
+ * Known data types for raw struct dynamic fields (see StructFieldDescriptor).
+ */
+enum class StructFieldType {
+  kBool,
+  kChar,
+  kInt8,
+  kInt16,
+  kInt32,
+  kInt64,
+  kUint8,
+  kUint16,
+  kUint32,
+  kUint64,
+  kFloat,
+  kDouble,
+  kStruct
+};
+
+/**
+ * Raw struct dynamic field descriptor.
+ */
+class StructFieldDescriptor {
+  struct private_init {};
+  friend class DynamicStruct;
+  friend class MutableDynamicStruct;
+  friend class StructDescriptor;
+  friend class StructDescriptorDatabase;
+
+ public:
+  /**
+   * Set of enumerated values.
+   */
+  using EnumValues = std::vector<std::pair<std::string, int64_t>>;
+
+  StructFieldDescriptor(const StructDescriptor* parent, std::string_view name,
+                        StructFieldType type, size_t size, size_t arraySize,
+                        unsigned int bitWidth, EnumValues enumValues,
+                        const StructDescriptor* structDesc,
+                        const private_init&);
+
+  /**
+   * Gets the dynamic struct this field is contained in.
+   *
+   * @return struct descriptor
+   */
+  const StructDescriptor* GetParent() const { return m_parent; }
+
+  /**
+   * Gets the field name.
+   *
+   * @return field name
+   */
+  const std::string& GetName() const { return m_name; }
+
+  /**
+   * Gets the field type.
+   *
+   * @return field type
+   */
+  StructFieldType GetType() const { return m_type; }
+
+  /**
+   * Returns whether the field type is a signed integer.
+   *
+   * @return true if signed integer, false otherwise
+   */
+  bool IsInt() const {
+    return m_type == StructFieldType::kInt8 ||
+           m_type == StructFieldType::kInt16 ||
+           m_type == StructFieldType::kInt32 ||
+           m_type == StructFieldType::kInt64;
+  }
+
+  /**
+   * Returns whether the field type is an unsigned integer.
+   *
+   * @return true if unsigned integer, false otherwise
+   */
+  bool IsUint() const {
+    return m_type == StructFieldType::kUint8 ||
+           m_type == StructFieldType::kUint16 ||
+           m_type == StructFieldType::kUint32 ||
+           m_type == StructFieldType::kUint64;
+  }
+
+  /**
+   * Gets the underlying storage size of the field, in bytes.
+   *
+   * @return number of bytes
+   */
+  size_t GetSize() const { return m_size; }
+
+  /**
+   * Gets the storage offset of the field, in bytes.
+   *
+   * @return number of bytes from the start of the struct
+   */
+  size_t GetOffset() const { return m_offset; }
+
+  /**
+   * Gets the bit width of the field, in bits.
+   *
+   * @return number of bits
+   */
+  unsigned int GetBitWidth() const {
+    return m_bitWidth == 0 ? m_size * 8 : m_bitWidth;
+  }
+
+  /**
+   * Gets the bit mask for the field. The mask is always the least significant
+   * bits (it is not shifted).
+   *
+   * @return bit mask
+   */
+  uint64_t GetBitMask() const { return m_bitMask; }
+
+  /**
+   * Gets the bit shift for the field (LSB=0).
+   *
+   * @return number of bits
+   */
+  unsigned int GetBitShift() const { return m_bitShift; }
+
+  /**
+   * Returns whether the field is an array.
+   *
+   * @return true if array
+   */
+  bool IsArray() const { return m_arraySize > 1; }
+
+  /**
+   * Gets the array size. Returns 1 if non-array.
+   *
+   * @return number of elements
+   */
+  size_t GetArraySize() const { return m_arraySize; }
+
+  /**
+   * Returns whether the field has enumerated values.
+   *
+   * @return true if there are enumerated values
+   */
+  bool HasEnum() const { return !m_enum.empty(); }
+
+  /**
+   * Gets the enumerated values.
+   *
+   * @return set of enumerated values
+   */
+  const EnumValues& GetEnumValues() { return m_enum; }
+
+  /**
+   * Gets the struct descriptor for a struct data type.
+   *
+   * @return struct descriptor; returns null for non-struct
+   */
+  const StructDescriptor* GetStruct() const { return m_struct; }
+
+  /**
+   * Gets the minimum unsigned integer value that can be stored in this field.
+   *
+   * @return minimum value
+   */
+  uint64_t GetUintMin() const { return 0; }
+
+  /**
+   * Gets the maximum unsigned integer value that can be stored in this field.
+   *
+   * @return maximum value
+   */
+  uint64_t GetUintMax() const { return m_bitMask; }
+
+  /**
+   * Gets the minimum signed integer value that can be stored in this field.
+   *
+   * @return minimum value
+   */
+  int64_t GetIntMin() const {
+    return static_cast<int64_t>(-(m_bitMask >> 1)) - 1;
+  }
+
+  /**
+   * Gets the maximum signed integer value that can be stored in this field.
+   *
+   * @return maximum value
+   */
+  int64_t GetIntMax() const { return m_bitMask >> 1; }
+
+  /**
+   * Returns whether the field is a bitfield.
+   *
+   * @return true if bitfield
+   */
+  bool IsBitField() const {
+    return m_bitShift != 0 || m_bitWidth != (m_size * 8);
+  }
+
+ private:
+  // note: constructor fills in everything except offset and shift
+  const StructDescriptor* m_parent;
+  std::string m_name;
+  size_t m_size;
+  size_t m_offset = 0;
+  size_t m_arraySize;  // 1 for non-arrays
+  EnumValues m_enum;
+  const StructDescriptor* m_struct;  // nullptr for non-structs
+  uint64_t m_bitMask;
+  StructFieldType m_type;
+  unsigned int m_bitWidth;
+  unsigned int m_bitShift = 0;
+};
+
+/**
+ * Raw struct dynamic struct descriptor.
+ */
+class StructDescriptor {
+  struct private_init {};
+  friend class StructDescriptorDatabase;
+
+ public:
+  StructDescriptor(std::string_view name, const private_init&) : m_name{name} {}
+
+  /**
+   * Gets the struct name.
+   *
+   * @return name
+   */
+  const std::string& GetName() const { return m_name; }
+
+  /**
+   * Gets the struct schema.
+   *
+   * @return schema
+   */
+  const std::string& GetSchema() const { return m_schema; }
+
+  /**
+   * Returns whether the struct is valid (e.g. the struct is fully defined and
+   * field offsets computed).
+   *
+   * @return true if valid
+   */
+  bool IsValid() const { return m_valid; }
+
+  /**
+   * Returns the struct size, in bytes. Not valid unless IsValid() is true.
+   *
+   * @return size in bytes
+   */
+  size_t GetSize() const {
+    assert(m_valid);
+    return m_size;
+  }
+
+  /**
+   * Gets a field descriptor by name. Note the field cannot be accessed until
+   * the struct is valid.
+   *
+   * @param name field name
+   * @return field descriptor, or nullptr if not found
+   */
+  const StructFieldDescriptor* FindFieldByName(std::string_view name) const;
+
+  /**
+   * Gets all field descriptors. Note fields cannot be accessed until the struct
+   * is valid.
+   *
+   * @return field descriptors
+   */
+  const std::vector<StructFieldDescriptor>& GetFields() const {
+    return m_fields;
+  }
+
+ private:
+  bool CheckCircular(
+      wpi::SmallVectorImpl<const StructDescriptor*>& stack) const;
+  std::string CalculateOffsets(
+      wpi::SmallVectorImpl<const StructDescriptor*>& stack);
+
+  std::string m_name;
+  std::string m_schema;
+  std::vector<StructDescriptor*> m_references;
+  std::vector<StructFieldDescriptor> m_fields;
+  StringMap<size_t> m_fieldsByName;
+  size_t m_size = 0;
+  bool m_valid = false;
+};
+
+/**
+ * Database of raw struct dynamic descriptors.
+ */
+class StructDescriptorDatabase {
+ public:
+  /**
+   * Adds a structure schema to the database. If the struct references other
+   * structs that have not yet been added, it will not be valid until those
+   * structs are also added.
+   *
+   * @param[in] name structure name
+   * @param[in] schema structure schema
+   * @param[out] err detailed error, if nullptr is returned
+   * @return Added struct, or nullptr on error
+   */
+  const StructDescriptor* Add(std::string_view name, std::string_view schema,
+                              std::string* err);
+
+  /**
+   * Finds a structure in the database by name.
+   *
+   * @param name structure name
+   * @return struct descriptor, or nullptr if not found
+   */
+  const StructDescriptor* Find(std::string_view name) const;
+
+ private:
+  StringMap<std::unique_ptr<StructDescriptor>> m_structs;
+};
+
+/**
+ * Dynamic (run-time) read-only access to a serialized raw struct.
+ */
+class DynamicStruct {
+ public:
+  /**
+   * Constructs a new dynamic struct. Note: the passed data is a span; no copy
+   * is made, so it's necessary for the lifetime of the referenced data to be
+   * longer than this object.
+   *
+   * @param desc struct descriptor
+   * @param data serialized data
+   */
+  DynamicStruct(const StructDescriptor* desc, std::span<const uint8_t> data)
+      : m_desc{desc}, m_data{data} {}
+
+  /**
+   * Gets the struct descriptor.
+   *
+   * @return struct descriptor
+   */
+  const StructDescriptor* GetDescriptor() const { return m_desc; }
+
+  /**
+   * Gets the serialized data.
+   *
+   * @return data
+   */
+  std::span<const uint8_t> GetData() const { return m_data; }
+
+  /**
+   * Gets a struct field descriptor by name.
+   *
+   * @param name field name
+   * @return field descriptor, or nullptr if no field with that name exists
+   */
+  const StructFieldDescriptor* FindField(std::string_view name) const {
+    return m_desc->FindFieldByName(name);
+  }
+
+  /**
+   * Gets the value of a boolean field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  bool GetBoolField(const StructFieldDescriptor* field,
+                    size_t arrIndex = 0) const {
+    assert(field->m_type == StructFieldType::kBool);
+    return GetFieldImpl(field, arrIndex);
+  }
+
+  /**
+   * Gets the value of a signed integer field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  int64_t GetIntField(const StructFieldDescriptor* field,
+                      size_t arrIndex = 0) const {
+    assert(field->IsInt());
+    return GetFieldImpl(field, arrIndex);
+  }
+
+  /**
+   * Gets the value of an unsigned integer field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  uint64_t GetUintField(const StructFieldDescriptor* field,
+                        size_t arrIndex = 0) const {
+    assert(field->IsUint());
+    return GetFieldImpl(field, arrIndex);
+  }
+
+  /**
+   * Gets the value of a float field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  float GetFloatField(const StructFieldDescriptor* field,
+                      size_t arrIndex = 0) const {
+    assert(field->m_type == StructFieldType::kFloat);
+    return bit_cast<float>(
+        static_cast<uint32_t>(GetFieldImpl(field, arrIndex)));
+  }
+
+  /**
+   * Gets the value of a double field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  double GetDoubleField(const StructFieldDescriptor* field,
+                        size_t arrIndex = 0) const {
+    assert(field->m_type == StructFieldType::kDouble);
+    return bit_cast<double>(GetFieldImpl(field, arrIndex));
+  }
+
+  /**
+   * Gets the value of a char or char array field.
+   *
+   * @param field field descriptor
+   * @return field value
+   */
+  std::string_view GetStringField(const StructFieldDescriptor* field) const {
+    assert(field->m_type == StructFieldType::kChar);
+    assert(field->m_parent == m_desc);
+    assert(m_desc->IsValid());
+    return {reinterpret_cast<const char*>(&m_data[field->m_offset]),
+            field->m_arraySize};
+  }
+
+  /**
+   * Gets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  DynamicStruct GetStructField(const StructFieldDescriptor* field,
+                               size_t arrIndex = 0) const {
+    assert(field->m_type == StructFieldType::kStruct);
+    assert(field->m_parent == m_desc);
+    assert(m_desc->IsValid());
+    assert(arrIndex < field->m_arraySize);
+    return DynamicStruct{field->m_struct,
+                         m_data.subspan(field->m_offset +
+                                        arrIndex * field->m_struct->GetSize())};
+  }
+
+ protected:
+  const StructDescriptor* m_desc;
+
+ private:
+  uint64_t GetFieldImpl(const StructFieldDescriptor* field,
+                        size_t arrIndex) const;
+
+  std::span<const uint8_t> m_data;
+};
+
+/**
+ * Dynamic (run-time) mutable access to a serialized raw struct.
+ */
+class MutableDynamicStruct : public DynamicStruct {
+ public:
+  /**
+   * Constructs a new dynamic struct. Note: the passed data is a span; no copy
+   * is made, so it's necessary for the lifetime of the referenced data to be
+   * longer than this object.
+   *
+   * @param desc struct descriptor
+   * @param data serialized data
+   */
+  MutableDynamicStruct(const StructDescriptor* desc, std::span<uint8_t> data)
+      : DynamicStruct{desc, data}, m_data{data} {}
+
+  /**
+   * Gets the serialized data.
+   *
+   * @return data
+   */
+  std::span<uint8_t> GetData() { return m_data; }
+
+  using DynamicStruct::GetData;
+
+  /**
+   * Overwrites the entire serialized struct by copying data from a span.
+   *
+   * @param data replacement data for the struct
+   */
+  void SetData(std::span<const uint8_t> data);
+
+  /**
+   * Sets the value of a boolean field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @param arrIndex array index (must be less than field array size)
+   */
+  void SetBoolField(const StructFieldDescriptor* field, bool value,
+                    size_t arrIndex = 0) {
+    assert(field->m_type == StructFieldType::kBool);
+    SetFieldImpl(field, value ? 1 : 0, arrIndex);
+  }
+
+  /**
+   * Sets the value of a signed integer field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @param arrIndex array index (must be less than field array size)
+   */
+  void SetIntField(const StructFieldDescriptor* field, int64_t value,
+                   size_t arrIndex = 0) {
+    assert(field->IsInt());
+    SetFieldImpl(field, value, arrIndex);
+  }
+
+  /**
+   * Sets the value of an unsigned integer field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @param arrIndex array index (must be less than field array size)
+   */
+  void SetUintField(const StructFieldDescriptor* field, uint64_t value,
+                    size_t arrIndex = 0) {
+    assert(field->IsUint());
+    SetFieldImpl(field, value, arrIndex);
+  }
+
+  /**
+   * Sets the value of a float field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @param arrIndex array index (must be less than field array size)
+   */
+  void SetFloatField(const StructFieldDescriptor* field, float value,
+                     size_t arrIndex = 0) {
+    assert(field->m_type == StructFieldType::kFloat);
+    SetFieldImpl(field, bit_cast<uint32_t>(value), arrIndex);
+  }
+
+  /**
+   * Sets the value of a double field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @param arrIndex array index (must be less than field array size)
+   */
+  void SetDoubleField(const StructFieldDescriptor* field, double value,
+                      size_t arrIndex = 0) {
+    assert(field->m_type == StructFieldType::kDouble);
+    SetFieldImpl(field, bit_cast<uint64_t>(value), arrIndex);
+  }
+
+  /**
+   * Sets the value of a char or char array field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   */
+  void SetStringField(const StructFieldDescriptor* field,
+                      std::string_view value);
+
+  /**
+   * Sets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @param value field value
+   * @param arrIndex array index (must be less than field array size)
+   */
+  void SetStructField(const StructFieldDescriptor* field,
+                      const DynamicStruct& value, size_t arrIndex = 0);
+
+  /**
+   * Gets the value of a struct field.
+   *
+   * @param field field descriptor
+   * @param arrIndex array index (must be less than field array size)
+   * @return field value
+   */
+  MutableDynamicStruct GetStructField(const StructFieldDescriptor* field,
+                                      size_t arrIndex = 0) {
+    assert(field->m_type == StructFieldType::kStruct);
+    assert(field->m_parent == m_desc);
+    assert(m_desc->IsValid());
+    assert(arrIndex < field->m_arraySize);
+    return MutableDynamicStruct{
+        field->m_struct, m_data.subspan(field->m_offset +
+                                        arrIndex * field->m_struct->GetSize())};
+  }
+
+  using DynamicStruct::GetStructField;
+
+ private:
+  void SetFieldImpl(const StructFieldDescriptor* field, uint64_t value,
+                    size_t arrIndex);
+
+  std::span<uint8_t> m_data;
+};
+
+namespace impl {
+struct DSOData {
+  explicit DSOData(size_t size) : m_dataStore(size) {}
+  explicit DSOData(std::span<const uint8_t> data)
+      : m_dataStore{data.begin(), data.end()} {}
+
+  std::vector<uint8_t> m_dataStore;
+};
+}  // namespace impl
+
+/**
+ * Dynamic (run-time) mutable access to a serialized raw struct, with internal
+ * data storage.
+ */
+class DynamicStructObject : private impl::DSOData, public MutableDynamicStruct {
+  /**
+   * Constructs a new dynamic struct object. The descriptor must be valid.
+   *
+   * @param desc struct descriptor
+   */
+  explicit DynamicStructObject(const StructDescriptor* desc)
+      : DSOData{desc->GetSize()}, MutableDynamicStruct{desc, m_dataStore} {}
+
+  /**
+   * Constructs a new dynamic struct object. Makes a copy of the serialized
+   * data so there are no lifetime constraints on the data parameter.
+   *
+   * @param desc struct descriptor
+   * @param data serialized data
+   */
+  DynamicStructObject(const StructDescriptor* desc,
+                      std::span<const uint8_t> data)
+      : DSOData{data}, MutableDynamicStruct{desc, m_dataStore} {
+    assert(data.size() >= desc->GetSize());
+  }
+
+  // can't be movable due to span references
+  DynamicStructObject(DynamicStructObject&&) = delete;
+  DynamicStructObject& operator=(DynamicStructObject&&) = delete;
+};
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/struct/SchemaParser.h b/wpiutil/src/main/native/include/wpi/struct/SchemaParser.h
new file mode 100644
index 0000000..a8cf1a4
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/struct/SchemaParser.h
@@ -0,0 +1,186 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+namespace wpi::structparser {
+
+/**
+ * A lexed raw struct schema token.
+ */
+struct Token {
+  enum Kind {
+    kUnknown,
+    kInteger,
+    kIdentifier,
+    kLeftBracket,
+    kRightBracket,
+    kLeftBrace,
+    kRightBrace,
+    kColon,
+    kSemicolon,
+    kComma,
+    kEquals,
+    kEndOfInput,
+  };
+
+  Token() = default;
+  Token(Kind kind, std::string_view text) : kind{kind}, text{text} {}
+
+  bool Is(Kind k) const { return kind == k; }
+
+  Kind kind = kUnknown;
+  std::string_view text;
+};
+
+std::string_view ToString(Token::Kind kind);
+
+/**
+ * Raw struct schema lexer.
+ */
+class Lexer {
+ public:
+  /**
+   * Construct a raw struct schema lexer.
+   *
+   * @param in schema
+   */
+  explicit Lexer(std::string_view in) : m_in{in} {}
+
+  /**
+   * Gets the next token.
+   *
+   * @return Token
+   */
+  [[nodiscard]]
+  Token Scan();
+
+  /**
+   * Gets the starting position of the last lexed token.
+   *
+   * @return position (0 = first character)
+   */
+  size_t GetPosition() const { return m_tokenStart; }
+
+ private:
+  Token ScanInteger();
+  Token ScanIdentifier();
+
+  void Get() {
+    if (m_pos < m_in.size()) {
+      [[likely]] m_current = m_in[m_pos];
+    } else {
+      m_current = -1;
+    }
+    ++m_pos;
+  }
+
+  void Unget() {
+    if (m_pos > 0) {
+      [[likely]] m_pos--;
+      if (m_pos < m_in.size()) {
+        [[likely]] m_current = m_in[m_pos];
+      } else {
+        m_current = -1;
+      }
+    } else {
+      m_current = -1;
+    }
+  }
+
+  Token MakeToken(Token::Kind kind) {
+    return {kind, m_in.substr(m_tokenStart, m_pos - m_tokenStart)};
+  }
+
+  std::string_view m_in;
+  int m_current = -1;
+  size_t m_tokenStart = 0;
+  size_t m_pos = 0;
+};
+
+/**
+ * Raw struct set of enumerated values.
+ */
+using EnumValues = std::vector<std::pair<std::string, int64_t>>;
+
+/**
+ * Raw struct schema declaration.
+ */
+struct ParsedDeclaration {
+  std::string typeString;
+  std::string name;
+  EnumValues enumValues;
+  size_t arraySize = 1;
+  unsigned int bitWidth = 0;
+};
+
+/**
+ * Raw struct schema.
+ */
+struct ParsedSchema {
+  std::vector<ParsedDeclaration> declarations;
+};
+
+/**
+ * Raw struct schema parser.
+ */
+class Parser {
+ public:
+  /**
+   * Construct a raw struct schema parser.
+   *
+   * @param in schema
+   */
+  explicit Parser(std::string_view in) : m_lexer{in} {}
+
+  /**
+   * Parses the schema.
+   *
+   * @param[out] out parsed schema object
+   * @return true on success, false on failure (use GetError() to get error)
+   */
+  [[nodiscard]]
+  bool Parse(ParsedSchema* out);
+
+  /**
+   * Gets the parser error if one occurred.
+   *
+   * @return parser error; blank if no error occurred
+   */
+  const std::string& GetError() const { return m_error; }
+
+ private:
+  [[nodiscard]]
+  bool ParseDeclaration(ParsedDeclaration* out);
+  [[nodiscard]]
+  bool ParseEnum(EnumValues* out);
+
+  Token::Kind GetNextToken() {
+    m_token = m_lexer.Scan();
+    return m_token.kind;
+  }
+  [[nodiscard]]
+  bool Expect(Token::Kind kind) {
+    if (m_token.Is(kind)) {
+      [[likely]] return true;
+    }
+    FailExpect(kind);
+    return false;
+  }
+  void FailExpect(Token::Kind desired);
+  void Fail(std::string_view msg);
+
+  Lexer m_lexer;
+  Token m_token;
+  std::string m_error;
+};
+
+}  // namespace wpi::structparser
diff --git a/wpiutil/src/main/native/include/wpi/struct/Struct.h b/wpiutil/src/main/native/include/wpi/struct/Struct.h
new file mode 100644
index 0000000..1336707
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/struct/Struct.h
@@ -0,0 +1,533 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <concepts>
+#include <span>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "wpi/Endian.h"
+#include "wpi/MathExtras.h"
+#include "wpi/bit.h"
+#include "wpi/ct_string.h"
+#include "wpi/function_ref.h"
+#include "wpi/mutex.h"
+
+namespace wpi {
+
+/**
+ * Struct serialization template. Unspecialized class has no members; only
+ * specializations of this class are useful, and only if they meet the
+ * StructSerializable concept.
+ *
+ * @tparam T type to serialize/deserialize
+ */
+template <typename T>
+struct Struct {};
+
+/**
+ * Specifies that a type is capable of raw struct serialization and
+ * deserialization.
+ *
+ * This is designed for serializing small fixed-size data structures in the
+ * fastest and most compact means possible. Serialization consists of writing
+ * values into a mutable std::span and deserialization consists of reading
+ * values from an immutable std::span.
+ *
+ * Implementations must define a template specialization for wpi::Struct with
+ * T being the type that is being serialized/deserialized, with the following
+ * static members (as enforced by this concept):
+ * - std::string_view kTypeString: the type string
+ * - size_t kSize: the structure size in bytes
+ * - std::string_view kSchema: the struct schema
+ * - T Unpack(std::span<const uint8_t, kSize>): function for deserialization
+ * - void Pack(std::span<uint8_t, kSize>, T&& value): function for
+ *   serialization
+ *
+ * If the struct has nested structs, implementations should also meet the
+ * requirements of HasNestedStruct<T>.
+ */
+template <typename T>
+concept StructSerializable =
+    requires(std::span<const uint8_t> in, std::span<uint8_t> out, T&& value) {
+      typename Struct<typename std::remove_cvref_t<T>>;
+      {
+        Struct<typename std::remove_cvref_t<T>>::kTypeString
+      } -> std::convertible_to<std::string_view>;
+      {
+        Struct<typename std::remove_cvref_t<T>>::kSize
+      } -> std::convertible_to<size_t>;
+      {
+        Struct<typename std::remove_cvref_t<T>>::kSchema
+      } -> std::convertible_to<std::string_view>;
+      {
+        Struct<typename std::remove_cvref_t<T>>::Unpack(
+            in.subspan<0, Struct<typename std::remove_cvref_t<T>>::kSize>())
+      } -> std::same_as<typename std::remove_cvref_t<T>>;
+      Struct<typename std::remove_cvref_t<T>>::Pack(
+          out.subspan<0, Struct<typename std::remove_cvref_t<T>>::kSize>(),
+          std::forward<T>(value));
+    };
+
+/**
+ * Specifies that a type is capable of in-place raw struct deserialization.
+ *
+ * In addition to meeting StructSerializable, implementations must define a
+ * wpi::Struct<T> static member `void UnpackInto(T*, std::span<const uint8_t>)`
+ * to update the pointed-to T with the contents of the span.
+ */
+template <typename T>
+concept MutableStructSerializable =
+    StructSerializable<T> && requires(T* out, std::span<const uint8_t> in) {
+      Struct<typename std::remove_cvref_t<T>>::UnpackInto(
+          out, in.subspan<0, Struct<typename std::remove_cvref_t<T>>::kSize>());
+    };
+
+/**
+ * Specifies that a struct type has nested struct declarations.
+ *
+ * In addition to meeting StructSerializable, implementations must define a
+ * wpi::Struct<T> static member
+ * `void ForEachNested(std::invocable<std::string_view, std::string_view) auto
+ * fn)` (or equivalent) and call ForEachNestedStruct<Type> on each nested struct
+ * type.
+ */
+template <typename T>
+concept HasNestedStruct =
+    StructSerializable<T> &&
+    requires(function_ref<void(std::string_view, std::string_view)> fn) {
+      Struct<typename std::remove_cvref_t<T>>::ForEachNested(fn);
+    };
+
+/**
+ * Unpack a serialized struct.
+ *
+ * @tparam T object type
+ * @param data raw struct data
+ * @return Deserialized object
+ */
+template <StructSerializable T>
+inline T UnpackStruct(std::span<const uint8_t, Struct<T>::kSize> data) {
+  return Struct<T>::Unpack(data);
+}
+
+/**
+ * Unpack a serialized struct starting at a given offset within the data.
+ * This is primarily useful in unpack implementations to unpack nested structs.
+ *
+ * @tparam T object type
+ * @tparam Offset starting offset
+ * @param data raw struct data
+ * @return Deserialized object
+ */
+template <StructSerializable T, size_t Offset>
+inline T UnpackStruct(std::span<const uint8_t> data) {
+  return Struct<T>::Unpack(data.template subspan<Offset, Struct<T>::kSize>());
+}
+
+/**
+ * Pack a serialized struct.
+ *
+ * @param data struct storage (mutable, output)
+ * @param value object
+ */
+template <StructSerializable T>
+inline void PackStruct(
+    std::span<uint8_t, Struct<typename std::remove_cvref_t<T>>::kSize> data,
+    T&& value) {
+  Struct<typename std::remove_cvref_t<T>>::Pack(data, std::forward<T>(value));
+}
+
+/**
+ * Pack a serialized struct starting at a given offset within the data. This is
+ * primarily useful in pack implementations to pack nested structs.
+ *
+ * @tparam Offset starting offset
+ * @param data struct storage (mutable, output)
+ * @param value object
+ */
+template <size_t Offset, StructSerializable T>
+inline void PackStruct(std::span<uint8_t> data, T&& value) {
+  Struct<typename std::remove_cvref_t<T>>::Pack(
+      data.template subspan<Offset,
+                            Struct<typename std::remove_cvref_t<T>>::kSize>(),
+      std::forward<T>(value));
+}
+
+/**
+ * Unpack a serialized struct into an existing object, overwriting its contents.
+ *
+ * @param out object (output)
+ * @param data raw struct data
+ */
+template <StructSerializable T>
+inline void UnpackStructInto(T* out,
+                             std::span<const uint8_t, Struct<T>::kSize> data) {
+  if constexpr (MutableStructSerializable<T>) {
+    Struct<T>::UnpackInto(out, data);
+  } else {
+    *out = UnpackStruct<T>(data);
+  }
+}
+
+/**
+ * Unpack a serialized struct into an existing object, overwriting its contents,
+ * and starting at a given offset within the data.
+ * This is primarily useful in unpack implementations to unpack nested structs.
+ *
+ * @tparam Offset starting offset
+ * @param out object (output)
+ * @param data raw struct data
+ */
+template <size_t Offset, StructSerializable T>
+inline void UnpackStructInto(T* out, std::span<const uint8_t> data) {
+  if constexpr (MutableStructSerializable<T>) {
+    Struct<T>::UnpackInto(out,
+                          data.template subspan<Offset, Struct<T>::kSize>());
+  } else {
+    *out = UnpackStruct<T, Offset>(data);
+  }
+}
+
+/**
+ * Get the type string for a raw struct serializable type
+ *
+ * @tparam T serializable type
+ * @return type string
+ */
+template <StructSerializable T>
+constexpr auto GetStructTypeString() {
+  return Struct<T>::kTypeString;
+}
+
+template <StructSerializable T, size_t N>
+consteval auto MakeStructArrayTypeString() {
+  using namespace literals;
+  if constexpr (N == std::dynamic_extent) {
+    return Concat(
+        ct_string<char, std::char_traits<char>, Struct<T>::kTypeString.size()>{
+            Struct<T>::kTypeString},
+        "[]"_ct_string);
+  } else {
+    return Concat(
+        ct_string<char, std::char_traits<char>, Struct<T>::kTypeString.size()>{
+            Struct<T>::kTypeString},
+        "["_ct_string, NumToCtString<N>(), "]"_ct_string);
+  }
+}
+
+template <StructSerializable T, size_t N>
+consteval auto MakeStructArraySchema() {
+  using namespace literals;
+  if constexpr (N == std::dynamic_extent) {
+    return Concat(
+        ct_string<char, std::char_traits<char>, Struct<T>::kSchema.size()>{
+            Struct<T>::kSchema},
+        "[]"_ct_string);
+  } else {
+    return Concat(
+        ct_string<char, std::char_traits<char>, Struct<T>::kSchema.size()>{
+            Struct<T>::kSchema},
+        "["_ct_string, NumToCtString<N>(), "]"_ct_string);
+  }
+}
+
+template <StructSerializable T>
+constexpr std::string_view GetStructSchema() {
+  return Struct<T>::kSchema;
+}
+
+template <StructSerializable T>
+constexpr std::span<const uint8_t> GetStructSchemaBytes() {
+  return {reinterpret_cast<const uint8_t*>(Struct<T>::kSchema.data()),
+          Struct<T>::kSchema.size()};
+}
+
+template <StructSerializable T>
+void ForEachStructSchema(
+    std::invocable<std::string_view, std::string_view> auto fn) {
+  if constexpr (HasNestedStruct<T>) {
+    Struct<T>::ForEachNested(fn);
+  }
+  fn(Struct<T>::kTypeString, Struct<T>::kSchema);
+}
+
+template <StructSerializable T>
+class StructArrayBuffer {
+  using S = Struct<T>;
+
+ public:
+  StructArrayBuffer() = default;
+  StructArrayBuffer(const StructArrayBuffer&) = delete;
+  StructArrayBuffer& operator=(const StructArrayBuffer&) = delete;
+  StructArrayBuffer(StructArrayBuffer&& rhs) : m_buf{std::move(rhs.m_buf)} {}
+  StructArrayBuffer& operator=(StructArrayBuffer&& rhs) {
+    m_buf = std::move(rhs.m_buf);
+    return *this;
+  }
+
+  template <typename U, typename F>
+    requires
+#if __cpp_lib_ranges >= 201911L
+      std::ranges::range<U> &&
+      std::convertible_to<std::ranges::range_value_t<U>, T> &&
+#endif
+      std::invocable<F, std::span<const uint8_t>>
+    void Write(U&& data, F&& func) {
+    if ((std::size(data) * S::kSize) < 256) {
+      // use the stack
+      uint8_t buf[256];
+      auto out = buf;
+      for (auto&& val : data) {
+        S::Pack(std::span<uint8_t, S::kSize>{out, out + S::kSize},
+                std::forward<decltype(val)>(val));
+        out += S::kSize;
+      }
+      func(std::span<uint8_t>{buf, out});
+    } else {
+      std::scoped_lock lock{m_mutex};
+      m_buf.resize(std::size(data) * S::kSize);
+      auto out = m_buf.begin();
+      for (auto&& val : data) {
+        S::Pack(std::span<uint8_t, S::kSize>{out, out + S::kSize},
+                std::forward<decltype(val)>(val));
+        out += S::kSize;
+      }
+      func(m_buf);
+    }
+  }
+
+ private:
+  wpi::mutex m_mutex;
+  std::vector<uint8_t> m_buf;
+};
+
+/**
+ * Raw struct support for fixed-size arrays of other structs.
+ */
+template <StructSerializable T, size_t N>
+struct Struct<std::array<T, N>> {
+  static constexpr auto kTypeString = MakeStructArrayTypeString<T, N>();
+  static constexpr size_t kSize = N * Struct<T>::kSize;
+  static constexpr auto kSchema = MakeStructArraySchema<T, N>();
+  static std::array<T, N> Unpack(std::span<const uint8_t, kSize> data) {
+    std::array<T, N> result;
+    for (size_t i = 0; i < N; ++i) {
+      result[i] = UnpackStruct<T, 0>(data);
+      data = data.subspan(Struct<T>::kSize);
+    }
+    return result;
+  }
+  static void Pack(std::span<uint8_t, kSize> data,
+                   std::span<const T, N> values) {
+    std::span<uint8_t> unsizedData = data;
+    for (auto&& val : values) {
+      PackStruct<0>(unsizedData, val);
+      unsizedData = unsizedData.subspan(Struct<T>::kSize);
+    }
+  }
+  static void UnpackInto(std::array<T, N>* out,
+                         std::span<const uint8_t, kSize> data) {
+    UnpackInto(std::span{*out}, data);
+  }
+  // alternate span-based function
+  static void UnpackInto(std::span<T, N> out,
+                         std::span<const uint8_t, kSize> data) {
+    std::span<const uint8_t> unsizedData = data;
+    for (size_t i = 0; i < N; ++i) {
+      UnpackStructInto<0, T>(&out[i], unsizedData);
+      unsizedData = unsizedData.subspan(Struct<T>::kSize);
+    }
+  }
+};
+
+/**
+ * Raw struct support for boolean values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<bool> {
+  static constexpr std::string_view kTypeString = "struct:bool";
+  static constexpr size_t kSize = 1;
+  static constexpr std::string_view kSchema = "bool value";
+  static bool Unpack(std::span<const uint8_t, 1> data) { return data[0]; }
+  static void Pack(std::span<uint8_t, 1> data, bool value) {
+    data[0] = static_cast<char>(value ? 1 : 0);
+  }
+};
+
+/**
+ * Raw struct support for uint8_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<uint8_t> {
+  static constexpr std::string_view kTypeString = "struct:uint8";
+  static constexpr size_t kSize = 1;
+  static constexpr std::string_view kSchema = "uint8 value";
+  static uint8_t Unpack(std::span<const uint8_t, 1> data) { return data[0]; }
+  static void Pack(std::span<uint8_t, 1> data, uint8_t value) {
+    data[0] = value;
+  }
+};
+
+/**
+ * Raw struct support for int8_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<int8_t> {
+  static constexpr std::string_view kTypeString = "struct:int8";
+  static constexpr size_t kSize = 1;
+  static constexpr std::string_view kSchema = "int8 value";
+  static int8_t Unpack(std::span<const uint8_t, 1> data) { return data[0]; }
+  static void Pack(std::span<uint8_t, 1> data, int8_t value) {
+    data[0] = value;
+  }
+};
+
+/**
+ * Raw struct support for uint16_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<uint16_t> {
+  static constexpr std::string_view kTypeString = "struct:uint16";
+  static constexpr size_t kSize = 2;
+  static constexpr std::string_view kSchema = "uint16 value";
+  static uint16_t Unpack(std::span<const uint8_t, 2> data) {
+    return support::endian::read16le(data.data());
+  }
+  static void Pack(std::span<uint8_t, 2> data, uint16_t value) {
+    support::endian::write16le(data.data(), value);
+  }
+};
+
+/**
+ * Raw struct support for int16_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<int16_t> {
+  static constexpr std::string_view kTypeString = "struct:int16";
+  static constexpr size_t kSize = 2;
+  static constexpr std::string_view kSchema = "int16 value";
+  static int16_t Unpack(std::span<const uint8_t, 2> data) {
+    return support::endian::read16le(data.data());
+  }
+  static void Pack(std::span<uint8_t, 2> data, int16_t value) {
+    support::endian::write16le(data.data(), value);
+  }
+};
+
+/**
+ * Raw struct support for uint32_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<uint32_t> {
+  static constexpr std::string_view kTypeString = "struct:uint32";
+  static constexpr size_t kSize = 4;
+  static constexpr std::string_view kSchema = "uint32 value";
+  static uint32_t Unpack(std::span<const uint8_t, 4> data) {
+    return support::endian::read32le(data.data());
+  }
+  static void Pack(std::span<uint8_t, 4> data, uint32_t value) {
+    support::endian::write32le(data.data(), value);
+  }
+};
+
+/**
+ * Raw struct support for int32_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<int32_t> {
+  static constexpr std::string_view kTypeString = "struct:int32";
+  static constexpr size_t kSize = 4;
+  static constexpr std::string_view kSchema = "int32 value";
+  static int32_t Unpack(std::span<const uint8_t, 4> data) {
+    return support::endian::read32le(data.data());
+  }
+  static void Pack(std::span<uint8_t, 4> data, int32_t value) {
+    support::endian::write32le(data.data(), value);
+  }
+};
+
+/**
+ * Raw struct support for uint64_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<uint64_t> {
+  static constexpr std::string_view kTypeString = "struct:uint64";
+  static constexpr size_t kSize = 8;
+  static constexpr std::string_view kSchema = "uint64 value";
+  static uint64_t Unpack(std::span<const uint8_t, 8> data) {
+    return support::endian::read64le(data.data());
+  }
+  static void Pack(std::span<uint8_t, 8> data, uint64_t value) {
+    support::endian::write64le(data.data(), value);
+  }
+};
+
+/**
+ * Raw struct support for int64_t values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<int64_t> {
+  static constexpr std::string_view kTypeString = "struct:int64";
+  static constexpr size_t kSize = 8;
+  static constexpr std::string_view kSchema = "int64 value";
+  static int64_t Unpack(std::span<const uint8_t, 8> data) {
+    return support::endian::read64le(data.data());
+  }
+  static void Pack(std::span<uint8_t, 8> data, int64_t value) {
+    support::endian::write64le(data.data(), value);
+  }
+};
+
+/**
+ * Raw struct support for float values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<float> {
+  static constexpr std::string_view kTypeString = "struct:float";
+  static constexpr size_t kSize = 4;
+  static constexpr std::string_view kSchema = "float value";
+  static float Unpack(std::span<const uint8_t, 4> data) {
+    return bit_cast<float>(support::endian::read32le(data.data()));
+  }
+  static void Pack(std::span<uint8_t, 4> data, float value) {
+    support::endian::write32le(data.data(), bit_cast<uint32_t>(value));
+  }
+};
+
+/**
+ * Raw struct support for double values.
+ * Primarily useful for higher level struct implementations.
+ */
+template <>
+struct Struct<double> {
+  static constexpr std::string_view kTypeString = "struct:double";
+  static constexpr size_t kSize = 8;
+  static constexpr std::string_view kSchema = "double value";
+  static double Unpack(std::span<const uint8_t, 8> data) {
+    return bit_cast<double>(support::endian::read64le(data.data()));
+  }
+  static void Pack(std::span<uint8_t, 8> data, double value) {
+    support::endian::write64le(data.data(), bit_cast<uint64_t>(value));
+  }
+};
+
+}  // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/timestamp.h b/wpiutil/src/main/native/include/wpi/timestamp.h
index c50117c..c232481 100644
--- a/wpiutil/src/main/native/include/wpi/timestamp.h
+++ b/wpiutil/src/main/native/include/wpi/timestamp.h
@@ -12,6 +12,19 @@
 #endif
 
 /**
+ * Initialize the on-Rio Now() implementation to use the FPGA timestamp.
+ * No effect on non-Rio platforms. This is called by HAL_Initialize() and
+ * thus should generally not be called by user code.
+ */
+void WPI_Impl_SetupNowRio(void);
+
+/**
+ * De-initialize the on-Rio Now() implementation. No effect on non-Rio
+ * platforms.
+ */
+void WPI_Impl_ShutdownNowRio(void);
+
+/**
  * The default implementation used for Now().
  * In general this is the time returned by the operating system.
  * @return Time in microseconds.
@@ -48,12 +61,27 @@
 #ifdef __cplusplus
 namespace wpi {
 
+namespace impl {
+/**
+ * Initialize the on-Rio Now() implementation to use the FPGA timestamp.
+ * No effect on non-Rio platforms. This is called by HAL_Initialize() and
+ * thus should generally not be called by user code.
+ */
+void SetupNowRio();
+
+/**
+ * De-initialize the on-Rio Now() implementation. No effect on non-Rio
+ * platforms.
+ */
+void ShutdownNowRio();
+}  // namespace impl
+
 /**
  * The default implementation used for Now().
  * In general this is the time returned by the operating system.
  * @return Time in microseconds.
  */
-uint64_t NowDefault(void);
+uint64_t NowDefault();
 
 /**
  * Set the implementation used by Now().
@@ -68,7 +96,7 @@
  * This is a monotonic clock with an undefined epoch.
  * @return Time in microseconds.
  */
-uint64_t Now(void);
+uint64_t Now();
 
 /**
  * Return the current system time in microseconds since the Unix epoch
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
index a3966d1..2d684e7 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
@@ -1,4 +1,4 @@
-// Formatting library for C++ - dynamic format arguments
+// Formatting library for C++ - dynamic argument lists
 //
 // Copyright (c) 2012 - present, Victor Zverovich
 // All rights reserved.
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
index b112f76..ff3e144 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
@@ -22,6 +22,24 @@
 
 FMT_BEGIN_NAMESPACE
 
+// Check if std::chrono::local_t is available.
+#ifndef FMT_USE_LOCAL_TIME
+#  ifdef __cpp_lib_chrono
+#    define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L)
+#  else
+#    define FMT_USE_LOCAL_TIME 0
+#  endif
+#endif
+
+// Check if std::chrono::utc_timestamp is available.
+#ifndef FMT_USE_UTC_TIME
+#  ifdef __cpp_lib_chrono
+#    define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L)
+#  else
+#    define FMT_USE_UTC_TIME 0
+#  endif
+#endif
+
 // Enable tzset.
 #ifndef FMT_USE_TZSET
 // UWP doesn't provide _tzset.
@@ -203,7 +221,8 @@
     }
     const auto min1 =
         (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
-    if (!std::is_unsigned<IntermediateRep>::value && count < min1) {
+    if (detail::const_check(!std::is_unsigned<IntermediateRep>::value) &&
+        count < min1) {
       ec = 1;
       return {};
     }
@@ -358,37 +377,11 @@
     unit_t unit;
     write_codecvt(unit, in, loc);
     // In UTF-8 is used one to four one-byte code units.
-    auto&& buf = basic_memory_buffer<char, unit_t::max_size * 4>();
-    for (code_unit* p = unit.buf; p != unit.end; ++p) {
-      uint32_t c = static_cast<uint32_t>(*p);
-      if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
-        // surrogate pair
-        ++p;
-        if (p == unit.end || (c & 0xfc00) != 0xd800 ||
-            (*p & 0xfc00) != 0xdc00) {
-          FMT_THROW(format_error("failed to format time"));
-        }
-        c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
-      }
-      if (c < 0x80) {
-        buf.push_back(static_cast<char>(c));
-      } else if (c < 0x800) {
-        buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
-        buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
-      } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
-        buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
-        buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
-        buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
-      } else if (c >= 0x10000 && c <= 0x10ffff) {
-        buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
-        buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
-        buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
-        buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
-      } else {
-        FMT_THROW(format_error("failed to format time"));
-      }
-    }
-    return copy_str<char>(buf.data(), buf.data() + buf.size(), out);
+    auto u =
+        to_utf8<code_unit, basic_memory_buffer<char, unit_t::max_size * 4>>();
+    if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
+      FMT_THROW(format_error("failed to format time"));
+    return copy_str<char>(u.c_str(), u.c_str() + u.size(), out);
   }
   return copy_str<char>(in.data(), in.data() + in.size(), out);
 }
@@ -427,7 +420,7 @@
            char format, char modifier = 0) -> OutputIt {
   auto&& buf = get_buffer<Char>(out);
   do_write<Char>(buf, time, loc, format, modifier);
-  return buf.out();
+  return get_iterator(buf, out);
 }
 
 template <typename Char, typename OutputIt,
@@ -441,7 +434,7 @@
 
 }  // namespace detail
 
-FMT_MODULE_EXPORT_BEGIN
+FMT_BEGIN_EXPORT
 
 /**
   Converts given time since epoch as ``std::time_t`` value into calendar time,
@@ -484,10 +477,13 @@
   return lt.tm_;
 }
 
-inline std::tm localtime(
-    std::chrono::time_point<std::chrono::system_clock> time_point) {
-  return localtime(std::chrono::system_clock::to_time_t(time_point));
+#if FMT_USE_LOCAL_TIME
+template <typename Duration>
+inline auto localtime(std::chrono::local_time<Duration> time) -> std::tm {
+  return localtime(std::chrono::system_clock::to_time_t(
+      std::chrono::current_zone()->to_sys(time)));
 }
+#endif
 
 /**
   Converts given time since epoch as ``std::time_t`` value into calendar time,
@@ -523,7 +519,7 @@
     }
 #endif
   };
-  dispatcher gt(time);
+  auto gt = dispatcher(time);
   // Too big time values may be unsupported.
   if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
   return gt.tm_;
@@ -534,7 +530,7 @@
   return gmtime(std::chrono::system_clock::to_time_t(time_point));
 }
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 // Writes two-digit numbers a, b and c separated by sep to buf.
 // The method by Pavel Novikov based on
@@ -599,12 +595,39 @@
   alternative
 };
 
+// Glibc extensions for formatting numeric values.
+enum class pad_type {
+  unspecified,
+  // Do not pad a numeric result string.
+  none,
+  // Pad a numeric result string with zeros even if the conversion specifier
+  // character uses space-padding by default.
+  zero,
+  // Pad a numeric result string with spaces.
+  space,
+};
+
+template <typename OutputIt>
+auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt {
+  if (pad == pad_type::none) return out;
+  return std::fill_n(out, width, pad == pad_type::space ? ' ' : '0');
+}
+
+template <typename OutputIt>
+auto write_padding(OutputIt out, pad_type pad) -> OutputIt {
+  if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0';
+  return out;
+}
+
 // Parses a put_time-like format string and invokes handler actions.
 template <typename Char, typename Handler>
 FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
                                               const Char* end,
                                               Handler&& handler) {
+  if (begin == end || *begin == '}') return begin;
+  if (*begin != '%') FMT_THROW(format_error("invalid format"));
   auto ptr = begin;
+  pad_type pad = pad_type::unspecified;
   while (ptr != end) {
     auto c = *ptr;
     if (c == '}') break;
@@ -615,6 +638,22 @@
     if (begin != ptr) handler.on_text(begin, ptr);
     ++ptr;  // consume '%'
     if (ptr == end) FMT_THROW(format_error("invalid format"));
+    c = *ptr;
+    switch (c) {
+    case '_':
+      pad = pad_type::space;
+      ++ptr;
+      break;
+    case '-':
+      pad = pad_type::none;
+      ++ptr;
+      break;
+    case '0':
+      pad = pad_type::zero;
+      ++ptr;
+      break;
+    }
+    if (ptr == end) FMT_THROW(format_error("invalid format"));
     c = *ptr++;
     switch (c) {
     case '%':
@@ -691,16 +730,16 @@
       break;
     // Hour, minute, second:
     case 'H':
-      handler.on_24_hour(numeric_system::standard);
+      handler.on_24_hour(numeric_system::standard, pad);
       break;
     case 'I':
-      handler.on_12_hour(numeric_system::standard);
+      handler.on_12_hour(numeric_system::standard, pad);
       break;
     case 'M':
-      handler.on_minute(numeric_system::standard);
+      handler.on_minute(numeric_system::standard, pad);
       break;
     case 'S':
-      handler.on_second(numeric_system::standard);
+      handler.on_second(numeric_system::standard, pad);
       break;
     // Other:
     case 'c':
@@ -737,7 +776,7 @@
       handler.on_duration_unit();
       break;
     case 'z':
-      handler.on_utc_offset();
+      handler.on_utc_offset(numeric_system::standard);
       break;
     case 'Z':
       handler.on_tz_name();
@@ -765,6 +804,9 @@
       case 'X':
         handler.on_loc_time(numeric_system::alternative);
         break;
+      case 'z':
+        handler.on_utc_offset(numeric_system::alternative);
+        break;
       default:
         FMT_THROW(format_error("invalid format"));
       }
@@ -802,16 +844,19 @@
         handler.on_dec1_weekday(numeric_system::alternative);
         break;
       case 'H':
-        handler.on_24_hour(numeric_system::alternative);
+        handler.on_24_hour(numeric_system::alternative, pad);
         break;
       case 'I':
-        handler.on_12_hour(numeric_system::alternative);
+        handler.on_12_hour(numeric_system::alternative, pad);
         break;
       case 'M':
-        handler.on_minute(numeric_system::alternative);
+        handler.on_minute(numeric_system::alternative, pad);
         break;
       case 'S':
-        handler.on_second(numeric_system::alternative);
+        handler.on_second(numeric_system::alternative, pad);
+        break;
+      case 'z':
+        handler.on_utc_offset(numeric_system::alternative);
         break;
       default:
         FMT_THROW(format_error("invalid format"));
@@ -864,7 +909,7 @@
   FMT_CONSTEXPR void on_am_pm() { unsupported(); }
   FMT_CONSTEXPR void on_duration_value() { unsupported(); }
   FMT_CONSTEXPR void on_duration_unit() { unsupported(); }
-  FMT_CONSTEXPR void on_utc_offset() { unsupported(); }
+  FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); }
   FMT_CONSTEXPR void on_tz_name() { unsupported(); }
 };
 
@@ -892,10 +937,10 @@
   FMT_CONSTEXPR void on_day_of_year() {}
   FMT_CONSTEXPR void on_day_of_month(numeric_system) {}
   FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {}
-  FMT_CONSTEXPR void on_24_hour(numeric_system) {}
-  FMT_CONSTEXPR void on_12_hour(numeric_system) {}
-  FMT_CONSTEXPR void on_minute(numeric_system) {}
-  FMT_CONSTEXPR void on_second(numeric_system) {}
+  FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {}
+  FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {}
+  FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {}
+  FMT_CONSTEXPR void on_second(numeric_system, pad_type) {}
   FMT_CONSTEXPR void on_datetime(numeric_system) {}
   FMT_CONSTEXPR void on_loc_date(numeric_system) {}
   FMT_CONSTEXPR void on_loc_time(numeric_system) {}
@@ -905,7 +950,7 @@
   FMT_CONSTEXPR void on_24_hour_time() {}
   FMT_CONSTEXPR void on_iso_time() {}
   FMT_CONSTEXPR void on_am_pm() {}
-  FMT_CONSTEXPR void on_utc_offset() {}
+  FMT_CONSTEXPR void on_utc_offset(numeric_system) {}
   FMT_CONSTEXPR void on_tz_name() {}
 };
 
@@ -957,13 +1002,130 @@
 }
 #endif
 
-template <typename OutputIt, typename Char> class tm_writer {
+// Converts value to Int and checks that it's in the range [0, upper).
+template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
+inline Int to_nonnegative_int(T value, Int upper) {
+  FMT_ASSERT(std::is_unsigned<Int>::value ||
+                 (value >= 0 && to_unsigned(value) <= to_unsigned(upper)),
+             "invalid value");
+  (void)upper;
+  return static_cast<Int>(value);
+}
+template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
+inline Int to_nonnegative_int(T value, Int upper) {
+  if (value < 0 || value > static_cast<T>(upper))
+    FMT_THROW(format_error("invalid value"));
+  return static_cast<Int>(value);
+}
+
+constexpr long long pow10(std::uint32_t n) {
+  return n == 0 ? 1 : 10 * pow10(n - 1);
+}
+
+// Counts the number of fractional digits in the range [0, 18] according to the
+// C++20 spec. If more than 18 fractional digits are required then returns 6 for
+// microseconds precision.
+template <long long Num, long long Den, int N = 0,
+          bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
+struct count_fractional_digits {
+  static constexpr int value =
+      Num % Den == 0 ? N : count_fractional_digits<Num * 10, Den, N + 1>::value;
+};
+
+// Base case that doesn't instantiate any more templates
+// in order to avoid overflow.
+template <long long Num, long long Den, int N>
+struct count_fractional_digits<Num, Den, N, false> {
+  static constexpr int value = (Num % Den == 0) ? N : 6;
+};
+
+// Format subseconds which are given as an integer type with an appropriate
+// number of digits.
+template <typename Char, typename OutputIt, typename Duration>
+void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) {
+  constexpr auto num_fractional_digits =
+      count_fractional_digits<Duration::period::num,
+                              Duration::period::den>::value;
+
+  using subsecond_precision = std::chrono::duration<
+      typename std::common_type<typename Duration::rep,
+                                std::chrono::seconds::rep>::type,
+      std::ratio<1, detail::pow10(num_fractional_digits)>>;
+
+  const auto fractional =
+      d - std::chrono::duration_cast<std::chrono::seconds>(d);
+  const auto subseconds =
+      std::chrono::treat_as_floating_point<
+          typename subsecond_precision::rep>::value
+          ? fractional.count()
+          : std::chrono::duration_cast<subsecond_precision>(fractional).count();
+  auto n = static_cast<uint32_or_64_or_128_t<long long>>(subseconds);
+  const int num_digits = detail::count_digits(n);
+
+  int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
+  if (precision < 0) {
+    FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
+    if (std::ratio_less<typename subsecond_precision::period,
+                        std::chrono::seconds::period>::value) {
+      *out++ = '.';
+      out = std::fill_n(out, leading_zeroes, '0');
+      out = format_decimal<Char>(out, n, num_digits).end;
+    }
+  } else {
+    *out++ = '.';
+    leading_zeroes = (std::min)(leading_zeroes, precision);
+    out = std::fill_n(out, leading_zeroes, '0');
+    int remaining = precision - leading_zeroes;
+    if (remaining != 0 && remaining < num_digits) {
+      n /= to_unsigned(detail::pow10(to_unsigned(num_digits - remaining)));
+      out = format_decimal<Char>(out, n, remaining).end;
+      return;
+    }
+    out = format_decimal<Char>(out, n, num_digits).end;
+    remaining -= num_digits;
+    out = std::fill_n(out, remaining, '0');
+  }
+}
+
+// Format subseconds which are given as a floating point type with an
+// appropriate number of digits. We cannot pass the Duration here, as we
+// explicitly need to pass the Rep value in the chrono_formatter.
+template <typename Duration>
+void write_floating_seconds(memory_buffer& buf, Duration duration,
+                            int num_fractional_digits = -1) {
+  using rep = typename Duration::rep;
+  FMT_ASSERT(std::is_floating_point<rep>::value, "");
+
+  auto val = duration.count();
+
+  if (num_fractional_digits < 0) {
+    // For `std::round` with fallback to `round`:
+    // On some toolchains `std::round` is not available (e.g. GCC 6).
+    using namespace std;
+    num_fractional_digits =
+        count_fractional_digits<Duration::period::num,
+                                Duration::period::den>::value;
+    if (num_fractional_digits < 6 && static_cast<rep>(round(val)) != val)
+      num_fractional_digits = 6;
+  }
+
+  format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"),
+            std::fmod(val * static_cast<rep>(Duration::period::num) /
+                          static_cast<rep>(Duration::period::den),
+                      static_cast<rep>(60)),
+            num_fractional_digits);
+}
+
+template <typename OutputIt, typename Char,
+          typename Duration = std::chrono::seconds>
+class tm_writer {
  private:
   static constexpr int days_per_week = 7;
 
   const std::locale& loc_;
   const bool is_classic_;
   OutputIt out_;
+  const Duration* subsecs_;
   const std::tm& tm_;
 
   auto tm_sec() const noexcept -> int {
@@ -1051,6 +1213,17 @@
     *out_++ = *d++;
     *out_++ = *d;
   }
+  void write2(int value, pad_type pad) {
+    unsigned int v = to_unsigned(value) % 100;
+    if (v >= 10) {
+      const char* d = digits2(v);
+      *out_++ = *d++;
+      *out_++ = *d;
+    } else {
+      out_ = detail::write_padding(out_, pad);
+      *out_++ = static_cast<char>('0' + v);
+    }
+  }
 
   void write_year_extended(long long year) {
     // At least 4 characters.
@@ -1074,7 +1247,7 @@
     }
   }
 
-  void write_utc_offset(long offset) {
+  void write_utc_offset(long offset, numeric_system ns) {
     if (offset < 0) {
       *out_++ = '-';
       offset = -offset;
@@ -1083,14 +1256,15 @@
     }
     offset /= 60;
     write2(static_cast<int>(offset / 60));
+    if (ns != numeric_system::standard) *out_++ = ':';
     write2(static_cast<int>(offset % 60));
   }
   template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
-  void format_utc_offset_impl(const T& tm) {
-    write_utc_offset(tm.tm_gmtoff);
+  void format_utc_offset_impl(const T& tm, numeric_system ns) {
+    write_utc_offset(tm.tm_gmtoff, ns);
   }
   template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
-  void format_utc_offset_impl(const T& tm) {
+  void format_utc_offset_impl(const T& tm, numeric_system ns) {
 #if defined(_WIN32) && defined(_UCRT)
 #  if FMT_USE_TZSET
     tzset_once();
@@ -1102,10 +1276,17 @@
       _get_dstbias(&dstbias);
       offset += dstbias;
     }
-    write_utc_offset(-offset);
+    write_utc_offset(-offset, ns);
 #else
-    ignore_unused(tm);
-    format_localized('z');
+    if (ns == numeric_system::standard) return format_localized('z');
+
+    // Extract timezone offset from timezone conversion functions.
+    std::tm gtm = tm;
+    std::time_t gt = std::mktime(&gtm);
+    std::tm ltm = gmtime(gt);
+    std::time_t lt = std::mktime(&ltm);
+    long offset = gt - lt;
+    write_utc_offset(offset, ns);
 #endif
   }
 
@@ -1126,10 +1307,12 @@
   }
 
  public:
-  tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm)
+  tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm,
+            const Duration* subsecs = nullptr)
       : loc_(loc),
         is_classic_(loc_ == get_classic_locale()),
         out_(out),
+        subsecs_(subsecs),
         tm_(tm) {}
 
   OutputIt out() const { return out_; }
@@ -1227,7 +1410,7 @@
     out_ = copy_str<Char>(std::begin(buf) + offset, std::end(buf), out_);
   }
 
-  void on_utc_offset() { format_utc_offset_impl(tm_); }
+  void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
   void on_tz_name() { format_tz_name_impl(tm_); }
 
   void on_year(numeric_system ns) {
@@ -1315,22 +1498,41 @@
     }
   }
 
-  void on_24_hour(numeric_system ns) {
-    if (is_classic_ || ns == numeric_system::standard) return write2(tm_hour());
+  void on_24_hour(numeric_system ns, pad_type pad) {
+    if (is_classic_ || ns == numeric_system::standard)
+      return write2(tm_hour(), pad);
     format_localized('H', 'O');
   }
-  void on_12_hour(numeric_system ns) {
+  void on_12_hour(numeric_system ns, pad_type pad) {
     if (is_classic_ || ns == numeric_system::standard)
-      return write2(tm_hour12());
+      return write2(tm_hour12(), pad);
     format_localized('I', 'O');
   }
-  void on_minute(numeric_system ns) {
-    if (is_classic_ || ns == numeric_system::standard) return write2(tm_min());
+  void on_minute(numeric_system ns, pad_type pad) {
+    if (is_classic_ || ns == numeric_system::standard)
+      return write2(tm_min(), pad);
     format_localized('M', 'O');
   }
-  void on_second(numeric_system ns) {
-    if (is_classic_ || ns == numeric_system::standard) return write2(tm_sec());
-    format_localized('S', 'O');
+
+  void on_second(numeric_system ns, pad_type pad) {
+    if (is_classic_ || ns == numeric_system::standard) {
+      write2(tm_sec(), pad);
+      if (subsecs_) {
+        if (std::is_floating_point<typename Duration::rep>::value) {
+          auto buf = memory_buffer();
+          write_floating_seconds(buf, *subsecs_);
+          if (buf.size() > 1) {
+            // Remove the leading "0", write something like ".123".
+            out_ = std::copy(buf.begin() + 1, buf.end(), out_);
+          }
+        } else {
+          write_fractional_seconds<Char>(out_, *subsecs_);
+        }
+      }
+    } else {
+      // Currently no formatting of subseconds when a locale is set.
+      format_localized('S', 'O');
+    }
   }
 
   void on_12_hour_time() {
@@ -1351,10 +1553,9 @@
     write2(tm_min());
   }
   void on_iso_time() {
-    char buf[8];
-    write_digit2_separated(buf, to_unsigned(tm_hour()), to_unsigned(tm_min()),
-                           to_unsigned(tm_sec()), ':');
-    out_ = copy_str<Char>(std::begin(buf), std::end(buf), out_);
+    on_24_hour_time();
+    *out_++ = ':';
+    on_second(numeric_system::standard, pad_type::unspecified);
   }
 
   void on_am_pm() {
@@ -1372,43 +1573,34 @@
 };
 
 struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
+  bool has_precision_integral = false;
+
   FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); }
 
   template <typename Char>
   FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
-  FMT_CONSTEXPR void on_24_hour(numeric_system) {}
-  FMT_CONSTEXPR void on_12_hour(numeric_system) {}
-  FMT_CONSTEXPR void on_minute(numeric_system) {}
-  FMT_CONSTEXPR void on_second(numeric_system) {}
+  FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {}
+  FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {}
+  FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {}
+  FMT_CONSTEXPR void on_second(numeric_system, pad_type) {}
   FMT_CONSTEXPR void on_12_hour_time() {}
   FMT_CONSTEXPR void on_24_hour_time() {}
   FMT_CONSTEXPR void on_iso_time() {}
   FMT_CONSTEXPR void on_am_pm() {}
-  FMT_CONSTEXPR void on_duration_value() {}
+  FMT_CONSTEXPR void on_duration_value() const {
+    if (has_precision_integral) {
+      FMT_THROW(format_error("precision not allowed for this argument type"));
+    }
+  }
   FMT_CONSTEXPR void on_duration_unit() {}
 };
 
-template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
+template <typename T,
+          FMT_ENABLE_IF(std::is_integral<T>::value&& has_isfinite<T>::value)>
 inline bool isfinite(T) {
   return true;
 }
 
-// Converts value to Int and checks that it's in the range [0, upper).
-template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
-inline Int to_nonnegative_int(T value, Int upper) {
-  FMT_ASSERT(std::is_unsigned<Int>::value ||
-             (value >= 0 && to_unsigned(value) <= to_unsigned(upper)),
-             "invalid value");
-  (void)upper;
-  return static_cast<Int>(value);
-}
-template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
-inline Int to_nonnegative_int(T value, Int upper) {
-  if (value < 0 || value > static_cast<T>(upper))
-    FMT_THROW(format_error("invalid value"));
-  return static_cast<Int>(value);
-}
-
 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 inline T mod(T x, int y) {
   return x % static_cast<T>(y);
@@ -1463,47 +1655,6 @@
 #endif
 }
 
-// Counts the number of fractional digits in the range [0, 18] according to the
-// C++20 spec. If more than 18 fractional digits are required then returns 6 for
-// microseconds precision.
-template <long long Num, long long Den, int N = 0,
-          bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
-struct count_fractional_digits {
-  static constexpr int value =
-      Num % Den == 0 ? N : count_fractional_digits<Num * 10, Den, N + 1>::value;
-};
-
-// Base case that doesn't instantiate any more templates
-// in order to avoid overflow.
-template <long long Num, long long Den, int N>
-struct count_fractional_digits<Num, Den, N, false> {
-  static constexpr int value = (Num % Den == 0) ? N : 6;
-};
-
-constexpr long long pow10(std::uint32_t n) {
-  return n == 0 ? 1 : 10 * pow10(n - 1);
-}
-
-template <class Rep, class Period,
-          FMT_ENABLE_IF(std::numeric_limits<Rep>::is_signed)>
-constexpr std::chrono::duration<Rep, Period> abs(
-    std::chrono::duration<Rep, Period> d) {
-  // We need to compare the duration using the count() method directly
-  // due to a compiler bug in clang-11 regarding the spaceship operator,
-  // when -Wzero-as-null-pointer-constant is enabled.
-  // In clang-12 the bug has been fixed. See
-  // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example:
-  // https://www.godbolt.org/z/Knbb5joYx.
-  return d.count() >= d.zero().count() ? d : -d;
-}
-
-template <class Rep, class Period,
-          FMT_ENABLE_IF(!std::numeric_limits<Rep>::is_signed)>
-constexpr std::chrono::duration<Rep, Period> abs(
-    std::chrono::duration<Rep, Period> d) {
-  return d;
-}
-
 template <typename Char, typename Rep, typename OutputIt,
           FMT_ENABLE_IF(std::is_integral<Rep>::value)>
 OutputIt format_duration_value(OutputIt out, Rep val, int) {
@@ -1513,7 +1664,7 @@
 template <typename Char, typename Rep, typename OutputIt,
           FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
 OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
-  auto specs = basic_format_specs<Char>();
+  auto specs = format_specs<Char>();
   specs.precision = precision;
   specs.type = precision >= 0 ? presentation_type::fixed_lower
                               : presentation_type::general_lower;
@@ -1654,44 +1805,16 @@
     }
   }
 
-  void write(Rep value, int width) {
+  void write(Rep value, int width, pad_type pad = pad_type::unspecified) {
     write_sign();
     if (isnan(value)) return write_nan();
     uint32_or_64_or_128_t<int> n =
         to_unsigned(to_nonnegative_int(value, max_value<int>()));
     int num_digits = detail::count_digits(n);
-    if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
-    out = format_decimal<char_type>(out, n, num_digits).end;
-  }
-
-  template <typename Duration> void write_fractional_seconds(Duration d) {
-    FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
-    constexpr auto num_fractional_digits =
-        count_fractional_digits<Duration::period::num,
-                                Duration::period::den>::value;
-
-    using subsecond_precision = std::chrono::duration<
-        typename std::common_type<typename Duration::rep,
-                                  std::chrono::seconds::rep>::type,
-        std::ratio<1, detail::pow10(num_fractional_digits)>>;
-    if (std::ratio_less<typename subsecond_precision::period,
-                        std::chrono::seconds::period>::value) {
-      *out++ = '.';
-      auto fractional =
-          detail::abs(d) - std::chrono::duration_cast<std::chrono::seconds>(d);
-      auto subseconds =
-          std::chrono::treat_as_floating_point<
-              typename subsecond_precision::rep>::value
-              ? fractional.count()
-              : std::chrono::duration_cast<subsecond_precision>(fractional)
-                    .count();
-      uint32_or_64_or_128_t<long long> n =
-          to_unsigned(to_nonnegative_int(subseconds, max_value<long long>()));
-      int num_digits = detail::count_digits(n);
-      if (num_fractional_digits > num_digits)
-        out = std::fill_n(out, num_fractional_digits - num_digits, '0');
-      out = format_decimal<char_type>(out, n, num_digits).end;
+    if (width > num_digits) {
+      out = detail::write_padding(out, pad, width - num_digits);
     }
+    out = format_decimal<char_type>(out, n, num_digits).end;
   }
 
   void write_nan() { std::copy_n("nan", 3, out); }
@@ -1723,7 +1846,7 @@
   void on_loc_time(numeric_system) {}
   void on_us_date() {}
   void on_iso_date() {}
-  void on_utc_offset() {}
+  void on_utc_offset(numeric_system) {}
   void on_tz_name() {}
   void on_year(numeric_system) {}
   void on_short_year(numeric_system) {}
@@ -1739,58 +1862,56 @@
   void on_day_of_month(numeric_system) {}
   void on_day_of_month_space(numeric_system) {}
 
-  void on_24_hour(numeric_system ns) {
+  void on_24_hour(numeric_system ns, pad_type pad) {
     if (handle_nan_inf()) return;
 
-    if (ns == numeric_system::standard) return write(hour(), 2);
+    if (ns == numeric_system::standard) return write(hour(), 2, pad);
     auto time = tm();
     time.tm_hour = to_nonnegative_int(hour(), 24);
-    format_tm(time, &tm_writer_type::on_24_hour, ns);
+    format_tm(time, &tm_writer_type::on_24_hour, ns, pad);
   }
 
-  void on_12_hour(numeric_system ns) {
+  void on_12_hour(numeric_system ns, pad_type pad) {
     if (handle_nan_inf()) return;
 
-    if (ns == numeric_system::standard) return write(hour12(), 2);
+    if (ns == numeric_system::standard) return write(hour12(), 2, pad);
     auto time = tm();
     time.tm_hour = to_nonnegative_int(hour12(), 12);
-    format_tm(time, &tm_writer_type::on_12_hour, ns);
+    format_tm(time, &tm_writer_type::on_12_hour, ns, pad);
   }
 
-  void on_minute(numeric_system ns) {
+  void on_minute(numeric_system ns, pad_type pad) {
     if (handle_nan_inf()) return;
 
-    if (ns == numeric_system::standard) return write(minute(), 2);
+    if (ns == numeric_system::standard) return write(minute(), 2, pad);
     auto time = tm();
     time.tm_min = to_nonnegative_int(minute(), 60);
-    format_tm(time, &tm_writer_type::on_minute, ns);
+    format_tm(time, &tm_writer_type::on_minute, ns, pad);
   }
 
-  void on_second(numeric_system ns) {
+  void on_second(numeric_system ns, pad_type pad) {
     if (handle_nan_inf()) return;
 
     if (ns == numeric_system::standard) {
       if (std::is_floating_point<rep>::value) {
-        constexpr auto num_fractional_digits =
-            count_fractional_digits<Period::num, Period::den>::value;
         auto buf = memory_buffer();
-        format_to(std::back_inserter(buf), runtime("{:.{}f}"),
-                  std::fmod(val * static_cast<rep>(Period::num) /
-                                static_cast<rep>(Period::den),
-                            static_cast<rep>(60)),
-                  num_fractional_digits);
+        write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
+                               precision);
         if (negative) *out++ = '-';
-        if (buf.size() < 2 || buf[1] == '.') *out++ = '0';
+        if (buf.size() < 2 || buf[1] == '.') {
+          out = detail::write_padding(out, pad);
+        }
         out = std::copy(buf.begin(), buf.end(), out);
       } else {
-        write(second(), 2);
-        write_fractional_seconds(std::chrono::duration<rep, Period>(val));
+        write(second(), 2, pad);
+        write_fractional_seconds<char_type>(
+            out, std::chrono::duration<rep, Period>(val), precision);
       }
       return;
     }
     auto time = tm();
     time.tm_sec = to_nonnegative_int(second(), 60);
-    format_tm(time, &tm_writer_type::on_second, ns);
+    format_tm(time, &tm_writer_type::on_second, ns, pad);
   }
 
   void on_12_hour_time() {
@@ -1814,7 +1935,7 @@
     on_24_hour_time();
     *out++ = ':';
     if (handle_nan_inf()) return;
-    on_second(numeric_system::standard);
+    on_second(numeric_system::standard, pad_type::unspecified);
   }
 
   void on_am_pm() {
@@ -1833,7 +1954,7 @@
   }
 };
 
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
 #if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
 using weekday = std::chrono::weekday;
@@ -1883,118 +2004,67 @@
 template <typename Rep, typename Period, typename Char>
 struct formatter<std::chrono::duration<Rep, Period>, Char> {
  private:
-  basic_format_specs<Char> specs;
-  int precision = -1;
-  using arg_ref_type = detail::arg_ref<Char>;
-  arg_ref_type width_ref;
-  arg_ref_type precision_ref;
-  bool localized = false;
-  basic_string_view<Char> format_str;
-  using duration = std::chrono::duration<Rep, Period>;
-
-  struct spec_handler {
-    formatter& f;
-    basic_format_parse_context<Char>& context;
-    basic_string_view<Char> format_str;
-
-    template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
-      context.check_arg_id(arg_id);
-      return arg_ref_type(arg_id);
-    }
-
-    FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) {
-      context.check_arg_id(arg_id);
-      return arg_ref_type(arg_id);
-    }
-
-    FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) {
-      return arg_ref_type(context.next_arg_id());
-    }
-
-    void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
-    FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
-      f.specs.fill = fill;
-    }
-    FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; }
-    FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; }
-    FMT_CONSTEXPR void on_precision(int _precision) {
-      f.precision = _precision;
-    }
-    FMT_CONSTEXPR void end_precision() {}
-
-    template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
-      f.width_ref = make_arg_ref(arg_id);
-    }
-
-    template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
-      f.precision_ref = make_arg_ref(arg_id);
-    }
-  };
-
-  using iterator = typename basic_format_parse_context<Char>::iterator;
-  struct parse_range {
-    iterator begin;
-    iterator end;
-  };
-
-  FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context<Char>& ctx) {
-    auto begin = ctx.begin(), end = ctx.end();
-    if (begin == end || *begin == '}') return {begin, begin};
-    spec_handler handler{*this, ctx, format_str};
-    begin = detail::parse_align(begin, end, handler);
-    if (begin == end) return {begin, begin};
-    begin = detail::parse_width(begin, end, handler);
-    if (begin == end) return {begin, begin};
-    if (*begin == '.') {
-      if (std::is_floating_point<Rep>::value)
-        begin = detail::parse_precision(begin, end, handler);
-      else
-        handler.on_error("precision not allowed for this argument type");
-    }
-    if (begin != end && *begin == 'L') {
-      ++begin;
-      localized = true;
-    }
-    end = detail::parse_chrono_format(begin, end,
-                                      detail::chrono_format_checker());
-    return {begin, end};
-  }
+  format_specs<Char> specs_;
+  detail::arg_ref<Char> width_ref_;
+  detail::arg_ref<Char> precision_ref_;
+  bool localized_ = false;
+  basic_string_view<Char> format_str_;
 
  public:
   FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
       -> decltype(ctx.begin()) {
-    auto range = do_parse(ctx);
-    format_str = basic_string_view<Char>(
-        &*range.begin, detail::to_unsigned(range.end - range.begin));
-    return range.end;
+    auto it = ctx.begin(), end = ctx.end();
+    if (it == end || *it == '}') return it;
+
+    it = detail::parse_align(it, end, specs_);
+    if (it == end) return it;
+
+    it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
+    if (it == end) return it;
+
+    auto checker = detail::chrono_format_checker();
+    if (*it == '.') {
+      checker.has_precision_integral = !std::is_floating_point<Rep>::value;
+      it = detail::parse_precision(it, end, specs_.precision, precision_ref_,
+                                   ctx);
+    }
+    if (it != end && *it == 'L') {
+      localized_ = true;
+      ++it;
+    }
+    end = detail::parse_chrono_format(it, end, checker);
+    format_str_ = {it, detail::to_unsigned(end - it)};
+    return end;
   }
 
   template <typename FormatContext>
-  auto format(const duration& d, FormatContext& ctx) const
+  auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx) const
       -> decltype(ctx.out()) {
-    auto specs_copy = specs;
-    auto precision_copy = precision;
-    auto begin = format_str.begin(), end = format_str.end();
+    auto specs = specs_;
+    auto precision = specs.precision;
+    specs.precision = -1;
+    auto begin = format_str_.begin(), end = format_str_.end();
     // As a possible future optimization, we could avoid extra copying if width
     // is not specified.
-    basic_memory_buffer<Char> buf;
+    auto buf = basic_memory_buffer<Char>();
     auto out = std::back_inserter(buf);
-    detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
-                                                       width_ref, ctx);
-    detail::handle_dynamic_spec<detail::precision_checker>(precision_copy,
-                                                           precision_ref, ctx);
+    detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
+                                                       ctx);
+    detail::handle_dynamic_spec<detail::precision_checker>(precision,
+                                                           precision_ref_, ctx);
     if (begin == end || *begin == '}') {
-      out = detail::format_duration_value<Char>(out, d.count(), precision_copy);
+      out = detail::format_duration_value<Char>(out, d.count(), precision);
       detail::format_duration_unit<Char, Period>(out);
     } else {
-      detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
-          ctx, out, d);
-      f.precision = precision_copy;
-      f.localized = localized;
+      using chrono_formatter =
+          detail::chrono_formatter<FormatContext, decltype(out), Rep, Period>;
+      auto f = chrono_formatter(ctx, out, d);
+      f.precision = precision;
+      f.localized = localized_;
       detail::parse_chrono_format(begin, end, f);
     }
     return detail::write(
-        ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy);
+        ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
   }
 };
 
@@ -2002,68 +2072,137 @@
 struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
                  Char> : formatter<std::tm, Char> {
   FMT_CONSTEXPR formatter() {
-    basic_string_view<Char> default_specs =
-        detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
-    this->do_parse(default_specs.begin(), default_specs.end());
+    this->format_str_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
   }
 
   template <typename FormatContext>
-  auto format(std::chrono::time_point<std::chrono::system_clock> val,
+  auto format(std::chrono::time_point<std::chrono::system_clock, Duration> val,
               FormatContext& ctx) const -> decltype(ctx.out()) {
-    return formatter<std::tm, Char>::format(localtime(val), ctx);
+    using period = typename Duration::period;
+    if (detail::const_check(
+            period::num != 1 || period::den != 1 ||
+            std::is_floating_point<typename Duration::rep>::value)) {
+      const auto epoch = val.time_since_epoch();
+      auto subsecs = std::chrono::duration_cast<Duration>(
+          epoch - std::chrono::duration_cast<std::chrono::seconds>(epoch));
+
+      if (subsecs.count() < 0) {
+        auto second =
+            std::chrono::duration_cast<Duration>(std::chrono::seconds(1));
+        if (epoch.count() < ((Duration::min)() + second).count())
+          FMT_THROW(format_error("duration is too small"));
+        subsecs += second;
+        val -= second;
+      }
+
+      return formatter<std::tm, Char>::do_format(
+          gmtime(std::chrono::time_point_cast<std::chrono::seconds>(val)), ctx,
+          &subsecs);
+    }
+
+    return formatter<std::tm, Char>::format(
+        gmtime(std::chrono::time_point_cast<std::chrono::seconds>(val)), ctx);
   }
 };
 
+#if FMT_USE_LOCAL_TIME
+template <typename Char, typename Duration>
+struct formatter<std::chrono::local_time<Duration>, Char>
+    : formatter<std::tm, Char> {
+  FMT_CONSTEXPR formatter() {
+    this->format_str_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
+  }
+
+  template <typename FormatContext>
+  auto format(std::chrono::local_time<Duration> val, FormatContext& ctx) const
+      -> decltype(ctx.out()) {
+    using period = typename Duration::period;
+    if (period::num != 1 || period::den != 1 ||
+        std::is_floating_point<typename Duration::rep>::value) {
+      const auto epoch = val.time_since_epoch();
+      const auto subsecs = std::chrono::duration_cast<Duration>(
+          epoch - std::chrono::duration_cast<std::chrono::seconds>(epoch));
+
+      return formatter<std::tm, Char>::do_format(
+          localtime(std::chrono::time_point_cast<std::chrono::seconds>(val)),
+          ctx, &subsecs);
+    }
+
+    return formatter<std::tm, Char>::format(
+        localtime(std::chrono::time_point_cast<std::chrono::seconds>(val)),
+        ctx);
+  }
+};
+#endif
+
+#if FMT_USE_UTC_TIME
+template <typename Char, typename Duration>
+struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,
+                 Char>
+    : formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
+                Char> {
+  template <typename FormatContext>
+  auto format(std::chrono::time_point<std::chrono::utc_clock, Duration> val,
+              FormatContext& ctx) const -> decltype(ctx.out()) {
+    return formatter<
+        std::chrono::time_point<std::chrono::system_clock, Duration>,
+        Char>::format(std::chrono::utc_clock::to_sys(val), ctx);
+  }
+};
+#endif
+
 template <typename Char> struct formatter<std::tm, Char> {
  private:
-  enum class spec {
-    unknown,
-    year_month_day,
-    hh_mm_ss,
-  };
-  spec spec_ = spec::unknown;
-  basic_string_view<Char> specs;
+  format_specs<Char> specs_;
+  detail::arg_ref<Char> width_ref_;
 
  protected:
-  template <typename It> FMT_CONSTEXPR auto do_parse(It begin, It end) -> It {
-    if (begin != end && *begin == ':') ++begin;
-    end = detail::parse_chrono_format(begin, end, detail::tm_format_checker());
-    // Replace default spec only if the new spec is not empty.
-    if (end != begin) specs = {begin, detail::to_unsigned(end - begin)};
-    return end;
+  basic_string_view<Char> format_str_;
+
+  template <typename FormatContext, typename Duration>
+  auto do_format(const std::tm& tm, FormatContext& ctx,
+                 const Duration* subsecs) const -> decltype(ctx.out()) {
+    auto specs = specs_;
+    auto buf = basic_memory_buffer<Char>();
+    auto out = std::back_inserter(buf);
+    detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
+                                                       ctx);
+
+    auto loc_ref = ctx.locale();
+    detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
+    auto w =
+        detail::tm_writer<decltype(out), Char, Duration>(loc, out, tm, subsecs);
+    detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w);
+    return detail::write(
+        ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
   }
 
  public:
   FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
       -> decltype(ctx.begin()) {
-    auto end = this->do_parse(ctx.begin(), ctx.end());
-    // basic_string_view<>::compare isn't constexpr before C++17.
-    if (specs.size() == 2 && specs[0] == Char('%')) {
-      if (specs[1] == Char('F'))
-        spec_ = spec::year_month_day;
-      else if (specs[1] == Char('T'))
-        spec_ = spec::hh_mm_ss;
-    }
+    auto it = ctx.begin(), end = ctx.end();
+    if (it == end || *it == '}') return it;
+
+    it = detail::parse_align(it, end, specs_);
+    if (it == end) return it;
+
+    it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
+    if (it == end) return it;
+
+    end = detail::parse_chrono_format(it, end, detail::tm_format_checker());
+    // Replace the default format_str only if the new spec is not empty.
+    if (end != it) format_str_ = {it, detail::to_unsigned(end - it)};
     return end;
   }
 
   template <typename FormatContext>
   auto format(const std::tm& tm, FormatContext& ctx) const
       -> decltype(ctx.out()) {
-    const auto loc_ref = ctx.locale();
-    detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
-    auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), tm);
-    if (spec_ == spec::year_month_day)
-      w.on_iso_date();
-    else if (spec_ == spec::hh_mm_ss)
-      w.on_iso_time();
-    else
-      detail::parse_chrono_format(specs.begin(), specs.end(), w);
-    return w.out();
+    return do_format<FormatContext, std::chrono::seconds>(tm, ctx, nullptr);
   }
 };
 
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_CHRONO_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
index 4c16327..8697e1c 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
@@ -11,7 +11,7 @@
 #include "format.h"
 
 FMT_BEGIN_NAMESPACE
-FMT_MODULE_EXPORT_BEGIN
+FMT_BEGIN_EXPORT
 
 enum class color : uint32_t {
   alice_blue = 0xF0F8FF,               // rgb(240,248,255)
@@ -203,7 +203,7 @@
   uint8_t b;
 };
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 // color is a struct of either a rgb color or a terminal color.
 struct color_type {
@@ -225,8 +225,7 @@
     uint32_t rgb_color;
   } value;
 };
-
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
 /** A text style consisting of foreground and background colors and emphasis. */
 class text_style {
@@ -323,7 +322,7 @@
   return text_style(lhs) | rhs;
 }
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 template <typename Char> struct ansi_color_escape {
   FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
@@ -423,26 +422,6 @@
   return ansi_color_escape<Char>(em);
 }
 
-template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
-  int result = std::fputs(chars, stream);
-  if (result < 0)
-    FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
-}
-
-template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
-  int result = std::fputws(chars, stream);
-  if (result < 0)
-    FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
-}
-
-template <typename Char> inline void reset_color(FILE* stream) {
-  fputs("\x1b[0m", stream);
-}
-
-template <> inline void reset_color<wchar_t>(FILE* stream) {
-  fputs(L"\x1b[0m", stream);
-}
-
 template <typename Char> inline void reset_color(buffer<Char>& buffer) {
   auto reset_color = string_view("\x1b[0m");
   buffer.append(reset_color.begin(), reset_color.end());
@@ -477,19 +456,21 @@
   if (has_style) detail::reset_color<Char>(buf);
 }
 
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
-template <typename S, typename Char = char_t<S>>
-void vprint(std::FILE* f, const text_style& ts, const S& format,
-            basic_format_args<buffer_context<type_identity_t<Char>>> args) {
-  basic_memory_buffer<Char> buf;
-  detail::vformat_to(buf, ts, detail::to_string_view(format), args);
+inline void vprint(std::FILE* f, const text_style& ts, string_view fmt,
+                   format_args args) {
+  // Legacy wide streams are not supported.
+  auto buf = memory_buffer();
+  detail::vformat_to(buf, ts, fmt, args);
   if (detail::is_utf8()) {
-    detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
-  } else {
-    buf.push_back(Char(0));
-    detail::fputs(buf.data(), f);
+    detail::print(f, string_view(buf.begin(), buf.size()));
+    return;
   }
+  buf.push_back('\0');
+  int result = std::fputs(buf.data(), f);
+  if (result < 0)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
 }
 
 /**
@@ -566,7 +547,7 @@
     basic_format_args<buffer_context<type_identity_t<Char>>> args) {
   auto&& buf = detail::get_buffer<Char>(out);
   detail::vformat_to(buf, ts, format_str, args);
-  return detail::get_iterator(buf);
+  return detail::get_iterator(buf, out);
 }
 
 /**
@@ -645,7 +626,7 @@
   return detail::styled_arg<remove_cvref_t<T>>{value, ts};
 }
 
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_COLOR_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
index 933668c..a4c7e49 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
@@ -19,84 +19,6 @@
   return it + (end - begin);
 }
 
-template <typename OutputIt> class truncating_iterator_base {
- protected:
-  OutputIt out_;
-  size_t limit_;
-  size_t count_ = 0;
-
-  truncating_iterator_base() : out_(), limit_(0) {}
-
-  truncating_iterator_base(OutputIt out, size_t limit)
-      : out_(out), limit_(limit) {}
-
- public:
-  using iterator_category = std::output_iterator_tag;
-  using value_type = typename std::iterator_traits<OutputIt>::value_type;
-  using difference_type = std::ptrdiff_t;
-  using pointer = void;
-  using reference = void;
-  FMT_UNCHECKED_ITERATOR(truncating_iterator_base);
-
-  OutputIt base() const { return out_; }
-  size_t count() const { return count_; }
-};
-
-// An output iterator that truncates the output and counts the number of objects
-// written to it.
-template <typename OutputIt,
-          typename Enable = typename std::is_void<
-              typename std::iterator_traits<OutputIt>::value_type>::type>
-class truncating_iterator;
-
-template <typename OutputIt>
-class truncating_iterator<OutputIt, std::false_type>
-    : public truncating_iterator_base<OutputIt> {
-  mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
-
- public:
-  using value_type = typename truncating_iterator_base<OutputIt>::value_type;
-
-  truncating_iterator() = default;
-
-  truncating_iterator(OutputIt out, size_t limit)
-      : truncating_iterator_base<OutputIt>(out, limit) {}
-
-  truncating_iterator& operator++() {
-    if (this->count_++ < this->limit_) ++this->out_;
-    return *this;
-  }
-
-  truncating_iterator operator++(int) {
-    auto it = *this;
-    ++*this;
-    return it;
-  }
-
-  value_type& operator*() const {
-    return this->count_ < this->limit_ ? *this->out_ : blackhole_;
-  }
-};
-
-template <typename OutputIt>
-class truncating_iterator<OutputIt, std::true_type>
-    : public truncating_iterator_base<OutputIt> {
- public:
-  truncating_iterator() = default;
-
-  truncating_iterator(OutputIt out, size_t limit)
-      : truncating_iterator_base<OutputIt>(out, limit) {}
-
-  template <typename T> truncating_iterator& operator=(T val) {
-    if (this->count_++ < this->limit_) *this->out_++ = val;
-    return *this;
-  }
-
-  truncating_iterator& operator++() { return *this; }
-  truncating_iterator& operator++(int) { return *this; }
-  truncating_iterator& operator*() { return *this; }
-};
-
 // A compile-time string which is compiled into fast formatting code.
 class compiled_string {};
 
@@ -196,7 +118,8 @@
 
   template <typename OutputIt, typename... Args>
   constexpr OutputIt format(OutputIt out, const Args&...) const {
-    return write<Char>(out, value);
+    *out++ = value;
+    return out;
   }
 };
 
@@ -220,7 +143,12 @@
 
   template <typename OutputIt, typename... Args>
   constexpr OutputIt format(OutputIt out, const Args&... args) const {
-    return write<Char>(out, get_arg_checked<T, N>(args...));
+    const T& arg = get_arg_checked<T, N>(args...);
+    if constexpr (std::is_convertible_v<T, basic_string_view<Char>>) {
+      auto s = basic_string_view<Char>(arg);
+      return copy_str<Char>(s.begin(), s.end(), out);
+    }
+    return write<Char>(out, arg);
   }
 };
 
@@ -331,14 +259,14 @@
   int next_arg_id;
 };
 
-constexpr int manual_indexing_id = -1;
+enum { manual_indexing_id = -1 };
 
 template <typename T, typename Char>
 constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
                                                   size_t pos, int next_arg_id) {
   str.remove_prefix(pos);
-  auto ctx = compile_parse_context<Char>(str, max_value<int>(), nullptr, {},
-                                         next_arg_id);
+  auto ctx =
+      compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
   auto f = formatter<T, Char>();
   auto end = f.parse(ctx);
   return {f, pos + fmt::detail::to_unsigned(end - str.data()),
@@ -348,22 +276,18 @@
 template <typename Char> struct arg_id_handler {
   arg_ref<Char> arg_id;
 
-  constexpr int operator()() {
+  constexpr int on_auto() {
     FMT_ASSERT(false, "handler cannot be used with automatic indexing");
     return 0;
   }
-  constexpr int operator()(int id) {
+  constexpr int on_index(int id) {
     arg_id = arg_ref<Char>(id);
     return 0;
   }
-  constexpr int operator()(basic_string_view<Char> id) {
+  constexpr int on_name(basic_string_view<Char> id) {
     arg_id = arg_ref<Char>(id);
     return 0;
   }
-
-  constexpr void on_error(const char* message) {
-    FMT_THROW(format_error(message));
-  }
 };
 
 template <typename Char> struct parse_arg_id_result {
@@ -452,20 +376,18 @@
       } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
         constexpr auto arg_index =
             get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
-        if constexpr (arg_index != invalid_arg_index) {
+        if constexpr (arg_index >= 0) {
           constexpr auto next_id =
               ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
           return parse_replacement_field_then_tail<
               decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
               arg_index, next_id>(format_str);
-        } else {
-          if constexpr (c == '}') {
-            return parse_tail<Args, arg_id_end_pos + 1, ID>(
-                runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
-                format_str);
-          } else if constexpr (c == ':') {
-            return unknown_format();  // no type info for specs parsing
-          }
+        } else if constexpr (c == '}') {
+          return parse_tail<Args, arg_id_end_pos + 1, ID>(
+              runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
+              format_str);
+        } else if constexpr (c == ':') {
+          return unknown_format();  // no type info for specs parsing
         }
       }
     }
@@ -501,7 +423,7 @@
 #endif  // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
 }  // namespace detail
 
-FMT_MODULE_EXPORT_BEGIN
+FMT_BEGIN_EXPORT
 
 #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
 
@@ -568,9 +490,10 @@
           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
 format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
                                          const S& format_str, Args&&... args) {
-  auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
-                           format_str, std::forward<Args>(args)...);
-  return {it.base(), it.count()};
+  using traits = detail::fixed_buffer_traits;
+  auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
+  format_to(std::back_inserter(buf), format_str, std::forward<Args>(args)...);
+  return {buf.out(), buf.count()};
 }
 
 template <typename S, typename... Args,
@@ -605,7 +528,7 @@
 }  // namespace literals
 #endif
 
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_COMPILE_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
index 5c210bc..1fe1388 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
@@ -13,11 +13,12 @@
 #include <cstring>  // std::strlen
 #include <iterator>
 #include <limits>
+#include <memory>  // std::addressof
 #include <string>
 #include <type_traits>
 
 // The fmt library version in the form major * 10000 + minor * 100 + patch.
-#define FMT_VERSION 90100
+#define FMT_VERSION 100100
 
 #if defined(__clang__) && !defined(__ibmxl__)
 #  define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
@@ -69,9 +70,7 @@
 #  define FMT_HAS_FEATURE(x) 0
 #endif
 
-#if (defined(__has_include) || FMT_ICC_VERSION >= 1600 || \
-     FMT_MSC_VERSION > 1900) &&                           \
-    !defined(__INTELLISENSE__)
+#if defined(__has_include) || FMT_ICC_VERSION >= 1600 || FMT_MSC_VERSION > 1900
 #  define FMT_HAS_INCLUDE(x) __has_include(x)
 #else
 #  define FMT_HAS_INCLUDE(x) 0
@@ -94,7 +93,7 @@
 #ifndef FMT_USE_CONSTEXPR
 #  if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \
        (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) &&             \
-      !FMT_ICC_VERSION && !defined(__NVCC__)
+      !FMT_ICC_VERSION && (!defined(__NVCC__) || FMT_CPLUSPLUS >= 202002L)
 #    define FMT_USE_CONSTEXPR 1
 #  else
 #    define FMT_USE_CONSTEXPR 0
@@ -140,22 +139,7 @@
 #  endif
 #endif
 
-#ifndef FMT_DEPRECATED
-#  if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900
-#    define FMT_DEPRECATED [[deprecated]]
-#  else
-#    if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
-#      define FMT_DEPRECATED __attribute__((deprecated))
-#    elif FMT_MSC_VERSION
-#      define FMT_DEPRECATED __declspec(deprecated)
-#    else
-#      define FMT_DEPRECATED /* deprecated */
-#    endif
-#  endif
-#endif
-
-// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
-// warnings.
+// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings.
 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \
     !defined(__NVCC__)
 #  define FMT_NORETURN [[noreturn]]
@@ -163,17 +147,6 @@
 #  define FMT_NORETURN
 #endif
 
-#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
-#  define FMT_FALLTHROUGH [[fallthrough]]
-#elif defined(__clang__)
-#  define FMT_FALLTHROUGH [[clang::fallthrough]]
-#elif FMT_GCC_VERSION >= 700 && \
-    (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
-#  define FMT_FALLTHROUGH [[gnu::fallthrough]]
-#else
-#  define FMT_FALLTHROUGH
-#endif
-
 #ifndef FMT_NODISCARD
 #  if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
 #    define FMT_NODISCARD [[nodiscard]]
@@ -182,16 +155,6 @@
 #  endif
 #endif
 
-#ifndef FMT_USE_FLOAT
-#  define FMT_USE_FLOAT 1
-#endif
-#ifndef FMT_USE_DOUBLE
-#  define FMT_USE_DOUBLE 1
-#endif
-#ifndef FMT_USE_LONG_DOUBLE
-#  define FMT_USE_LONG_DOUBLE 1
-#endif
-
 #ifndef FMT_INLINE
 #  if FMT_GCC_VERSION || FMT_CLANG_VERSION
 #    define FMT_INLINE inline __attribute__((always_inline))
@@ -200,9 +163,6 @@
 #  endif
 #endif
 
-// An inline std::forward replacement.
-#define FMT_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
-
 #ifdef _MSC_VER
 #  define FMT_UNCHECKED_ITERATOR(It) \
     using _Unchecked_type = It  // Mark iterator as checked.
@@ -213,30 +173,26 @@
 #ifndef FMT_BEGIN_NAMESPACE
 #  define FMT_BEGIN_NAMESPACE \
     namespace fmt {           \
-    inline namespace v9 {
+    inline namespace v10 {
 #  define FMT_END_NAMESPACE \
     }                       \
     }
 #endif
 
-#ifndef FMT_MODULE_EXPORT
-#  define FMT_MODULE_EXPORT
-#  define FMT_MODULE_EXPORT_BEGIN
-#  define FMT_MODULE_EXPORT_END
-#  define FMT_BEGIN_DETAIL_NAMESPACE namespace detail {
-#  define FMT_END_DETAIL_NAMESPACE }
+#ifndef FMT_EXPORT
+#  define FMT_EXPORT
+#  define FMT_BEGIN_EXPORT
+#  define FMT_END_EXPORT
 #endif
 
 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
-#  define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
-#  ifdef FMT_EXPORT
+#  ifdef FMT_LIB_EXPORT
 #    define FMT_API __declspec(dllexport)
 #  elif defined(FMT_SHARED)
 #    define FMT_API __declspec(dllimport)
 #  endif
 #else
-#  define FMT_CLASS_API
-#  if defined(FMT_EXPORT) || defined(FMT_SHARED)
+#  if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
 #    if defined(__GNUC__) || defined(__clang__)
 #      define FMT_API __attribute__((visibility("default")))
 #    endif
@@ -261,11 +217,13 @@
 #endif
 
 #ifndef FMT_CONSTEVAL
-#  if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) &&         \
-       FMT_CPLUSPLUS >= 202002L && !defined(__apple_build_version__)) || \
-      (defined(__cpp_consteval) &&                                       \
+#  if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
+       (!defined(__apple_build_version__) ||                     \
+        __apple_build_version__ >= 14000029L) &&                 \
+       FMT_CPLUSPLUS >= 202002L) ||                              \
+      (defined(__cpp_consteval) &&                               \
        (!FMT_MSC_VERSION || _MSC_FULL_VER >= 193030704))
-// consteval is broken in MSVC before VS2022 and Apple clang 13.
+// consteval is broken in MSVC before VS2022 and Apple clang before 14.
 #    define FMT_CONSTEVAL consteval
 #    define FMT_HAS_CONSTEVAL
 #  else
@@ -277,7 +235,7 @@
 #  if defined(__cpp_nontype_template_args) &&                  \
       ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \
        __cpp_nontype_template_args >= 201911L) &&              \
-      !defined(__NVCOMPILER)
+      !defined(__NVCOMPILER) && !defined(__LCC__)
 #    define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
 #  else
 #    define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
@@ -286,12 +244,12 @@
 
 // Enable minimal optimizations for more compact code in debug mode.
 FMT_GCC_PRAGMA("GCC push_options")
-#if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER)
+#if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER) && !defined(__LCC__) && \
+    !defined(__CUDACC__)
 FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
 #endif
 
 FMT_BEGIN_NAMESPACE
-FMT_MODULE_EXPORT_BEGIN
 
 // Implementations of enable_if_t and other metafunctions for older systems.
 template <bool B, typename T = void>
@@ -310,17 +268,10 @@
 template <typename T>
 using underlying_t = typename std::underlying_type<T>::type;
 
-template <typename...> struct disjunction : std::false_type {};
-template <typename P> struct disjunction<P> : P {};
-template <typename P1, typename... Pn>
-struct disjunction<P1, Pn...>
-    : conditional_t<bool(P1::value), P1, disjunction<Pn...>> {};
-
-template <typename...> struct conjunction : std::true_type {};
-template <typename P> struct conjunction<P> : P {};
-template <typename P1, typename... Pn>
-struct conjunction<P1, Pn...>
-    : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
+// Checks whether T is a container with contiguous storage.
+template <typename T> struct is_contiguous : std::false_type {};
+template <typename Char>
+struct is_contiguous<std::basic_string<Char>> : std::true_type {};
 
 struct monostate {
   constexpr monostate() {}
@@ -332,11 +283,19 @@
 #ifdef FMT_DOC
 #  define FMT_ENABLE_IF(...)
 #else
-#  define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
+#  define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0
 #endif
 
-FMT_BEGIN_DETAIL_NAMESPACE
+// This is defined in core.h instead of format.h to avoid injecting in std.
+// It is a template to avoid undesirable implicit conversions to std::byte.
+#ifdef __cpp_lib_byte
+template <typename T, FMT_ENABLE_IF(std::is_same<T, std::byte>::value)>
+inline auto format_as(T b) -> unsigned char {
+  return static_cast<unsigned char>(b);
+}
+#endif
 
+namespace detail {
 // Suppresses "unused variable" warnings with the method described in
 // https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
 // (void)var does not work on many Intel compilers.
@@ -344,7 +303,15 @@
 
 constexpr FMT_INLINE auto is_constant_evaluated(
     bool default_value = false) noexcept -> bool {
-#ifdef __cpp_lib_is_constant_evaluated
+// Workaround for incompatibility between libstdc++ consteval-based
+// std::is_constant_evaluated() implementation and clang-14.
+// https://github.com/fmtlib/fmt/issues/3247
+#if FMT_CPLUSPLUS >= 202002L && defined(_GLIBCXX_RELEASE) && \
+    _GLIBCXX_RELEASE >= 12 &&                                \
+    (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
+  ignore_unused(default_value);
+  return __builtin_is_constant_evaluated();
+#elif defined(__cpp_lib_is_constant_evaluated)
   ignore_unused(default_value);
   return std::is_constant_evaluated();
 #else
@@ -364,12 +331,12 @@
 #  ifdef NDEBUG
 // FMT_ASSERT is not empty to avoid -Wempty-body.
 #    define FMT_ASSERT(condition, message) \
-      ::fmt::detail::ignore_unused((condition), (message))
+      fmt::detail::ignore_unused((condition), (message))
 #  else
 #    define FMT_ASSERT(condition, message)                                    \
       ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
            ? (void)0                                                          \
-           : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
+           : fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
 #  endif
 #endif
 
@@ -410,15 +377,15 @@
   return static_cast<typename std::make_unsigned<Int>::type>(value);
 }
 
-FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
+FMT_CONSTEXPR inline auto is_utf8() -> bool {
+  FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char section[] = "\u00A7";
 
-constexpr auto is_utf8() -> bool {
   // Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297).
   using uchar = unsigned char;
-  return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 &&
-                         uchar(micro[1]) == 0xB5);
+  return FMT_UNICODE || (sizeof(section) == 3 && uchar(section[0]) == 0xC2 &&
+                         uchar(section[1]) == 0xA7);
 }
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
 /**
   An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
@@ -427,6 +394,7 @@
   compiled with a different ``-std`` option than the client code (which is not
   recommended).
  */
+FMT_EXPORT
 template <typename Char> class basic_string_view {
  private:
   const Char* data_;
@@ -486,6 +454,18 @@
     size_ -= n;
   }
 
+  FMT_CONSTEXPR_CHAR_TRAITS bool starts_with(
+      basic_string_view<Char> sv) const noexcept {
+    return size_ >= sv.size_ &&
+           std::char_traits<Char>::compare(data_, sv.data_, sv.size_) == 0;
+  }
+  FMT_CONSTEXPR_CHAR_TRAITS bool starts_with(Char c) const noexcept {
+    return size_ >= 1 && std::char_traits<Char>::eq(*data_, c);
+  }
+  FMT_CONSTEXPR_CHAR_TRAITS bool starts_with(const Char* s) const {
+    return starts_with(basic_string_view<Char>(s));
+  }
+
   // Lexicographically compare this string reference to other.
   FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int {
     size_t str_size = size_ < other.size_ ? size_ : other.size_;
@@ -517,13 +497,15 @@
   }
 };
 
+FMT_EXPORT
 using string_view = basic_string_view<char>;
 
 /** Specifies if ``T`` is a character type. Can be specialized by users. */
+FMT_EXPORT
 template <typename T> struct is_char : std::false_type {};
 template <> struct is_char<char> : std::true_type {};
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 // A base class for compile-time strings.
 struct compile_string {};
@@ -531,7 +513,6 @@
 template <typename S>
 struct is_compile_string : std::is_base_of<compile_string, S> {};
 
-// Returns a string view of `s`.
 template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
 FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> {
   return s;
@@ -561,10 +542,10 @@
 // Specifies whether S is a string type convertible to fmt::basic_string_view.
 // It should be a constexpr function but MSVC 2017 fails to compile it in
 // enable_if and MSVC 2015 fails to compile it as an alias template.
-// ADL invocation of to_string_view is DEPRECATED!
+// ADL is intentionally disabled as to_string_view is not an extension point.
 template <typename S>
-struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
-};
+struct is_string
+    : std::is_class<decltype(detail::to_string_view(std::declval<S>()))> {};
 
 template <typename S, typename = void> struct char_t_impl {};
 template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
@@ -622,23 +603,44 @@
 constexpr bool is_integral_type(type t) {
   return t > type::none_type && t <= type::last_integer_type;
 }
-
 constexpr bool is_arithmetic_type(type t) {
   return t > type::none_type && t <= type::last_numeric_type;
 }
 
+constexpr auto set(type rhs) -> int { return 1 << static_cast<int>(rhs); }
+constexpr auto in(type t, int set) -> bool {
+  return ((set >> static_cast<int>(t)) & 1) != 0;
+}
+
+// Bitsets of types.
+enum {
+  sint_set =
+      set(type::int_type) | set(type::long_long_type) | set(type::int128_type),
+  uint_set = set(type::uint_type) | set(type::ulong_long_type) |
+             set(type::uint128_type),
+  bool_set = set(type::bool_type),
+  char_set = set(type::char_type),
+  float_set = set(type::float_type) | set(type::double_type) |
+              set(type::long_double_type),
+  string_set = set(type::string_type),
+  cstring_set = set(type::cstring_type),
+  pointer_set = set(type::pointer_type)
+};
+
 FMT_NORETURN FMT_API void throw_format_error(const char* message);
 
 struct error_handler {
   constexpr error_handler() = default;
-  constexpr error_handler(const error_handler&) = default;
 
   // This function is intentionally not constexpr to give a compile-time error.
   FMT_NORETURN void on_error(const char* message) {
     throw_format_error(message);
   }
 };
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
+
+/** Throws ``format_error`` with a given message. */
+using detail::throw_format_error;
 
 /** String's character type. */
 template <typename S> using char_t = typename detail::char_t_impl<S>::type;
@@ -650,8 +652,8 @@
   You can use the ``format_parse_context`` type alias for ``char`` instead.
   \endrst
  */
-template <typename Char, typename ErrorHandler = detail::error_handler>
-class basic_format_parse_context : private ErrorHandler {
+FMT_EXPORT
+template <typename Char> class basic_format_parse_context {
  private:
   basic_string_view<Char> format_str_;
   int next_arg_id_;
@@ -660,12 +662,11 @@
 
  public:
   using char_type = Char;
-  using iterator = typename basic_string_view<Char>::iterator;
+  using iterator = const Char*;
 
   explicit constexpr basic_format_parse_context(
-      basic_string_view<Char> format_str, ErrorHandler eh = {},
-      int next_arg_id = 0)
-      : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
+      basic_string_view<Char> format_str, int next_arg_id = 0)
+      : format_str_(format_str), next_arg_id_(next_arg_id) {}
 
   /**
     Returns an iterator to the beginning of the format string range being
@@ -691,7 +692,8 @@
    */
   FMT_CONSTEXPR auto next_arg_id() -> int {
     if (next_arg_id_ < 0) {
-      on_error("cannot switch from manual to automatic argument indexing");
+      detail::throw_format_error(
+          "cannot switch from manual to automatic argument indexing");
       return 0;
     }
     int id = next_arg_id_++;
@@ -705,7 +707,8 @@
    */
   FMT_CONSTEXPR void check_arg_id(int id) {
     if (next_arg_id_ > 0) {
-      on_error("cannot switch from automatic to manual argument indexing");
+      detail::throw_format_error(
+          "cannot switch from automatic to manual argument indexing");
       return;
     }
     next_arg_id_ = -1;
@@ -713,116 +716,49 @@
   }
   FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
   FMT_CONSTEXPR void check_dynamic_spec(int arg_id);
-
-  FMT_CONSTEXPR void on_error(const char* message) {
-    ErrorHandler::on_error(message);
-  }
-
-  constexpr auto error_handler() const -> ErrorHandler { return *this; }
 };
 
+FMT_EXPORT
 using format_parse_context = basic_format_parse_context<char>;
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 // A parse context with extra data used only in compile-time checks.
-template <typename Char, typename ErrorHandler = detail::error_handler>
-class compile_parse_context
-    : public basic_format_parse_context<Char, ErrorHandler> {
+template <typename Char>
+class compile_parse_context : public basic_format_parse_context<Char> {
  private:
   int num_args_;
   const type* types_;
-  using base = basic_format_parse_context<Char, ErrorHandler>;
+  using base = basic_format_parse_context<Char>;
 
  public:
   explicit FMT_CONSTEXPR compile_parse_context(
       basic_string_view<Char> format_str, int num_args, const type* types,
-      ErrorHandler eh = {}, int next_arg_id = 0)
-      : base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {}
+      int next_arg_id = 0)
+      : base(format_str, next_arg_id), num_args_(num_args), types_(types) {}
 
   constexpr auto num_args() const -> int { return num_args_; }
   constexpr auto arg_type(int id) const -> type { return types_[id]; }
 
   FMT_CONSTEXPR auto next_arg_id() -> int {
     int id = base::next_arg_id();
-    if (id >= num_args_) this->on_error("argument not found");
+    if (id >= num_args_) throw_format_error("argument not found");
     return id;
   }
 
   FMT_CONSTEXPR void check_arg_id(int id) {
     base::check_arg_id(id);
-    if (id >= num_args_) this->on_error("argument not found");
+    if (id >= num_args_) throw_format_error("argument not found");
   }
   using base::check_arg_id;
 
   FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
+    detail::ignore_unused(arg_id);
+#if !defined(__LCC__)
     if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
-      this->on_error("width/precision is not integer");
+      throw_format_error("width/precision is not integer");
+#endif
   }
 };
-FMT_END_DETAIL_NAMESPACE
-
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR void
-basic_format_parse_context<Char, ErrorHandler>::do_check_arg_id(int id) {
-  // Argument id is only checked at compile-time during parsing because
-  // formatting has its own validation.
-  if (detail::is_constant_evaluated() && FMT_GCC_VERSION >= 1200) {
-    using context = detail::compile_parse_context<Char, ErrorHandler>;
-    if (id >= static_cast<context*>(this)->num_args())
-      on_error("argument not found");
-  }
-}
-
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR void
-basic_format_parse_context<Char, ErrorHandler>::check_dynamic_spec(int arg_id) {
-  if (detail::is_constant_evaluated()) {
-    using context = detail::compile_parse_context<Char, ErrorHandler>;
-    static_cast<context*>(this)->check_dynamic_spec(arg_id);
-  }
-}
-
-template <typename Context> class basic_format_arg;
-template <typename Context> class basic_format_args;
-template <typename Context> class dynamic_format_arg_store;
-
-// A formatter for objects of type T.
-template <typename T, typename Char = char, typename Enable = void>
-struct formatter {
-  // A deleted default constructor indicates a disabled formatter.
-  formatter() = delete;
-};
-
-// Specifies if T has an enabled formatter specialization. A type can be
-// formattable even if it doesn't have a formatter e.g. via a conversion.
-template <typename T, typename Context>
-using has_formatter =
-    std::is_constructible<typename Context::template formatter_type<T>>;
-
-// Checks whether T is a container with contiguous storage.
-template <typename T> struct is_contiguous : std::false_type {};
-template <typename Char>
-struct is_contiguous<std::basic_string<Char>> : std::true_type {};
-
-class appender;
-
-FMT_BEGIN_DETAIL_NAMESPACE
-
-template <typename Context, typename T>
-constexpr auto has_const_formatter_impl(T*)
-    -> decltype(typename Context::template formatter_type<T>().format(
-                    std::declval<const T&>(), std::declval<Context&>()),
-                true) {
-  return true;
-}
-template <typename Context>
-constexpr auto has_const_formatter_impl(...) -> bool {
-  return false;
-}
-template <typename T, typename Context>
-constexpr auto has_const_formatter() -> bool {
-  return has_const_formatter_impl<Context>(static_cast<T*>(nullptr));
-}
 
 // Extracts a reference to the container from back_insert_iterator.
 template <typename Container>
@@ -849,7 +785,7 @@
 FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* {
   if (is_constant_evaluated()) return copy_str<Char, T*, U*>(begin, end, out);
   auto size = to_unsigned(end - begin);
-  memcpy(out, begin, size * sizeof(U));
+  if (size > 0) memcpy(out, begin, size * sizeof(U));
   return out + size;
 }
 
@@ -892,11 +828,11 @@
   buffer(const buffer&) = delete;
   void operator=(const buffer&) = delete;
 
-  auto begin() noexcept -> T* { return ptr_; }
-  auto end() noexcept -> T* { return ptr_ + size_; }
+  FMT_INLINE auto begin() noexcept -> T* { return ptr_; }
+  FMT_INLINE auto end() noexcept -> T* { return ptr_ + size_; }
 
-  auto begin() const noexcept -> const T* { return ptr_; }
-  auto end() const noexcept -> const T* { return ptr_ + size_; }
+  FMT_INLINE auto begin() const noexcept -> const T* { return ptr_; }
+  FMT_INLINE auto end() const noexcept -> const T* { return ptr_ + size_; }
 
   /** Returns the size of this buffer. */
   constexpr auto size() const noexcept -> size_t { return size_; }
@@ -904,10 +840,8 @@
   /** Returns the capacity of this buffer. */
   constexpr auto capacity() const noexcept -> size_t { return capacity_; }
 
-  /** Returns a pointer to the buffer data. */
+  /** Returns a pointer to the buffer data (not null-terminated). */
   FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; }
-
-  /** Returns a pointer to the buffer data. */
   FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; }
 
   /** Clears this buffer. */
@@ -1100,6 +1034,79 @@
 
   auto count() -> size_t { return count_ + this->size(); }
 };
+}  // namespace detail
+
+template <typename Char>
+FMT_CONSTEXPR void basic_format_parse_context<Char>::do_check_arg_id(int id) {
+  // Argument id is only checked at compile-time during parsing because
+  // formatting has its own validation.
+  if (detail::is_constant_evaluated() &&
+      (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
+    using context = detail::compile_parse_context<Char>;
+    if (id >= static_cast<context*>(this)->num_args())
+      detail::throw_format_error("argument not found");
+  }
+}
+
+template <typename Char>
+FMT_CONSTEXPR void basic_format_parse_context<Char>::check_dynamic_spec(
+    int arg_id) {
+  if (detail::is_constant_evaluated() &&
+      (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
+    using context = detail::compile_parse_context<Char>;
+    static_cast<context*>(this)->check_dynamic_spec(arg_id);
+  }
+}
+
+FMT_EXPORT template <typename Context> class basic_format_arg;
+FMT_EXPORT template <typename Context> class basic_format_args;
+FMT_EXPORT template <typename Context> class dynamic_format_arg_store;
+
+// A formatter for objects of type T.
+FMT_EXPORT
+template <typename T, typename Char = char, typename Enable = void>
+struct formatter {
+  // A deleted default constructor indicates a disabled formatter.
+  formatter() = delete;
+};
+
+// Specifies if T has an enabled formatter specialization. A type can be
+// formattable even if it doesn't have a formatter e.g. via a conversion.
+template <typename T, typename Context>
+using has_formatter =
+    std::is_constructible<typename Context::template formatter_type<T>>;
+
+// An output iterator that appends to a buffer.
+// It is used to reduce symbol sizes for the common case.
+class appender : public std::back_insert_iterator<detail::buffer<char>> {
+  using base = std::back_insert_iterator<detail::buffer<char>>;
+
+ public:
+  using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
+  appender(base it) noexcept : base(it) {}
+  FMT_UNCHECKED_ITERATOR(appender);
+
+  auto operator++() noexcept -> appender& { return *this; }
+  auto operator++(int) noexcept -> appender { return *this; }
+};
+
+namespace detail {
+
+template <typename Context, typename T>
+constexpr auto has_const_formatter_impl(T*)
+    -> decltype(typename Context::template formatter_type<T>().format(
+                    std::declval<const T&>(), std::declval<Context&>()),
+                true) {
+  return true;
+}
+template <typename Context>
+constexpr auto has_const_formatter_impl(...) -> bool {
+  return false;
+}
+template <typename T, typename Context>
+constexpr auto has_const_formatter() -> bool {
+  return has_const_formatter_impl<Context>(static_cast<T*>(nullptr));
+}
 
 template <typename T>
 using buffer_appender = conditional_t<std::is_same<T, char>::value, appender,
@@ -1110,29 +1117,21 @@
 auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
   return iterator_buffer<OutputIt, T>(out);
 }
+template <typename T, typename Buf,
+          FMT_ENABLE_IF(std::is_base_of<buffer<char>, Buf>::value)>
+auto get_buffer(std::back_insert_iterator<Buf> out) -> buffer<char>& {
+  return get_container(out);
+}
 
-template <typename Buffer>
-auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
+template <typename Buf, typename OutputIt>
+FMT_INLINE auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
   return buf.out();
 }
-template <typename T> auto get_iterator(buffer<T>& buf) -> buffer_appender<T> {
-  return buffer_appender<T>(buf);
+template <typename T, typename OutputIt>
+auto get_iterator(buffer<T>&, OutputIt out) -> OutputIt {
+  return out;
 }
 
-template <typename T, typename Char = char, typename Enable = void>
-struct fallback_formatter {
-  fallback_formatter() = delete;
-};
-
-// Specifies if T has an enabled fallback_formatter specialization.
-template <typename T, typename Char>
-using has_fallback_formatter =
-#ifdef FMT_DEPRECATED_OSTREAM
-    std::is_constructible<fallback_formatter<T, Char>>;
-#else
-    std::false_type;
-#endif
-
 struct view {};
 
 template <typename Char, typename T> struct named_arg : view {
@@ -1217,7 +1216,6 @@
 
 struct unformattable {};
 struct unformattable_char : unformattable {};
-struct unformattable_const : unformattable {};
 struct unformattable_pointer : unformattable {};
 
 template <typename Char> struct string_value {
@@ -1284,21 +1282,17 @@
   FMT_INLINE value(const named_arg_info<char_type>* args, size_t size)
       : named_args{args, size} {}
 
-  template <typename T> FMT_CONSTEXPR FMT_INLINE value(T& val) {
-    using value_type = remove_cvref_t<T>;
-    custom.value = const_cast<value_type*>(&val);
+  template <typename T> FMT_CONSTEXPR20 FMT_INLINE value(T& val) {
+    using value_type = remove_const_t<T>;
+    custom.value = const_cast<value_type*>(std::addressof(val));
     // Get the formatter type through the context to allow different contexts
     // have different extension points, e.g. `formatter<T>` for `format` and
     // `printf_formatter<T>` for `printf`.
     custom.format = format_custom_arg<
-        value_type,
-        conditional_t<has_formatter<value_type, Context>::value,
-                      typename Context::template formatter_type<value_type>,
-                      fallback_formatter<value_type, char_type>>>;
+        value_type, typename Context::template formatter_type<value_type>>;
   }
   value(unformattable);
   value(unformattable_char);
-  value(unformattable_const);
   value(unformattable_pointer);
 
  private:
@@ -1315,29 +1309,25 @@
   }
 };
 
-template <typename Context, typename T>
-FMT_CONSTEXPR auto make_arg(T&& value) -> basic_format_arg<Context>;
-
 // To minimize the number of types we need to deal with, long is translated
 // either to int or to long long depending on its size.
 enum { long_short = sizeof(long) == sizeof(int) };
 using long_type = conditional_t<long_short, int, long long>;
 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
 
-#ifdef __cpp_lib_byte
-inline auto format_as(std::byte b) -> unsigned char {
-  return static_cast<unsigned char>(b);
-}
-#endif
+template <typename T> struct format_as_result {
+  template <typename U,
+            FMT_ENABLE_IF(std::is_enum<U>::value || std::is_class<U>::value)>
+  static auto map(U*) -> decltype(format_as(std::declval<U>()));
+  static auto map(...) -> void;
 
-template <typename T> struct has_format_as {
-  template <typename U, typename V = decltype(format_as(U())),
-            FMT_ENABLE_IF(std::is_enum<U>::value&& std::is_integral<V>::value)>
-  static auto check(U*) -> std::true_type;
-  static auto check(...) -> std::false_type;
-
-  enum { value = decltype(check(static_cast<T*>(nullptr)))::value };
+  using type = decltype(map(static_cast<T*>(nullptr)));
 };
+template <typename T> using format_as_t = typename format_as_result<T>::type;
+
+template <typename T>
+struct has_format_as
+    : bool_constant<!std::is_same<format_as_t<T>, void>::value> {};
 
 // Maps formatting arguments to core types.
 // arg_mapper reports errors by returning unformattable instead of using
@@ -1414,25 +1404,6 @@
   FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char {
     return {};
   }
-  template <typename T,
-            FMT_ENABLE_IF(
-                std::is_convertible<T, basic_string_view<char_type>>::value &&
-                !is_string<T>::value && !has_formatter<T, Context>::value &&
-                !has_fallback_formatter<T, char_type>::value)>
-  FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
-      -> basic_string_view<char_type> {
-    return basic_string_view<char_type>(val);
-  }
-  template <typename T,
-            FMT_ENABLE_IF(
-                std::is_convertible<T, std_string_view<char_type>>::value &&
-                !std::is_convertible<T, basic_string_view<char_type>>::value &&
-                !is_string<T>::value && !has_formatter<T, Context>::value &&
-                !has_fallback_formatter<T, char_type>::value)>
-  FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
-      -> basic_string_view<char_type> {
-    return std_string_view<char_type>(val);
-  }
 
   FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; }
   FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* {
@@ -1442,16 +1413,15 @@
     return val;
   }
 
-  // We use SFINAE instead of a const T* parameter to avoid conflicting with
-  // the C array overload.
+  // Use SFINAE instead of a const T* parameter to avoid a conflict with the
+  // array overload.
   template <
       typename T,
       FMT_ENABLE_IF(
           std::is_pointer<T>::value || std::is_member_pointer<T>::value ||
           std::is_function<typename std::remove_pointer<T>::type>::value ||
-          (std::is_convertible<const T&, const void*>::value &&
-           !std::is_convertible<const T&, const char_type*>::value &&
-           !has_formatter<T, Context>::value))>
+          (std::is_array<T>::value &&
+           !std::is_convertible<T, const char_type*>::value))>
   FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer {
     return {};
   }
@@ -1462,62 +1432,40 @@
     return values;
   }
 
-  template <typename T,
-            FMT_ENABLE_IF(
-                std::is_enum<T>::value&& std::is_convertible<T, int>::value &&
-                !has_format_as<T>::value && !has_formatter<T, Context>::value &&
-                !has_fallback_formatter<T, char_type>::value)>
-  FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
-      -> decltype(std::declval<arg_mapper>().map(
-          static_cast<underlying_t<T>>(val))) {
-    return map(static_cast<underlying_t<T>>(val));
-  }
-
-  template <typename T, FMT_ENABLE_IF(has_format_as<T>::value &&
-                                      !has_formatter<T, Context>::value)>
-  FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
-      -> decltype(std::declval<arg_mapper>().map(format_as(T()))) {
+  // Only map owning types because mapping views can be unsafe.
+  template <typename T, typename U = format_as_t<T>,
+            FMT_ENABLE_IF(std::is_arithmetic<U>::value)>
+  FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> decltype(this->map(U())) {
     return map(format_as(val));
   }
 
-  template <typename T, typename U = remove_cvref_t<T>>
-  struct formattable
-      : bool_constant<has_const_formatter<U, Context>() ||
-                      !std::is_const<remove_reference_t<T>>::value ||
-                      has_fallback_formatter<U, char_type>::value> {};
+  template <typename T, typename U = remove_const_t<T>>
+  struct formattable : bool_constant<has_const_formatter<U, Context>() ||
+                                     (has_formatter<U, Context>::value &&
+                                      !std::is_const<T>::value)> {};
 
-#if (FMT_MSC_VERSION != 0 && FMT_MSC_VERSION < 1910) || \
-    FMT_ICC_VERSION != 0 || defined(__NVCC__)
-  // Workaround a bug in MSVC and Intel (Issue 2746).
-  template <typename T> FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& {
-    return val;
-  }
-#else
   template <typename T, FMT_ENABLE_IF(formattable<T>::value)>
-  FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& {
+  FMT_CONSTEXPR FMT_INLINE auto do_map(T& val) -> T& {
     return val;
   }
   template <typename T, FMT_ENABLE_IF(!formattable<T>::value)>
-  FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const {
+  FMT_CONSTEXPR FMT_INLINE auto do_map(T&) -> unformattable {
     return {};
   }
-#endif
 
-  template <typename T, typename U = remove_cvref_t<T>,
-            FMT_ENABLE_IF(!is_string<U>::value && !is_char<U>::value &&
-                          !std::is_array<U>::value &&
-                          !std::is_pointer<U>::value &&
-                          !has_format_as<U>::value &&
-                          (has_formatter<U, Context>::value ||
-                           has_fallback_formatter<U, char_type>::value))>
-  FMT_CONSTEXPR FMT_INLINE auto map(T&& val)
-      -> decltype(this->do_map(std::forward<T>(val))) {
-    return do_map(std::forward<T>(val));
+  template <typename T, typename U = remove_const_t<T>,
+            FMT_ENABLE_IF((std::is_class<U>::value || std::is_enum<U>::value ||
+                           std::is_union<U>::value) &&
+                          !is_string<U>::value && !is_char<U>::value &&
+                          !is_named_arg<U>::value &&
+                          !std::is_arithmetic<format_as_t<U>>::value)>
+  FMT_CONSTEXPR FMT_INLINE auto map(T& val) -> decltype(this->do_map(val)) {
+    return do_map(val);
   }
 
   template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
   FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg)
-      -> decltype(std::declval<arg_mapper>().map(named_arg.value)) {
+      -> decltype(this->map(named_arg.value)) {
     return map(named_arg.value);
   }
 
@@ -1536,27 +1484,120 @@
 enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
 enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
 
-FMT_END_DETAIL_NAMESPACE
+template <typename Char, typename InputIt>
+auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
+  get_container(out).append(begin, end);
+  return out;
+}
+template <typename Char, typename InputIt>
+auto copy_str(InputIt begin, InputIt end,
+              std::back_insert_iterator<std::string> out)
+    -> std::back_insert_iterator<std::string> {
+  get_container(out).append(begin, end);
+  return out;
+}
 
-// An output iterator that appends to a buffer.
-// It is used to reduce symbol sizes for the common case.
-class appender : public std::back_insert_iterator<detail::buffer<char>> {
-  using base = std::back_insert_iterator<detail::buffer<char>>;
+template <typename Char, typename R, typename OutputIt>
+FMT_CONSTEXPR auto copy_str(R&& rng, OutputIt out) -> OutputIt {
+  return detail::copy_str<Char>(rng.begin(), rng.end(), out);
+}
 
-  template <typename T>
-  friend auto get_buffer(appender out) -> detail::buffer<char>& {
-    return detail::get_container(out);
-  }
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
+// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
+template <typename...> struct void_t_impl { using type = void; };
+template <typename... T> using void_t = typename void_t_impl<T...>::type;
+#else
+template <typename...> using void_t = void;
+#endif
+
+template <typename It, typename T, typename Enable = void>
+struct is_output_iterator : std::false_type {};
+
+template <typename It, typename T>
+struct is_output_iterator<
+    It, T,
+    void_t<typename std::iterator_traits<It>::iterator_category,
+           decltype(*std::declval<It>() = std::declval<T>())>>
+    : std::true_type {};
+
+template <typename It> struct is_back_insert_iterator : std::false_type {};
+template <typename Container>
+struct is_back_insert_iterator<std::back_insert_iterator<Container>>
+    : std::true_type {};
+
+// A type-erased reference to an std::locale to avoid a heavy <locale> include.
+class locale_ref {
+ private:
+  const void* locale_;  // A type-erased pointer to std::locale.
 
  public:
-  using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
-  appender(base it) noexcept : base(it) {}
-  FMT_UNCHECKED_ITERATOR(appender);
+  constexpr FMT_INLINE locale_ref() : locale_(nullptr) {}
+  template <typename Locale> explicit locale_ref(const Locale& loc);
 
-  auto operator++() noexcept -> appender& { return *this; }
-  auto operator++(int) noexcept -> appender { return *this; }
+  explicit operator bool() const noexcept { return locale_ != nullptr; }
+
+  template <typename Locale> auto get() const -> Locale;
 };
 
+template <typename> constexpr auto encode_types() -> unsigned long long {
+  return 0;
+}
+
+template <typename Context, typename Arg, typename... Args>
+constexpr auto encode_types() -> unsigned long long {
+  return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
+         (encode_types<Context, Args...>() << packed_arg_bits);
+}
+
+#if defined(__cpp_if_constexpr)
+// This type is intentionally undefined, only used for errors
+template <typename T, typename Char> struct type_is_unformattable_for;
+#endif
+
+template <bool PACKED, typename Context, typename T, FMT_ENABLE_IF(PACKED)>
+FMT_CONSTEXPR FMT_INLINE auto make_arg(T& val) -> value<Context> {
+  using arg_type = remove_cvref_t<decltype(arg_mapper<Context>().map(val))>;
+
+  constexpr bool formattable_char =
+      !std::is_same<arg_type, unformattable_char>::value;
+  static_assert(formattable_char, "Mixing character types is disallowed.");
+
+  // Formatting of arbitrary pointers is disallowed. If you want to format a
+  // pointer cast it to `void*` or `const void*`. In particular, this forbids
+  // formatting of `[const] volatile char*` printed as bool by iostreams.
+  constexpr bool formattable_pointer =
+      !std::is_same<arg_type, unformattable_pointer>::value;
+  static_assert(formattable_pointer,
+                "Formatting of non-void pointers is disallowed.");
+
+  constexpr bool formattable = !std::is_same<arg_type, unformattable>::value;
+#if defined(__cpp_if_constexpr)
+  if constexpr (!formattable) {
+    type_is_unformattable_for<T, typename Context::char_type> _;
+  }
+#endif
+  static_assert(
+      formattable,
+      "Cannot format an argument. To make type T formattable provide a "
+      "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
+  return {arg_mapper<Context>().map(val)};
+}
+
+template <typename Context, typename T>
+FMT_CONSTEXPR auto make_arg(T& val) -> basic_format_arg<Context> {
+  auto arg = basic_format_arg<Context>();
+  arg.type_ = mapped_type_constant<T, Context>::value;
+  arg.value_ = make_arg<true, Context>(val);
+  return arg;
+}
+
+template <bool PACKED, typename Context, typename T, FMT_ENABLE_IF(!PACKED)>
+FMT_CONSTEXPR inline auto make_arg(T& val) -> basic_format_arg<Context> {
+  return make_arg<Context>(val);
+}
+}  // namespace detail
+FMT_BEGIN_EXPORT
+
 // A formatting argument. It is a trivially copyable/constructible type to
 // allow storage in basic_memory_buffer.
 template <typename Context> class basic_format_arg {
@@ -1565,7 +1606,7 @@
   detail::type type_;
 
   template <typename ContextType, typename T>
-  friend FMT_CONSTEXPR auto detail::make_arg(T&& value)
+  friend FMT_CONSTEXPR auto detail::make_arg(T& value)
       -> basic_format_arg<ContextType>;
 
   template <typename Visitor, typename Ctx>
@@ -1619,6 +1660,7 @@
   ``vis(value)`` will be called with the value of type ``double``.
   \endrst
  */
+// DEPRECATED!
 template <typename Visitor, typename Context>
 FMT_CONSTEXPR FMT_INLINE auto visit_format_arg(
     Visitor&& vis, const basic_format_arg<Context>& arg) -> decltype(vis(0)) {
@@ -1660,136 +1702,8 @@
   return vis(monostate());
 }
 
-FMT_BEGIN_DETAIL_NAMESPACE
-
-template <typename Char, typename InputIt>
-auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
-  get_container(out).append(begin, end);
-  return out;
-}
-
-template <typename Char, typename R, typename OutputIt>
-FMT_CONSTEXPR auto copy_str(R&& rng, OutputIt out) -> OutputIt {
-  return detail::copy_str<Char>(rng.begin(), rng.end(), out);
-}
-
-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
-// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
-template <typename... Ts> struct void_t_impl { using type = void; };
-template <typename... Ts>
-using void_t = typename detail::void_t_impl<Ts...>::type;
-#else
-template <typename...> using void_t = void;
-#endif
-
-template <typename It, typename T, typename Enable = void>
-struct is_output_iterator : std::false_type {};
-
-template <typename It, typename T>
-struct is_output_iterator<
-    It, T,
-    void_t<typename std::iterator_traits<It>::iterator_category,
-           decltype(*std::declval<It>() = std::declval<T>())>>
-    : std::true_type {};
-
-template <typename OutputIt>
-struct is_back_insert_iterator : std::false_type {};
-template <typename Container>
-struct is_back_insert_iterator<std::back_insert_iterator<Container>>
-    : std::true_type {};
-
-template <typename OutputIt>
-struct is_contiguous_back_insert_iterator : std::false_type {};
-template <typename Container>
-struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
-    : is_contiguous<Container> {};
-template <>
-struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
-
-// A type-erased reference to an std::locale to avoid a heavy <locale> include.
-class locale_ref {
- private:
-  const void* locale_;  // A type-erased pointer to std::locale.
-
- public:
-  constexpr locale_ref() : locale_(nullptr) {}
-  template <typename Locale> explicit locale_ref(const Locale& loc);
-
-  explicit operator bool() const noexcept { return locale_ != nullptr; }
-
-  template <typename Locale> auto get() const -> Locale;
-};
-
-template <typename> constexpr auto encode_types() -> unsigned long long {
-  return 0;
-}
-
-template <typename Context, typename Arg, typename... Args>
-constexpr auto encode_types() -> unsigned long long {
-  return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
-         (encode_types<Context, Args...>() << packed_arg_bits);
-}
-
-template <typename Context, typename T>
-FMT_CONSTEXPR FMT_INLINE auto make_value(T&& val) -> value<Context> {
-  const auto& arg = arg_mapper<Context>().map(FMT_FORWARD(val));
-
-  constexpr bool formattable_char =
-      !std::is_same<decltype(arg), const unformattable_char&>::value;
-  static_assert(formattable_char, "Mixing character types is disallowed.");
-
-  constexpr bool formattable_const =
-      !std::is_same<decltype(arg), const unformattable_const&>::value;
-  static_assert(formattable_const, "Cannot format a const argument.");
-
-  // Formatting of arbitrary pointers is disallowed. If you want to output
-  // a pointer cast it to "void *" or "const void *". In particular, this
-  // forbids formatting of "[const] volatile char *" which is printed as bool
-  // by iostreams.
-  constexpr bool formattable_pointer =
-      !std::is_same<decltype(arg), const unformattable_pointer&>::value;
-  static_assert(formattable_pointer,
-                "Formatting of non-void pointers is disallowed.");
-
-  constexpr bool formattable =
-      !std::is_same<decltype(arg), const unformattable&>::value;
-  static_assert(
-      formattable,
-      "Cannot format an argument. To make type T formattable provide a "
-      "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
-  return {arg};
-}
-
-template <typename Context, typename T>
-FMT_CONSTEXPR auto make_arg(T&& value) -> basic_format_arg<Context> {
-  basic_format_arg<Context> arg;
-  arg.type_ = mapped_type_constant<T, Context>::value;
-  arg.value_ = make_value<Context>(value);
-  return arg;
-}
-
-// The type template parameter is there to avoid an ODR violation when using
-// a fallback formatter in one translation unit and an implicit conversion in
-// another (not recommended).
-template <bool IS_PACKED, typename Context, type, typename T,
-          FMT_ENABLE_IF(IS_PACKED)>
-FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value<Context> {
-  return make_value<Context>(val);
-}
-
-template <bool IS_PACKED, typename Context, type, typename T,
-          FMT_ENABLE_IF(!IS_PACKED)>
-FMT_CONSTEXPR inline auto make_arg(T&& value) -> basic_format_arg<Context> {
-  return make_arg<Context>(value);
-}
-FMT_END_DETAIL_NAMESPACE
-
 // Formatting context.
 template <typename OutputIt, typename Char> class basic_format_context {
- public:
-  /** The character type for the output. */
-  using char_type = Char;
-
  private:
   OutputIt out_;
   basic_format_args<basic_format_context> args_;
@@ -1798,31 +1712,32 @@
  public:
   using iterator = OutputIt;
   using format_arg = basic_format_arg<basic_format_context>;
+  using format_args = basic_format_args<basic_format_context>;
   using parse_context_type = basic_format_parse_context<Char>;
-  template <typename T> using formatter_type = formatter<T, char_type>;
+  template <typename T> using formatter_type = formatter<T, Char>;
+
+  /** The character type for the output. */
+  using char_type = Char;
 
   basic_format_context(basic_format_context&&) = default;
   basic_format_context(const basic_format_context&) = delete;
   void operator=(const basic_format_context&) = delete;
   /**
-   Constructs a ``basic_format_context`` object. References to the arguments are
-   stored in the object so make sure they have appropriate lifetimes.
+    Constructs a ``basic_format_context`` object. References to the arguments
+    are stored in the object so make sure they have appropriate lifetimes.
    */
-  constexpr basic_format_context(
-      OutputIt out, basic_format_args<basic_format_context> ctx_args,
-      detail::locale_ref loc = detail::locale_ref())
+  constexpr basic_format_context(OutputIt out, format_args ctx_args,
+                                 detail::locale_ref loc = {})
       : out_(out), args_(ctx_args), loc_(loc) {}
 
   constexpr auto arg(int id) const -> format_arg { return args_.get(id); }
-  FMT_CONSTEXPR auto arg(basic_string_view<char_type> name) -> format_arg {
+  FMT_CONSTEXPR auto arg(basic_string_view<Char> name) -> format_arg {
     return args_.get(name);
   }
-  FMT_CONSTEXPR auto arg_id(basic_string_view<char_type> name) -> int {
+  FMT_CONSTEXPR auto arg_id(basic_string_view<Char> name) -> int {
     return args_.get_id(name);
   }
-  auto args() const -> const basic_format_args<basic_format_context>& {
-    return args_;
-  }
+  auto args() const -> const format_args& { return args_; }
 
   FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; }
   void on_error(const char* message) { error_handler().on_error(message); }
@@ -1843,16 +1758,10 @@
     basic_format_context<detail::buffer_appender<Char>, Char>;
 using format_context = buffer_context<char>;
 
-// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
-#define FMT_BUFFER_CONTEXT(Char) \
-  basic_format_context<detail::buffer_appender<Char>, Char>
-
 template <typename T, typename Char = char>
-using is_formattable = bool_constant<
-    !std::is_base_of<detail::unformattable,
-                     decltype(detail::arg_mapper<buffer_context<Char>>().map(
-                         std::declval<T>()))>::value &&
-    !detail::has_fallback_formatter<T, Char>::value>;
+using is_formattable = bool_constant<!std::is_base_of<
+    detail::unformattable, decltype(detail::arg_mapper<buffer_context<Char>>()
+                                        .map(std::declval<T&>()))>::value>;
 
 /**
   \rst
@@ -1870,7 +1779,7 @@
 {
  private:
   static const size_t num_args = sizeof...(Args);
-  static const size_t num_named_args = detail::count_named_args<Args...>();
+  static constexpr size_t num_named_args = detail::count_named_args<Args...>();
   static const bool is_packed = num_args <= detail::max_packed_args;
 
   using value_type = conditional_t<is_packed, detail::value<Context>,
@@ -1891,16 +1800,14 @@
 
  public:
   template <typename... T>
-  FMT_CONSTEXPR FMT_INLINE format_arg_store(T&&... args)
+  FMT_CONSTEXPR FMT_INLINE format_arg_store(T&... args)
       :
 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
         basic_format_args<Context>(*this),
 #endif
-        data_{detail::make_arg<
-            is_packed, Context,
-            detail::mapped_type_constant<remove_cvref_t<T>, Context>::value>(
-            FMT_FORWARD(args))...} {
-    detail::init_named_args(data_.named_args(), 0, 0, args...);
+        data_{detail::make_arg<is_packed, Context>(args)...} {
+    if (detail::const_check(num_named_args != 0))
+      detail::init_named_args(data_.named_args(), 0, 0, args...);
   }
 };
 
@@ -1908,14 +1815,15 @@
   \rst
   Constructs a `~fmt::format_arg_store` object that contains references to
   arguments and can be implicitly converted to `~fmt::format_args`. `Context`
-  can be omitted in which case it defaults to `~fmt::context`.
+  can be omitted in which case it defaults to `~fmt::format_context`.
   See `~fmt::arg` for lifetime considerations.
   \endrst
  */
-template <typename Context = format_context, typename... Args>
-constexpr auto make_format_args(Args&&... args)
-    -> format_arg_store<Context, remove_cvref_t<Args>...> {
-  return {FMT_FORWARD(args)...};
+// Arguments are taken by lvalue references to avoid some lifetime issues.
+template <typename Context = format_context, typename... T>
+constexpr auto make_format_args(T&... args)
+    -> format_arg_store<Context, remove_cvref_t<T>...> {
+  return {args...};
 }
 
 /**
@@ -1934,6 +1842,7 @@
   static_assert(!detail::is_named_arg<T>(), "nested named arguments");
   return {name, arg};
 }
+FMT_END_EXPORT
 
 /**
   \rst
@@ -1942,7 +1851,7 @@
   ``vformat``::
 
     void vlog(string_view format_str, format_args args);  // OK
-    format_args args = make_format_args(42);  // Error: dangling reference
+    format_args args = make_format_args();  // Error: dangling reference
   \endrst
  */
 template <typename Context> class basic_format_args {
@@ -2059,7 +1968,7 @@
 /** An alias to ``basic_format_args<format_context>``. */
 // A separate type would result in shorter symbols but break ABI compatibility
 // between clang and gcc on ARM (#1919).
-using format_args = basic_format_args<format_context>;
+FMT_EXPORT using format_args = basic_format_args<format_context>;
 
 // We cannot use enum classes as bit fields because of a gcc bug, so we put them
 // in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414).
@@ -2080,7 +1989,7 @@
 }
 using sign_t = sign::type;
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 // Workaround an array initialization issue in gcc 4.8.
 template <typename Char> struct fill_t {
@@ -2092,7 +2001,7 @@
  public:
   FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
     auto size = s.size();
-    if (size > max_size) return throw_format_error("invalid fill");
+    FMT_ASSERT(size <= max_size, "invalid fill");
     for (size_t i = 0; i < size; ++i) data_[i] = s[i];
     size_ = static_cast<unsigned char>(size);
   }
@@ -2105,11 +2014,10 @@
     return data_[index];
   }
 };
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
 enum class presentation_type : unsigned char {
   none,
-  // Integer types should go first,
   dec,             // 'd'
   oct,             // 'o'
   hex_lower,       // 'x'
@@ -2131,7 +2039,7 @@
 };
 
 // Format specifiers for built-in and string types.
-template <typename Char> struct basic_format_specs {
+template <typename Char = char> struct format_specs {
   int width;
   int precision;
   presentation_type type;
@@ -2141,7 +2049,7 @@
   bool localized : 1;
   detail::fill_t<Char> fill;
 
-  constexpr basic_format_specs()
+  constexpr format_specs()
       : width(0),
         precision(-1),
         type(presentation_type::none),
@@ -2151,9 +2059,7 @@
         localized(false) {}
 };
 
-using format_specs = basic_format_specs<char>;
-
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 enum class arg_id_kind { none, index, name };
 
@@ -2174,7 +2080,7 @@
 
   arg_id_kind kind;
   union value {
-    FMT_CONSTEXPR value(int id = 0) : index{id} {}
+    FMT_CONSTEXPR value(int idx = 0) : index(idx) {}
     FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
 
     int index;
@@ -2183,134 +2089,30 @@
 };
 
 // Format specifiers with width and precision resolved at formatting rather
-// than parsing time to allow re-using the same parsed specifiers with
+// than parsing time to allow reusing the same parsed specifiers with
 // different sets of arguments (precompilation of format strings).
-template <typename Char>
-struct dynamic_format_specs : basic_format_specs<Char> {
+template <typename Char = char>
+struct dynamic_format_specs : format_specs<Char> {
   arg_ref<Char> width_ref;
   arg_ref<Char> precision_ref;
 };
 
-struct auto_id {};
-
-// A format specifier handler that sets fields in basic_format_specs.
-template <typename Char> class specs_setter {
- protected:
-  basic_format_specs<Char>& specs_;
-
- public:
-  explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
-      : specs_(specs) {}
-
-  FMT_CONSTEXPR specs_setter(const specs_setter& other)
-      : specs_(other.specs_) {}
-
-  FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
-  FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
-    specs_.fill = fill;
-  }
-  FMT_CONSTEXPR void on_sign(sign_t s) { specs_.sign = s; }
-  FMT_CONSTEXPR void on_hash() { specs_.alt = true; }
-  FMT_CONSTEXPR void on_localized() { specs_.localized = true; }
-
-  FMT_CONSTEXPR void on_zero() {
-    if (specs_.align == align::none) specs_.align = align::numeric;
-    specs_.fill[0] = Char('0');
-  }
-
-  FMT_CONSTEXPR void on_width(int width) { specs_.width = width; }
-  FMT_CONSTEXPR void on_precision(int precision) {
-    specs_.precision = precision;
-  }
-  FMT_CONSTEXPR void end_precision() {}
-
-  FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; }
-};
-
-// Format spec handler that saves references to arguments representing dynamic
-// width and precision to be resolved at formatting time.
-template <typename ParseContext>
-class dynamic_specs_handler
-    : public specs_setter<typename ParseContext::char_type> {
- public:
-  using char_type = typename ParseContext::char_type;
-
-  FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs,
-                                      ParseContext& ctx)
-      : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
-
-  FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other)
-      : specs_setter<char_type>(other),
-        specs_(other.specs_),
-        context_(other.context_) {}
-
-  template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
-    specs_.width_ref = make_arg_ref(arg_id);
-  }
-
-  template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
-    specs_.precision_ref = make_arg_ref(arg_id);
-  }
-
-  FMT_CONSTEXPR void on_error(const char* message) {
-    context_.on_error(message);
-  }
-
- private:
-  dynamic_format_specs<char_type>& specs_;
-  ParseContext& context_;
-
-  using arg_ref_type = arg_ref<char_type>;
-
-  FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type {
-    context_.check_arg_id(arg_id);
-    context_.check_dynamic_spec(arg_id);
-    return arg_ref_type(arg_id);
-  }
-
-  FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
-    int arg_id = context_.next_arg_id();
-    context_.check_dynamic_spec(arg_id);
-    return arg_ref_type(arg_id);
-  }
-
-  FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
-      -> arg_ref_type {
-    context_.check_arg_id(arg_id);
-    basic_string_view<char_type> format_str(
-        context_.begin(), to_unsigned(context_.end() - context_.begin()));
-    return arg_ref_type(arg_id);
-  }
-};
-
-template <typename Char> constexpr bool is_ascii_letter(Char c) {
-  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
-}
-
-// Converts a character to ASCII. Returns a number > 127 on conversion failure.
+// Converts a character to ASCII. Returns '\0' on conversion failure.
 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
-constexpr auto to_ascii(Char c) -> Char {
-  return c;
+constexpr auto to_ascii(Char c) -> char {
+  return c <= 0xff ? static_cast<char>(c) : '\0';
 }
 template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
-constexpr auto to_ascii(Char c) -> underlying_t<Char> {
-  return c;
+constexpr auto to_ascii(Char c) -> char {
+  return c <= 0xff ? static_cast<char>(c) : '\0';
 }
 
-FMT_CONSTEXPR inline auto code_point_length_impl(char c) -> int {
-  return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
-      [static_cast<unsigned char>(c) >> 3];
-}
-
+// Returns the number of code units in a code point or 1 on error.
 template <typename Char>
 FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
   if (const_check(sizeof(Char) != 1)) return 1;
-  int len = code_point_length_impl(static_cast<char>(*begin));
-
-  // Compute the pointer to the next character early so that the next
-  // iteration can start working on the next character. Neither Clang
-  // nor GCC figure out this reordering on their own.
-  return len + !len;
+  auto c = static_cast<unsigned char>(*begin);
+  return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 0x3) + 1;
 }
 
 // Return the result via the out param to workaround gcc bug 77539.
@@ -2355,279 +2157,284 @@
              : error_value;
 }
 
-// Parses fill and alignment.
-template <typename Char, typename Handler>
-FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
-                               Handler&& handler) -> const Char* {
-  FMT_ASSERT(begin != end, "");
-  auto align = align::none;
-  auto p = begin + code_point_length(begin);
-  if (end - p <= 0) p = begin;
-  for (;;) {
-    switch (to_ascii(*p)) {
-    case '<':
-      align = align::left;
-      break;
-    case '>':
-      align = align::right;
-      break;
-    case '^':
-      align = align::center;
-      break;
-    default:
-      break;
-    }
-    if (align != align::none) {
-      if (p != begin) {
-        auto c = *begin;
-        if (c == '{')
-          return handler.on_error("invalid fill character '{'"), begin;
-        handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
-        begin = p + 1;
-      } else
-        ++begin;
-      handler.on_align(align);
-      break;
-    } else if (p == begin) {
-      break;
-    }
-    p = begin;
+FMT_CONSTEXPR inline auto parse_align(char c) -> align_t {
+  switch (c) {
+  case '<':
+    return align::left;
+  case '>':
+    return align::right;
+  case '^':
+    return align::center;
   }
-  return begin;
+  return align::none;
 }
 
-template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
-  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
+template <typename Char> constexpr auto is_name_start(Char c) -> bool {
+  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_';
 }
 
-template <typename Char, typename IDHandler>
+template <typename Char, typename Handler>
 FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
-                                   IDHandler&& handler) -> const Char* {
-  FMT_ASSERT(begin != end, "");
+                                   Handler&& handler) -> const Char* {
   Char c = *begin;
   if (c >= '0' && c <= '9') {
     int index = 0;
+    constexpr int max = (std::numeric_limits<int>::max)();
     if (c != '0')
-      index =
-          parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
+      index = parse_nonnegative_int(begin, end, max);
     else
       ++begin;
     if (begin == end || (*begin != '}' && *begin != ':'))
-      handler.on_error("invalid format string");
+      throw_format_error("invalid format string");
     else
-      handler(index);
+      handler.on_index(index);
     return begin;
   }
   if (!is_name_start(c)) {
-    handler.on_error("invalid format string");
+    throw_format_error("invalid format string");
     return begin;
   }
   auto it = begin;
   do {
     ++it;
-  } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9')));
-  handler(basic_string_view<Char>(begin, to_unsigned(it - begin)));
+  } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9')));
+  handler.on_name({begin, to_unsigned(it - begin)});
   return it;
 }
 
-template <typename Char, typename IDHandler>
+template <typename Char, typename Handler>
 FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
-                                           IDHandler&& handler) -> const Char* {
+                                           Handler&& handler) -> const Char* {
+  FMT_ASSERT(begin != end, "");
   Char c = *begin;
   if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
-  handler();
+  handler.on_auto();
   return begin;
 }
 
-template <typename Char, typename Handler>
-FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
-                               Handler&& handler) -> const Char* {
-  using detail::auto_id;
-  struct width_adapter {
-    Handler& handler;
+template <typename Char> struct dynamic_spec_id_handler {
+  basic_format_parse_context<Char>& ctx;
+  arg_ref<Char>& ref;
 
-    FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
-    FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
-    FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
-      handler.on_dynamic_width(id);
-    }
-    FMT_CONSTEXPR void on_error(const char* message) {
-      if (message) handler.on_error(message);
-    }
-  };
+  FMT_CONSTEXPR void on_auto() {
+    int id = ctx.next_arg_id();
+    ref = arg_ref<Char>(id);
+    ctx.check_dynamic_spec(id);
+  }
+  FMT_CONSTEXPR void on_index(int id) {
+    ref = arg_ref<Char>(id);
+    ctx.check_arg_id(id);
+    ctx.check_dynamic_spec(id);
+  }
+  FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
+    ref = arg_ref<Char>(id);
+    ctx.check_arg_id(id);
+  }
+};
 
+// Parses [integer | "{" [arg_id] "}"].
+template <typename Char>
+FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
+                                      int& value, arg_ref<Char>& ref,
+                                      basic_format_parse_context<Char>& ctx)
+    -> const Char* {
   FMT_ASSERT(begin != end, "");
   if ('0' <= *begin && *begin <= '9') {
-    int width = parse_nonnegative_int(begin, end, -1);
-    if (width != -1)
-      handler.on_width(width);
+    int val = parse_nonnegative_int(begin, end, -1);
+    if (val != -1)
+      value = val;
     else
-      handler.on_error("number is too big");
+      throw_format_error("number is too big");
   } else if (*begin == '{') {
     ++begin;
-    if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
-    if (begin == end || *begin != '}')
-      return handler.on_error("invalid format string"), begin;
-    ++begin;
+    auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
+    if (begin != end) begin = parse_arg_id(begin, end, handler);
+    if (begin != end && *begin == '}') return ++begin;
+    throw_format_error("invalid format string");
   }
   return begin;
 }
 
-template <typename Char, typename Handler>
-FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
-                                   Handler&& handler) -> const Char* {
-  using detail::auto_id;
-  struct precision_adapter {
-    Handler& handler;
-
-    FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
-    FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
-    FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
-      handler.on_dynamic_precision(id);
-    }
-    FMT_CONSTEXPR void on_error(const char* message) {
-      if (message) handler.on_error(message);
-    }
-  };
-
-  ++begin;
-  auto c = begin != end ? *begin : Char();
-  if ('0' <= c && c <= '9') {
-    auto precision = parse_nonnegative_int(begin, end, -1);
-    if (precision != -1)
-      handler.on_precision(precision);
-    else
-      handler.on_error("number is too big");
-  } else if (c == '{') {
-    ++begin;
-    if (begin != end)
-      begin = parse_arg_id(begin, end, precision_adapter{handler});
-    if (begin == end || *begin++ != '}')
-      return handler.on_error("invalid format string"), begin;
-  } else {
-    return handler.on_error("missing precision specifier"), begin;
-  }
-  handler.end_precision();
-  return begin;
-}
-
 template <typename Char>
-FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type {
-  switch (to_ascii(type)) {
-  case 'd':
-    return presentation_type::dec;
-  case 'o':
-    return presentation_type::oct;
-  case 'x':
-    return presentation_type::hex_lower;
-  case 'X':
-    return presentation_type::hex_upper;
-  case 'b':
-    return presentation_type::bin_lower;
-  case 'B':
-    return presentation_type::bin_upper;
-  case 'a':
-    return presentation_type::hexfloat_lower;
-  case 'A':
-    return presentation_type::hexfloat_upper;
-  case 'e':
-    return presentation_type::exp_lower;
-  case 'E':
-    return presentation_type::exp_upper;
-  case 'f':
-    return presentation_type::fixed_lower;
-  case 'F':
-    return presentation_type::fixed_upper;
-  case 'g':
-    return presentation_type::general_lower;
-  case 'G':
-    return presentation_type::general_upper;
-  case 'c':
-    return presentation_type::chr;
-  case 's':
-    return presentation_type::string;
-  case 'p':
-    return presentation_type::pointer;
-  case '?':
-    return presentation_type::debug;
-  default:
-    return presentation_type::none;
-  }
-}
-
-// Parses standard format specifiers and sends notifications about parsed
-// components to handler.
-template <typename Char, typename SpecHandler>
-FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
-                                                 const Char* end,
-                                                 SpecHandler&& handler)
+FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
+                                   int& value, arg_ref<Char>& ref,
+                                   basic_format_parse_context<Char>& ctx)
     -> const Char* {
-  if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) &&
-      *begin != 'L') {
-    presentation_type type = parse_presentation_type(*begin++);
-    if (type == presentation_type::none)
-      handler.on_error("invalid type specifier");
-    handler.on_type(type);
+  ++begin;
+  if (begin == end || *begin == '}') {
+    throw_format_error("invalid precision");
     return begin;
   }
+  return parse_dynamic_spec(begin, end, value, ref, ctx);
+}
 
-  if (begin == end) return begin;
+enum class state { start, align, sign, hash, zero, width, precision, locale };
 
-  begin = parse_align(begin, end, handler);
-  if (begin == end) return begin;
-
-  // Parse sign.
-  switch (to_ascii(*begin)) {
-  case '+':
-    handler.on_sign(sign::plus);
-    ++begin;
-    break;
-  case '-':
-    handler.on_sign(sign::minus);
-    ++begin;
-    break;
-  case ' ':
-    handler.on_sign(sign::space);
-    ++begin;
-    break;
-  default:
-    break;
-  }
-  if (begin == end) return begin;
-
-  if (*begin == '#') {
-    handler.on_hash();
-    if (++begin == end) return begin;
-  }
-
-  // Parse zero flag.
-  if (*begin == '0') {
-    handler.on_zero();
-    if (++begin == end) return begin;
-  }
-
-  begin = parse_width(begin, end, handler);
-  if (begin == end) return begin;
-
-  // Parse precision.
-  if (*begin == '.') {
-    begin = parse_precision(begin, end, handler);
+// Parses standard format specifiers.
+template <typename Char>
+FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(
+    const Char* begin, const Char* end, dynamic_format_specs<Char>& specs,
+    basic_format_parse_context<Char>& ctx, type arg_type) -> const Char* {
+  auto c = '\0';
+  if (end - begin > 1) {
+    auto next = to_ascii(begin[1]);
+    c = parse_align(next) == align::none ? to_ascii(*begin) : '\0';
+  } else {
     if (begin == end) return begin;
+    c = to_ascii(*begin);
   }
 
-  if (*begin == 'L') {
-    handler.on_localized();
-    ++begin;
-  }
+  struct {
+    state current_state = state::start;
+    FMT_CONSTEXPR void operator()(state s, bool valid = true) {
+      if (current_state >= s || !valid)
+        throw_format_error("invalid format specifier");
+      current_state = s;
+    }
+  } enter_state;
 
-  // Parse type.
-  if (begin != end && *begin != '}') {
-    presentation_type type = parse_presentation_type(*begin++);
-    if (type == presentation_type::none)
-      handler.on_error("invalid type specifier");
-    handler.on_type(type);
+  using pres = presentation_type;
+  constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
+  struct {
+    const Char*& begin;
+    dynamic_format_specs<Char>& specs;
+    type arg_type;
+
+    FMT_CONSTEXPR auto operator()(pres type, int set) -> const Char* {
+      if (!in(arg_type, set)) throw_format_error("invalid format specifier");
+      specs.type = type;
+      return begin + 1;
+    }
+  } parse_presentation_type{begin, specs, arg_type};
+
+  for (;;) {
+    switch (c) {
+    case '<':
+    case '>':
+    case '^':
+      enter_state(state::align);
+      specs.align = parse_align(c);
+      ++begin;
+      break;
+    case '+':
+    case '-':
+    case ' ':
+      enter_state(state::sign, in(arg_type, sint_set | float_set));
+      switch (c) {
+      case '+':
+        specs.sign = sign::plus;
+        break;
+      case '-':
+        specs.sign = sign::minus;
+        break;
+      case ' ':
+        specs.sign = sign::space;
+        break;
+      }
+      ++begin;
+      break;
+    case '#':
+      enter_state(state::hash, is_arithmetic_type(arg_type));
+      specs.alt = true;
+      ++begin;
+      break;
+    case '0':
+      enter_state(state::zero);
+      if (!is_arithmetic_type(arg_type))
+        throw_format_error("format specifier requires numeric argument");
+      if (specs.align == align::none) {
+        // Ignore 0 if align is specified for compatibility with std::format.
+        specs.align = align::numeric;
+        specs.fill[0] = Char('0');
+      }
+      ++begin;
+      break;
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '{':
+      enter_state(state::width);
+      begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx);
+      break;
+    case '.':
+      enter_state(state::precision,
+                  in(arg_type, float_set | string_set | cstring_set));
+      begin = parse_precision(begin, end, specs.precision, specs.precision_ref,
+                              ctx);
+      break;
+    case 'L':
+      enter_state(state::locale, is_arithmetic_type(arg_type));
+      specs.localized = true;
+      ++begin;
+      break;
+    case 'd':
+      return parse_presentation_type(pres::dec, integral_set);
+    case 'o':
+      return parse_presentation_type(pres::oct, integral_set);
+    case 'x':
+      return parse_presentation_type(pres::hex_lower, integral_set);
+    case 'X':
+      return parse_presentation_type(pres::hex_upper, integral_set);
+    case 'b':
+      return parse_presentation_type(pres::bin_lower, integral_set);
+    case 'B':
+      return parse_presentation_type(pres::bin_upper, integral_set);
+    case 'a':
+      return parse_presentation_type(pres::hexfloat_lower, float_set);
+    case 'A':
+      return parse_presentation_type(pres::hexfloat_upper, float_set);
+    case 'e':
+      return parse_presentation_type(pres::exp_lower, float_set);
+    case 'E':
+      return parse_presentation_type(pres::exp_upper, float_set);
+    case 'f':
+      return parse_presentation_type(pres::fixed_lower, float_set);
+    case 'F':
+      return parse_presentation_type(pres::fixed_upper, float_set);
+    case 'g':
+      return parse_presentation_type(pres::general_lower, float_set);
+    case 'G':
+      return parse_presentation_type(pres::general_upper, float_set);
+    case 'c':
+      return parse_presentation_type(pres::chr, integral_set);
+    case 's':
+      return parse_presentation_type(pres::string,
+                                     bool_set | string_set | cstring_set);
+    case 'p':
+      return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
+    case '?':
+      return parse_presentation_type(pres::debug,
+                                     char_set | string_set | cstring_set);
+    case '}':
+      return begin;
+    default: {
+      if (*begin == '}') return begin;
+      // Parse fill and alignment.
+      auto fill_end = begin + code_point_length(begin);
+      if (end - fill_end <= 0) {
+        throw_format_error("invalid format specifier");
+        return begin;
+      }
+      if (*begin == '{') {
+        throw_format_error("invalid fill character '{'");
+        return begin;
+      }
+      auto align = parse_align(to_ascii(*fill_end));
+      enter_state(state::align, align != align::none);
+      specs.fill = {begin, to_unsigned(fill_end - begin)};
+      specs.align = align;
+      begin = fill_end + 1;
+    }
+    }
+    if (begin == end) return begin;
+    c = to_ascii(*begin);
   }
-  return begin;
 }
 
 template <typename Char, typename Handler>
@@ -2637,14 +2444,11 @@
     Handler& handler;
     int arg_id;
 
-    FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
-    FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
-    FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
+    FMT_CONSTEXPR void on_auto() { arg_id = handler.on_arg_id(); }
+    FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); }
+    FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
       arg_id = handler.on_arg_id(id);
     }
-    FMT_CONSTEXPR void on_error(const char* message) {
-      if (message) handler.on_error(message);
-    }
   };
 
   ++begin;
@@ -2673,9 +2477,6 @@
 template <bool IS_CONSTEXPR, typename Char, typename Handler>
 FMT_CONSTEXPR FMT_INLINE void parse_format_string(
     basic_string_view<Char> format_str, Handler&& handler) {
-  // Workaround a name-lookup bug in MSVC's modules implementation.
-  using detail::find;
-
   auto begin = format_str.data();
   auto end = begin + format_str.size();
   if (end - begin < 32) {
@@ -2735,189 +2536,46 @@
     -> decltype(ctx.begin()) {
   using char_type = typename ParseContext::char_type;
   using context = buffer_context<char_type>;
-  using stripped_type = typename strip_named_arg<T>::type;
   using mapped_type = conditional_t<
       mapped_type_constant<T, context>::value != type::custom_type,
       decltype(arg_mapper<context>().map(std::declval<const T&>())),
-      stripped_type>;
-  auto f = conditional_t<has_formatter<mapped_type, context>::value,
-                         formatter<mapped_type, char_type>,
-                         fallback_formatter<stripped_type, char_type>>();
-  return f.parse(ctx);
+      typename strip_named_arg<T>::type>;
+#if defined(__cpp_if_constexpr)
+  if constexpr (std::is_default_constructible_v<
+                    formatter<mapped_type, char_type>>) {
+    return formatter<mapped_type, char_type>().parse(ctx);
+  } else {
+    type_is_unformattable_for<T, char_type> _;
+    return ctx.begin();
+  }
+#else
+  return formatter<mapped_type, char_type>().parse(ctx);
+#endif
 }
 
-template <typename ErrorHandler>
-FMT_CONSTEXPR void check_int_type_spec(presentation_type type,
-                                       ErrorHandler&& eh) {
-  if (type > presentation_type::bin_upper && type != presentation_type::chr)
-    eh.on_error("invalid type specifier");
-}
-
-// Checks char specs and returns true if the type spec is char (and not int).
-template <typename Char, typename ErrorHandler = error_handler>
-FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
-                                    ErrorHandler&& eh = {}) -> bool {
+// Checks char specs and returns true iff the presentation type is char-like.
+template <typename Char>
+FMT_CONSTEXPR auto check_char_specs(const format_specs<Char>& specs) -> bool {
   if (specs.type != presentation_type::none &&
       specs.type != presentation_type::chr &&
       specs.type != presentation_type::debug) {
-    check_int_type_spec(specs.type, eh);
     return false;
   }
   if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
-    eh.on_error("invalid format specifier for char");
+    throw_format_error("invalid format specifier for char");
   return true;
 }
 
-// A floating-point presentation format.
-enum class float_format : unsigned char {
-  general,  // General: exponent notation or fixed point based on magnitude.
-  exp,      // Exponent notation with the default precision of 6, e.g. 1.2e-3.
-  fixed,    // Fixed point with the default precision of 6, e.g. 0.0012.
-  hex
-};
-
-struct float_specs {
-  int precision;
-  float_format format : 8;
-  sign_t sign : 8;
-  bool upper : 1;
-  bool locale : 1;
-  bool binary32 : 1;
-  bool showpoint : 1;
-};
-
-template <typename ErrorHandler = error_handler, typename Char>
-FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
-                                         ErrorHandler&& eh = {})
-    -> float_specs {
-  auto result = float_specs();
-  result.showpoint = specs.alt;
-  result.locale = specs.localized;
-  switch (specs.type) {
-  case presentation_type::none:
-    result.format = float_format::general;
-    break;
-  case presentation_type::general_upper:
-    result.upper = true;
-    FMT_FALLTHROUGH;
-  case presentation_type::general_lower:
-    result.format = float_format::general;
-    break;
-  case presentation_type::exp_upper:
-    result.upper = true;
-    FMT_FALLTHROUGH;
-  case presentation_type::exp_lower:
-    result.format = float_format::exp;
-    result.showpoint |= specs.precision != 0;
-    break;
-  case presentation_type::fixed_upper:
-    result.upper = true;
-    FMT_FALLTHROUGH;
-  case presentation_type::fixed_lower:
-    result.format = float_format::fixed;
-    result.showpoint |= specs.precision != 0;
-    break;
-  case presentation_type::hexfloat_upper:
-    result.upper = true;
-    FMT_FALLTHROUGH;
-  case presentation_type::hexfloat_lower:
-    result.format = float_format::hex;
-    break;
-  default:
-    eh.on_error("invalid type specifier");
-    break;
-  }
-  return result;
-}
-
-template <typename ErrorHandler = error_handler>
-FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type,
-                                           ErrorHandler&& eh = {}) -> bool {
-  if (type == presentation_type::none || type == presentation_type::string ||
-      type == presentation_type::debug)
-    return true;
-  if (type != presentation_type::pointer) eh.on_error("invalid type specifier");
-  return false;
-}
-
-template <typename ErrorHandler = error_handler>
-FMT_CONSTEXPR void check_string_type_spec(presentation_type type,
-                                          ErrorHandler&& eh = {}) {
-  if (type != presentation_type::none && type != presentation_type::string &&
-      type != presentation_type::debug)
-    eh.on_error("invalid type specifier");
-}
-
-template <typename ErrorHandler>
-FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type,
-                                           ErrorHandler&& eh) {
-  if (type != presentation_type::none && type != presentation_type::pointer)
-    eh.on_error("invalid type specifier");
-}
-
-// A parse_format_specs handler that checks if specifiers are consistent with
-// the argument type.
-template <typename Handler> class specs_checker : public Handler {
- private:
-  detail::type arg_type_;
-
-  FMT_CONSTEXPR void require_numeric_argument() {
-    if (!is_arithmetic_type(arg_type_))
-      this->on_error("format specifier requires numeric argument");
-  }
-
- public:
-  FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type)
-      : Handler(handler), arg_type_(arg_type) {}
-
-  FMT_CONSTEXPR void on_align(align_t align) {
-    if (align == align::numeric) require_numeric_argument();
-    Handler::on_align(align);
-  }
-
-  FMT_CONSTEXPR void on_sign(sign_t s) {
-    require_numeric_argument();
-    if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
-        arg_type_ != type::long_long_type && arg_type_ != type::int128_type &&
-        arg_type_ != type::char_type) {
-      this->on_error("format specifier requires signed argument");
-    }
-    Handler::on_sign(s);
-  }
-
-  FMT_CONSTEXPR void on_hash() {
-    require_numeric_argument();
-    Handler::on_hash();
-  }
-
-  FMT_CONSTEXPR void on_localized() {
-    require_numeric_argument();
-    Handler::on_localized();
-  }
-
-  FMT_CONSTEXPR void on_zero() {
-    require_numeric_argument();
-    Handler::on_zero();
-  }
-
-  FMT_CONSTEXPR void end_precision() {
-    if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
-      this->on_error("precision not allowed for this argument type");
-  }
-};
-
-constexpr int invalid_arg_index = -1;
-
 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
 template <int N, typename T, typename... Args, typename Char>
 constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
-  if constexpr (detail::is_statically_named_arg<T>()) {
+  if constexpr (is_statically_named_arg<T>()) {
     if (name == T::name) return N;
   }
   if constexpr (sizeof...(Args) > 0)
     return get_arg_index_by_name<N + 1, Args...>(name);
   (void)name;  // Workaround an MSVC bug about "unused" parameter.
-  return invalid_arg_index;
+  return -1;
 }
 #endif
 
@@ -2928,34 +2586,29 @@
     return get_arg_index_by_name<0, Args...>(name);
 #endif
   (void)name;
-  return invalid_arg_index;
+  return -1;
 }
 
-template <typename Char, typename ErrorHandler, typename... Args>
-class format_string_checker {
+template <typename Char, typename... Args> class format_string_checker {
  private:
-  // In the future basic_format_parse_context will replace compile_parse_context
-  // here and will use is_constant_evaluated and downcasting to access the data
-  // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1.
-  using parse_context_type = compile_parse_context<Char, ErrorHandler>;
+  using parse_context_type = compile_parse_context<Char>;
   static constexpr int num_args = sizeof...(Args);
 
   // Format specifier parsing function.
+  // In the future basic_format_parse_context will replace compile_parse_context
+  // here and will use is_constant_evaluated and downcasting to access the data
+  // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1.
   using parse_func = const Char* (*)(parse_context_type&);
 
+  type types_[num_args > 0 ? static_cast<size_t>(num_args) : 1];
   parse_context_type context_;
   parse_func parse_funcs_[num_args > 0 ? static_cast<size_t>(num_args) : 1];
-  type types_[num_args > 0 ? static_cast<size_t>(num_args) : 1];
 
  public:
-  explicit FMT_CONSTEXPR format_string_checker(
-      basic_string_view<Char> format_str, ErrorHandler eh)
-      : context_(format_str, num_args, types_, eh),
-        parse_funcs_{&parse_format_specs<Args, parse_context_type>...},
-        types_{  // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
-            mapped_type_constant<Args,
-                                 basic_format_context<Char*, Char>>::value...} {
-  }
+  explicit FMT_CONSTEXPR format_string_checker(basic_string_view<Char> fmt)
+      : types_{mapped_type_constant<Args, buffer_context<Char>>::value...},
+        context_(fmt, num_args, types_),
+        parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
 
   FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
 
@@ -2966,8 +2619,8 @@
   FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
     auto index = get_arg_index_by_name<Args...>(id);
-    if (index == invalid_arg_index) on_error("named argument is not found");
-    return context_.check_arg_id(index), index;
+    if (index < 0) on_error("named argument is not found");
+    return index;
 #else
     (void)id;
     on_error("compile-time checks for named arguments require C++20 support");
@@ -2975,17 +2628,19 @@
 #endif
   }
 
-  FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
+  FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) {
+    on_format_specs(id, begin, begin);  // Call parse() on empty specs.
+  }
 
   FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*)
       -> const Char* {
-    context_.advance_to(context_.begin() + (begin - &*context_.begin()));
+    context_.advance_to(begin);
     // id >= 0 check is a workaround for gcc 10 bug (#2065).
     return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
   }
 
   FMT_CONSTEXPR void on_error(const char* message) {
-    context_.on_error(message);
+    throw_format_error(message);
   }
 };
 
@@ -3001,28 +2656,33 @@
 template <typename... Args, typename S,
           FMT_ENABLE_IF(is_compile_string<S>::value)>
 void check_format_string(S format_str) {
-  FMT_CONSTEXPR auto s = basic_string_view<typename S::char_type>(format_str);
-  using checker = format_string_checker<typename S::char_type, error_handler,
-                                        remove_cvref_t<Args>...>;
-  FMT_CONSTEXPR bool invalid_format =
-      (parse_format_string<true>(s, checker(s, {})), true);
-  ignore_unused(invalid_format);
+  using char_t = typename S::char_type;
+  FMT_CONSTEXPR auto s = basic_string_view<char_t>(format_str);
+  using checker = format_string_checker<char_t, remove_cvref_t<Args>...>;
+  FMT_CONSTEXPR bool error = (parse_format_string<true>(s, checker(s)), true);
+  ignore_unused(error);
 }
 
+template <typename Char = char> struct vformat_args {
+  using type = basic_format_args<
+      basic_format_context<std::back_insert_iterator<buffer<Char>>, Char>>;
+};
+template <> struct vformat_args<char> { using type = format_args; };
+
+// Use vformat_args and avoid type_identity to keep symbols short.
 template <typename Char>
-void vformat_to(
-    buffer<Char>& buf, basic_string_view<Char> fmt,
-    basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
-    locale_ref loc = {});
+void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
+                typename vformat_args<Char>::type args, locale_ref loc = {});
 
 FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
 #ifndef _WIN32
 inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
 #endif
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
-// A formatter specialization for the core types corresponding to detail::type
-// constants.
+FMT_BEGIN_EXPORT
+
+// A formatter specialization for natively supported types.
 template <typename T, typename Char>
 struct formatter<T, Char,
                  enable_if_t<detail::type_constant<T, Char>::value !=
@@ -3031,81 +2691,21 @@
   detail::dynamic_format_specs<Char> specs_;
 
  public:
-  // Parses format specifiers stopping either at the end of the range or at the
-  // terminating '}'.
   template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    auto begin = ctx.begin(), end = ctx.end();
-    if (begin == end) return begin;
-    using handler_type = detail::dynamic_specs_handler<ParseContext>;
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
     auto type = detail::type_constant<T, Char>::value;
-    auto checker =
-        detail::specs_checker<handler_type>(handler_type(specs_, ctx), type);
-    auto it = detail::parse_format_specs(begin, end, checker);
-    auto eh = ctx.error_handler();
-    switch (type) {
-    case detail::type::none_type:
-      FMT_ASSERT(false, "invalid argument type");
-      break;
-    case detail::type::bool_type:
-      if (specs_.type == presentation_type::none ||
-          specs_.type == presentation_type::string) {
-        break;
-      }
-      FMT_FALLTHROUGH;
-    case detail::type::int_type:
-    case detail::type::uint_type:
-    case detail::type::long_long_type:
-    case detail::type::ulong_long_type:
-    case detail::type::int128_type:
-    case detail::type::uint128_type:
-      detail::check_int_type_spec(specs_.type, eh);
-      break;
-    case detail::type::char_type:
-      detail::check_char_specs(specs_, eh);
-      break;
-    case detail::type::float_type:
-      if (detail::const_check(FMT_USE_FLOAT))
-        detail::parse_float_type_spec(specs_, eh);
-      else
-        FMT_ASSERT(false, "float support disabled");
-      break;
-    case detail::type::double_type:
-      if (detail::const_check(FMT_USE_DOUBLE))
-        detail::parse_float_type_spec(specs_, eh);
-      else
-        FMT_ASSERT(false, "double support disabled");
-      break;
-    case detail::type::long_double_type:
-      if (detail::const_check(FMT_USE_LONG_DOUBLE))
-        detail::parse_float_type_spec(specs_, eh);
-      else
-        FMT_ASSERT(false, "long double support disabled");
-      break;
-    case detail::type::cstring_type:
-      detail::check_cstring_type_spec(specs_.type, eh);
-      break;
-    case detail::type::string_type:
-      detail::check_string_type_spec(specs_.type, eh);
-      break;
-    case detail::type::pointer_type:
-      detail::check_pointer_type_spec(specs_.type, eh);
-      break;
-    case detail::type::custom_type:
-      // Custom format specifiers are checked in parse functions of
-      // formatter specializations.
-      break;
-    }
-    return it;
+    auto end =
+        detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, type);
+    if (type == detail::type::char_type) detail::check_char_specs(specs_);
+    return end;
   }
 
   template <detail::type U = detail::type_constant<T, Char>::value,
-            enable_if_t<(U == detail::type::string_type ||
-                         U == detail::type::cstring_type ||
-                         U == detail::type::char_type),
-                        int> = 0>
-  FMT_CONSTEXPR void set_debug_format() {
-    specs_.type = presentation_type::debug;
+            FMT_ENABLE_IF(U == detail::type::string_type ||
+                          U == detail::type::cstring_type ||
+                          U == detail::type::char_type)>
+  FMT_CONSTEXPR void set_debug_format(bool set = true) {
+    specs_.type = set ? presentation_type::debug : presentation_type::none;
   }
 
   template <typename FormatContext>
@@ -3113,28 +2713,9 @@
       -> decltype(ctx.out());
 };
 
-#define FMT_FORMAT_AS(Type, Base)                                        \
-  template <typename Char>                                               \
-  struct formatter<Type, Char> : formatter<Base, Char> {                 \
-    template <typename FormatContext>                                    \
-    auto format(Type const& val, FormatContext& ctx) const               \
-        -> decltype(ctx.out()) {                                         \
-      return formatter<Base, Char>::format(static_cast<Base>(val), ctx); \
-    }                                                                    \
-  }
-
-FMT_FORMAT_AS(signed char, int);
-FMT_FORMAT_AS(unsigned char, unsigned);
-FMT_FORMAT_AS(short, int);
-FMT_FORMAT_AS(unsigned short, unsigned);
-FMT_FORMAT_AS(long, long long);
-FMT_FORMAT_AS(unsigned long, unsigned long long);
-FMT_FORMAT_AS(Char*, const Char*);
-FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
-FMT_FORMAT_AS(std::nullptr_t, const void*);
-FMT_FORMAT_AS(detail::std_string_view<Char>, basic_string_view<Char>);
-
-template <typename Char> struct basic_runtime { basic_string_view<Char> str; };
+template <typename Char = char> struct runtime_format_string {
+  basic_string_view<Char> str;
+};
 
 /** A compile-time format string. */
 template <typename Char, typename... Args> class basic_format_string {
@@ -3154,17 +2735,18 @@
 #ifdef FMT_HAS_CONSTEVAL
     if constexpr (detail::count_named_args<Args...>() ==
                   detail::count_statically_named_args<Args...>()) {
-      using checker = detail::format_string_checker<Char, detail::error_handler,
-                                                    remove_cvref_t<Args>...>;
-      detail::parse_format_string<true>(str_, checker(s, {}));
+      using checker =
+          detail::format_string_checker<Char, remove_cvref_t<Args>...>;
+      detail::parse_format_string<true>(str_, checker(s));
     }
 #else
     detail::check_format_string<Args...>(s);
 #endif
   }
-  basic_format_string(basic_runtime<Char> r) : str_(r.str) {}
+  basic_format_string(runtime_format_string<Char> fmt) : str_(fmt.str) {}
 
   FMT_INLINE operator basic_string_view<Char>() const { return str_; }
+  FMT_INLINE auto get() const -> basic_string_view<Char> { return str_; }
 };
 
 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
@@ -3184,7 +2766,7 @@
     fmt::print(fmt::runtime("{:d}"), "I am not a number");
   \endrst
  */
-inline auto runtime(string_view s) -> basic_runtime<char> { return {{s}}; }
+inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; }
 #endif
 
 FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
@@ -3210,10 +2792,9 @@
 template <typename OutputIt,
           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
 auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt {
-  using detail::get_buffer;
-  auto&& buf = get_buffer<char>(out);
+  auto&& buf = detail::get_buffer<char>(out);
   detail::vformat_to(buf, fmt, args, {});
-  return detail::get_iterator(buf);
+  return detail::get_iterator(buf, out);
 }
 
 /**
@@ -3272,7 +2853,7 @@
 FMT_NODISCARD FMT_INLINE auto formatted_size(format_string<T...> fmt,
                                              T&&... args) -> size_t {
   auto buf = detail::counting_buffer<>();
-  detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {});
+  detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...), {});
   return buf.count();
 }
 
@@ -3313,7 +2894,25 @@
                            : detail::vprint_mojibake(f, fmt, vargs);
 }
 
-FMT_MODULE_EXPORT_END
+/**
+  Formats ``args`` according to specifications in ``fmt`` and writes the
+  output to the file ``f`` followed by a newline.
+ */
+template <typename... T>
+FMT_INLINE void println(std::FILE* f, format_string<T...> fmt, T&&... args) {
+  return fmt::print(f, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
+}
+
+/**
+  Formats ``args`` according to specifications in ``fmt`` and writes the output
+  to ``stdout`` followed by a newline.
+ */
+template <typename... T>
+FMT_INLINE void println(format_string<T...> fmt, T&&... args) {
+  return fmt::println(stdout, fmt, std::forward<T>(args)...);
+}
+
+FMT_END_EXPORT
 FMT_GCC_PRAGMA("GCC pop_options")
 FMT_END_NAMESPACE
 
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h
index abe4ff1..af6ba74 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h
@@ -9,13 +9,9 @@
 #define FMT_FORMAT_INL_H_
 
 #include <algorithm>
-#include <cctype>
 #include <cerrno>  // errno
 #include <climits>
 #include <cmath>
-#include <cstdarg>
-#include <cstring>  // std::memmove
-#include <cwchar>
 #include <exception>
 
 #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
@@ -113,16 +109,43 @@
   return '.';
 }
 #endif
+
+FMT_FUNC auto write_loc(appender out, loc_value value,
+                        const format_specs<>& specs, locale_ref loc) -> bool {
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+  auto locale = loc.get<std::locale>();
+  // We cannot use the num_put<char> facet because it may produce output in
+  // a wrong encoding.
+  using facet = format_facet<std::locale>;
+  if (std::has_facet<facet>(locale))
+    return std::use_facet<facet>(locale).put(out, value, specs);
+  return facet(locale).put(out, value, specs);
+#endif
+  return false;
+}
 }  // namespace detail
 
-#if !FMT_MSC_VERSION
-FMT_API FMT_FUNC format_error::~format_error() noexcept = default;
+template <typename Locale> typename Locale::id format_facet<Locale>::id;
+
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+template <typename Locale> format_facet<Locale>::format_facet(Locale& loc) {
+  auto& numpunct = std::use_facet<std::numpunct<char>>(loc);
+  grouping_ = numpunct.grouping();
+  if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep());
+}
+
+template <>
+FMT_API FMT_FUNC auto format_facet<std::locale>::do_put(
+    appender out, loc_value val, const format_specs<>& specs) const -> bool {
+  return val.visit(
+      detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_});
+}
 #endif
 
-FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str,
+FMT_FUNC std::system_error vsystem_error(int error_code, string_view fmt,
                                          format_args args) {
   auto ec = std::error_code(error_code, std::generic_category());
-  return std::system_error(ec, vformat(format_str, args));
+  return std::system_error(ec, vformat(fmt, args));
 }
 
 namespace detail {
@@ -141,58 +164,8 @@
   return (n >> r) | (n << (64 - r));
 }
 
-// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
-inline uint128_fallback umul128(uint64_t x, uint64_t y) noexcept {
-#if FMT_USE_INT128
-  auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
-  return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)};
-#elif defined(_MSC_VER) && defined(_M_X64)
-  auto result = uint128_fallback();
-  result.lo_ = _umul128(x, y, &result.hi_);
-  return result;
-#else
-  const uint64_t mask = static_cast<uint64_t>(max_value<uint32_t>());
-
-  uint64_t a = x >> 32;
-  uint64_t b = x & mask;
-  uint64_t c = y >> 32;
-  uint64_t d = y & mask;
-
-  uint64_t ac = a * c;
-  uint64_t bc = b * c;
-  uint64_t ad = a * d;
-  uint64_t bd = b * d;
-
-  uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
-
-  return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
-          (intermediate << 32) + (bd & mask)};
-#endif
-}
-
 // Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
 namespace dragonbox {
-// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
-inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept {
-#if FMT_USE_INT128
-  auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
-  return static_cast<uint64_t>(p >> 64);
-#elif defined(_MSC_VER) && defined(_M_X64)
-  return __umulh(x, y);
-#else
-  return umul128(x, y).high();
-#endif
-}
-
-// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a
-// 128-bit unsigned integer.
-inline uint128_fallback umul192_upper128(uint64_t x,
-                                         uint128_fallback y) noexcept {
-  uint128_fallback r = umul128(x, y.high());
-  r += umul128_upper64(x, y.low());
-  return r;
-}
-
 // Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a
 // 64-bit unsigned integer.
 inline uint64_t umul96_upper64(uint32_t x, uint64_t y) noexcept {
@@ -214,25 +187,13 @@
   return x * y;
 }
 
-// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from
-// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1.
-inline int floor_log10_pow2(int e) noexcept {
-  FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent");
-  static_assert((-1 >> 1) == -1, "right shift is not arithmetic");
-  return (e * 315653) >> 20;
-}
-
 // Various fast log computations.
-inline int floor_log2_pow10(int e) noexcept {
-  FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent");
-  return (e * 1741647) >> 19;
-}
 inline int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept {
   FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent");
   return (e * 631305 - 261663) >> 21;
 }
 
-static constexpr struct {
+FMT_INLINE_VARIABLE constexpr struct {
   uint32_t divisor;
   int shift_amount;
 } div_small_pow10_infos[] = {{10, 16}, {100, 16}};
@@ -286,7 +247,7 @@
 }
 
 // Various subroutines using pow10 cache
-template <class T> struct cache_accessor;
+template <typename T> struct cache_accessor;
 
 template <> struct cache_accessor<float> {
   using carrier_uint = float_info<float>::carrier_uint;
@@ -1007,8 +968,23 @@
       {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6},
       {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2},
       {0xc5a05277621be293, 0xc7098b7305241886},
-      { 0xf70867153aa2db38,
-        0xb8cbee4fc66d1ea8 }
+      {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8},
+      {0x9a65406d44a5c903, 0x737f74f1dc043329},
+      {0xc0fe908895cf3b44, 0x505f522e53053ff3},
+      {0xf13e34aabb430a15, 0x647726b9e7c68ff0},
+      {0x96c6e0eab509e64d, 0x5eca783430dc19f6},
+      {0xbc789925624c5fe0, 0xb67d16413d132073},
+      {0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890},
+      {0x933e37a534cbaae7, 0x8e91b962f7b6f15a},
+      {0xb80dc58e81fe95a1, 0x723627bbb5a4adb1},
+      {0xe61136f2227e3b09, 0xcec3b1aaa30dd91d},
+      {0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2},
+      {0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e},
+      {0xe0accfa875af45a7, 0x93eb1b80a33b8606},
+      {0x8c6c01c9498d8b88, 0xbc72f130660533c4},
+      {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5},
+      { 0xdb68c2ca82ed2a05,
+        0xa67398db9f6820e2 }
 #else
       {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
       {0xce5d73ff402d98e3, 0xfb0a3d212dc81290},
@@ -1032,8 +1008,8 @@
       {0x8da471a9de737e24, 0x5ceaecfed289e5d3},
       {0xe4d5e82392a40515, 0x0fabaf3feaa5334b},
       {0xb8da1662e7b00a17, 0x3d6a751f3b936244},
-      { 0x95527a5202df0ccb,
-        0x0f37801e0c43ebc9 }
+      {0x95527a5202df0ccb, 0x0f37801e0c43ebc9},
+      {0xf13e34aabb430a15, 0x647726b9e7c68ff0}
 #endif
     };
 
@@ -1136,8 +1112,12 @@
   }
 };
 
+FMT_FUNC uint128_fallback get_cached_power(int k) noexcept {
+  return cache_accessor<double>::get_cached_power(k);
+}
+
 // Various integer checks
-template <class T>
+template <typename T>
 bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept {
   const int case_shorter_interval_left_endpoint_lower_threshold = 2;
   const int case_shorter_interval_left_endpoint_upper_threshold = 3;
@@ -1146,12 +1126,12 @@
 }
 
 // Remove trailing zeros from n and return the number of zeros removed (float)
-FMT_INLINE int remove_trailing_zeros(uint32_t& n) noexcept {
+FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept {
   FMT_ASSERT(n != 0, "");
-  const uint32_t mod_inv_5 = 0xcccccccd;
-  const uint32_t mod_inv_25 = mod_inv_5 * mod_inv_5;
+  // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1.
+  constexpr uint32_t mod_inv_5 = 0xcccccccd;
+  constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5
 
-  int s = 0;
   while (true) {
     auto q = rotr(n * mod_inv_25, 2);
     if (q > max_value<uint32_t>() / 100) break;
@@ -1163,7 +1143,6 @@
     n = q;
     s |= 1;
   }
-
   return s;
 }
 
@@ -1177,32 +1156,17 @@
 
   // Is n is divisible by 10^8?
   if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) {
-    // If yes, work with the quotient.
+    // If yes, work with the quotient...
     auto n32 = static_cast<uint32_t>(nm.high() >> (90 - 64));
-
-    const uint32_t mod_inv_5 = 0xcccccccd;
-    const uint32_t mod_inv_25 = mod_inv_5 * mod_inv_5;
-
-    int s = 8;
-    while (true) {
-      auto q = rotr(n32 * mod_inv_25, 2);
-      if (q > max_value<uint32_t>() / 100) break;
-      n32 = q;
-      s += 2;
-    }
-    auto q = rotr(n32 * mod_inv_5, 1);
-    if (q <= max_value<uint32_t>() / 10) {
-      n32 = q;
-      s |= 1;
-    }
-
+    // ... and use the 32 bit variant of the function
+    int s = remove_trailing_zeros(n32, 8);
     n = n32;
     return s;
   }
 
   // If n is not divisible by 10^8, work with n itself.
-  const uint64_t mod_inv_5 = 0xcccccccccccccccd;
-  const uint64_t mod_inv_25 = mod_inv_5 * mod_inv_5;
+  constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd;
+  constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // = mod_inv_5 * mod_inv_5
 
   int s = 0;
   while (true) {
@@ -1221,7 +1185,7 @@
 }
 
 // The main algorithm for shorter interval case
-template <class T>
+template <typename T>
 FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) noexcept {
   decimal_fp<T> ret_value;
   // Compute k and beta
@@ -1392,17 +1356,6 @@
   return ret_value;
 }
 }  // namespace dragonbox
-
-#ifdef _MSC_VER
-FMT_FUNC auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...)
-    -> int {
-  auto args = va_list();
-  va_start(args, fmt);
-  int result = vsnprintf_s(buf, size, _TRUNCATE, fmt, args);
-  va_end(args);
-  return result;
-}
-#endif
 }  // namespace detail
 
 template <> struct formatter<detail::bigint> {
@@ -1411,9 +1364,8 @@
     return ctx.begin();
   }
 
-  template <typename FormatContext>
-  auto format(const detail::bigint& n, FormatContext& ctx) const ->
-      typename FormatContext::iterator {
+  auto format(const detail::bigint& n, format_context& ctx) const
+      -> format_context::iterator {
     auto out = ctx.out();
     bool first = true;
     for (auto i = n.bigits_.size(); i > 0; --i) {
@@ -1472,57 +1424,44 @@
 }
 
 namespace detail {
-#ifdef _WIN32
+#ifndef _WIN32
+FMT_FUNC bool write_console(std::FILE*, string_view) { return false; }
+#else
 using dword = conditional_t<sizeof(long) == 4, unsigned long, unsigned>;
 extern "C" __declspec(dllimport) int __stdcall WriteConsoleW(  //
     void*, const void*, dword, dword*, void*);
 
 FMT_FUNC bool write_console(std::FILE* f, string_view text) {
   auto fd = _fileno(f);
-  if (_isatty(fd)) {
-    detail::utf8_to_utf16 u16(string_view(text.data(), text.size()));
-    auto written = detail::dword();
-    if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
-                              u16.c_str(), static_cast<uint32_t>(u16.size()),
-                              &written, nullptr)) {
-      return true;
-    }
-  }
-  // We return false if the file descriptor was not TTY, or it was but
-  // SetConsoleW failed which can happen if the output has been redirected to
-  // NUL. In both cases when we return false, we should attempt to do regular
-  // write via fwrite or std::ostream::write.
-  return false;
-}
-#endif
-
-FMT_FUNC void print(std::FILE* f, string_view text) {
-#ifdef _WIN32
-  if (write_console(f, text)) return;
-#endif
-  detail::fwrite_fully(text.data(), 1, text.size(), f);
-}
-}  // namespace detail
-
-FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
-  memory_buffer buffer;
-  detail::vformat_to(buffer, format_str, args);
-  detail::print(f, {buffer.data(), buffer.size()});
+  if (!_isatty(fd)) return false;
+  auto u16 = utf8_to_utf16(text);
+  auto written = dword();
+  return WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)), u16.c_str(),
+                       static_cast<uint32_t>(u16.size()), &written, nullptr) != 0;
 }
 
-#ifdef _WIN32
 // Print assuming legacy (non-Unicode) encoding.
-FMT_FUNC void detail::vprint_mojibake(std::FILE* f, string_view format_str,
-                                      format_args args) {
-  memory_buffer buffer;
-  detail::vformat_to(buffer, format_str,
+FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args) {
+  auto buffer = memory_buffer();
+  detail::vformat_to(buffer, fmt,
                      basic_format_args<buffer_context<char>>(args));
   fwrite_fully(buffer.data(), 1, buffer.size(), f);
 }
 #endif
 
-FMT_FUNC void vprint(string_view format_str, format_args args) {
-  vprint(stdout, format_str, args);
+FMT_FUNC void print(std::FILE* f, string_view text) {
+  if (!write_console(f, text)) fwrite_fully(text.data(), 1, text.size(), f);
+}
+}  // namespace detail
+
+FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) {
+  auto buffer = memory_buffer();
+  detail::vformat_to(buffer, fmt, args);
+  detail::print(f, {buffer.data(), buffer.size()});
+}
+
+FMT_FUNC void vprint(string_view fmt, format_args args) {
+  vprint(stdout, fmt, args);
 }
 
 namespace detail {
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
index 7c607db..ac0f52d 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
@@ -33,13 +33,14 @@
 #ifndef FMT_FORMAT_H_
 #define FMT_FORMAT_H_
 
-#include <cmath>         // std::signbit
-#include <cstdint>       // uint32_t
-#include <cstring>       // std::memcpy
-#include <limits>        // std::numeric_limits
-#include <memory>        // std::uninitialized_copy
-#include <stdexcept>     // std::runtime_error
-#include <system_error>  // std::system_error
+#include <cmath>             // std::signbit
+#include <cstdint>           // uint32_t
+#include <cstring>           // std::memcpy
+#include <initializer_list>  // std::initializer_list
+#include <limits>            // std::numeric_limits
+#include <memory>            // std::uninitialized_copy
+#include <stdexcept>         // std::runtime_error
+#include <system_error>      // std::system_error
 
 #ifdef __cpp_lib_bit_cast
 #  include <bit>  // std::bitcast
@@ -47,16 +48,55 @@
 
 #include "core.h"
 
-#if FMT_GCC_VERSION
-#  define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))
+#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L
+#  define FMT_INLINE_VARIABLE inline
 #else
-#  define FMT_GCC_VISIBILITY_HIDDEN
+#  define FMT_INLINE_VARIABLE
 #endif
 
-#ifdef __NVCC__
-#  define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)
+#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
+#  define FMT_FALLTHROUGH [[fallthrough]]
+#elif defined(__clang__)
+#  define FMT_FALLTHROUGH [[clang::fallthrough]]
+#elif FMT_GCC_VERSION >= 700 && \
+    (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
+#  define FMT_FALLTHROUGH [[gnu::fallthrough]]
 #else
-#  define FMT_CUDA_VERSION 0
+#  define FMT_FALLTHROUGH
+#endif
+
+#ifndef FMT_DEPRECATED
+#  if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900
+#    define FMT_DEPRECATED [[deprecated]]
+#  else
+#    if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
+#      define FMT_DEPRECATED __attribute__((deprecated))
+#    elif FMT_MSC_VERSION
+#      define FMT_DEPRECATED __declspec(deprecated)
+#    else
+#      define FMT_DEPRECATED /* deprecated */
+#    endif
+#  endif
+#endif
+
+#ifndef FMT_NO_UNIQUE_ADDRESS
+#  if FMT_CPLUSPLUS >= 202002L
+#    if FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
+#      define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
+// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485)
+#    elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION
+#      define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
+#    endif
+#  endif
+#endif
+#ifndef FMT_NO_UNIQUE_ADDRESS
+#  define FMT_NO_UNIQUE_ADDRESS
+#endif
+
+#if FMT_GCC_VERSION || defined(__clang__)
+#  define FMT_VISIBILITY(value) __attribute__((visibility(value)))
+#else
+#  define FMT_VISIBILITY(value)
 #endif
 
 #ifdef __has_builtin
@@ -71,12 +111,6 @@
 #  define FMT_NOINLINE
 #endif
 
-#if FMT_MSC_VERSION
-#  define FMT_MSC_DEFAULT = default
-#else
-#  define FMT_MSC_DEFAULT
-#endif
-
 #ifndef FMT_THROW
 #  if FMT_EXCEPTIONS
 #    if FMT_MSC_VERSION || defined(__NVCC__)
@@ -95,10 +129,8 @@
 #      define FMT_THROW(x) throw x
 #    endif
 #  else
-#    define FMT_THROW(x)               \
-      do {                             \
-        FMT_ASSERT(false, (x).what()); \
-      } while (false)
+#    define FMT_THROW(x) \
+      ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what())
 #  endif
 #endif
 
@@ -200,7 +232,8 @@
   _BitScanReverse64(&r, x);
 #  else
   // Scan the high 32 bits.
-  if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) return 63 ^ (r + 32);
+  if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
+    return 63 ^ static_cast<int>(r + 32);
   // Scan the low 32 bits.
   _BitScanReverse(&r, static_cast<uint32_t>(x));
 #  endif
@@ -240,6 +273,19 @@
 #endif
 
 FMT_BEGIN_NAMESPACE
+
+template <typename...> struct disjunction : std::false_type {};
+template <typename P> struct disjunction<P> : P {};
+template <typename P1, typename... Pn>
+struct disjunction<P1, Pn...>
+    : conditional_t<bool(P1::value), P1, disjunction<Pn...>> {};
+
+template <typename...> struct conjunction : std::true_type {};
+template <typename P> struct conjunction<P> : P {};
+template <typename P1, typename... Pn>
+struct conjunction<P1, Pn...>
+    : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
+
 namespace detail {
 
 FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) {
@@ -323,8 +369,6 @@
  private:
   uint64_t lo_, hi_;
 
-  friend uint128_fallback umul128(uint64_t x, uint64_t y) noexcept;
-
  public:
   constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {}
   constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {}
@@ -359,6 +403,10 @@
       -> uint128_fallback {
     return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
   }
+  friend constexpr auto operator~(const uint128_fallback& n)
+      -> uint128_fallback {
+    return {~n.hi_, ~n.lo_};
+  }
   friend auto operator+(const uint128_fallback& lhs,
                         const uint128_fallback& rhs) -> uint128_fallback {
     auto result = uint128_fallback(lhs);
@@ -397,6 +445,10 @@
     lo_ = new_lo;
     hi_ = new_hi;
   }
+  FMT_CONSTEXPR void operator&=(uint128_fallback n) {
+    lo_ &= n.lo_;
+    hi_ &= n.hi_;
+  }
 
   FMT_CONSTEXPR20 uint128_fallback& operator+=(uint64_t n) noexcept {
     if (is_constant_evaluated()) {
@@ -463,10 +515,34 @@
   return result;
 }
 
+template <typename UInt>
+FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int {
+  int lz = 0;
+  constexpr UInt msb_mask = static_cast<UInt>(1) << (num_bits<UInt>() - 1);
+  for (; (n & msb_mask) == 0; n <<= 1) lz++;
+  return lz;
+}
+
+FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int {
+#ifdef FMT_BUILTIN_CLZ
+  if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n);
+#endif
+  return countl_zero_fallback(n);
+}
+
+FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int {
+#ifdef FMT_BUILTIN_CLZLL
+  if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n);
+#endif
+  return countl_zero_fallback(n);
+}
+
 FMT_INLINE void assume(bool condition) {
   (void)condition;
 #if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION
   __builtin_assume(condition);
+#elif FMT_GCC_VERSION
+  if (!condition) __builtin_unreachable();
 #endif
 }
 
@@ -485,20 +561,6 @@
   return c.data();
 }
 
-#if defined(_SECURE_SCL) && _SECURE_SCL
-// Make a checked iterator to avoid MSVC warnings.
-template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
-template <typename T>
-constexpr auto make_checked(T* p, size_t size) -> checked_ptr<T> {
-  return {p, size};
-}
-#else
-template <typename T> using checked_ptr = T*;
-template <typename T> constexpr auto make_checked(T* p, size_t) -> T* {
-  return p;
-}
-#endif
-
 // Attempts to reserve space for n extra characters in the output range.
 // Returns a pointer to the reserved range or a reference to it.
 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
@@ -506,12 +568,12 @@
 __attribute__((no_sanitize("undefined")))
 #endif
 inline auto
-reserve(std::back_insert_iterator<Container> it, size_t n)
-    -> checked_ptr<typename Container::value_type> {
+reserve(std::back_insert_iterator<Container> it, size_t n) ->
+    typename Container::value_type* {
   Container& c = get_container(it);
   size_t size = c.size();
   c.resize(size + n);
-  return make_checked(get_data(c) + size, n);
+  return get_data(c) + size;
 }
 
 template <typename T>
@@ -543,8 +605,8 @@
 }
 
 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
-inline auto base_iterator(std::back_insert_iterator<Container>& it,
-                          checked_ptr<typename Container::value_type>)
+inline auto base_iterator(std::back_insert_iterator<Container> it,
+                          typename Container::value_type*)
     -> std::back_insert_iterator<Container> {
   return it;
 }
@@ -607,7 +669,8 @@
   constexpr const int shiftc[] = {0, 18, 12, 6, 0};
   constexpr const int shifte[] = {0, 6, 4, 2, 0};
 
-  int len = code_point_length_impl(*s);
+  int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
+      [static_cast<unsigned char>(*s) >> 3];
   // Compute the pointer to the next character early so that the next
   // iteration can start working on the next character. Neither Clang
   // nor GCC figure out this reordering on their own.
@@ -636,7 +699,7 @@
   return next;
 }
 
-constexpr uint32_t invalid_code_point = ~uint32_t();
+constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
 
 // Invokes f(cp, sv) for every code point cp in s with sv being the string view
 // corresponding to the code point. cp is invalid_code_point on error.
@@ -706,6 +769,7 @@
       return true;
     }
   };
+  // We could avoid branches by using utf8_decode directly.
   for_each_codepoint(s, count_code_points{&num_code_points});
   return num_code_points;
 }
@@ -737,13 +801,48 @@
       string_view(reinterpret_cast<const char*>(s.data()), s.size()), n);
 }
 
+template <typename T> struct is_integral : std::is_integral<T> {};
+template <> struct is_integral<int128_opt> : std::true_type {};
+template <> struct is_integral<uint128_t> : std::true_type {};
+
+template <typename T>
+using is_signed =
+    std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
+                                     std::is_same<T, int128_opt>::value>;
+
+template <typename T>
+using is_integer =
+    bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
+                  !std::is_same<T, char>::value &&
+                  !std::is_same<T, wchar_t>::value>;
+
+#ifndef FMT_USE_FLOAT
+#  define FMT_USE_FLOAT 1
+#endif
+#ifndef FMT_USE_DOUBLE
+#  define FMT_USE_DOUBLE 1
+#endif
+#ifndef FMT_USE_LONG_DOUBLE
+#  define FMT_USE_LONG_DOUBLE 1
+#endif
+
 #ifndef FMT_USE_FLOAT128
-#  ifdef __SIZEOF_FLOAT128__
-#    define FMT_USE_FLOAT128 1
-#  else
+#  ifdef __clang__
+// Clang emulates GCC, so it has to appear early.
+#    if FMT_HAS_INCLUDE(<quadmath.h>)
+#      define FMT_USE_FLOAT128 1
+#    endif
+#  elif defined(__GNUC__)
+// GNU C++:
+#    if defined(_GLIBCXX_USE_FLOAT128) && !defined(__STRICT_ANSI__)
+#      define FMT_USE_FLOAT128 1
+#    endif
+#  endif
+#  ifndef FMT_USE_FLOAT128
 #    define FMT_USE_FLOAT128 0
 #  endif
 #endif
+
 #if FMT_USE_FLOAT128
 using float128 = __float128;
 #else
@@ -775,7 +874,7 @@
     try_reserve(size_ + count);
     auto free_cap = capacity_ - size_;
     if (free_cap < count) count = free_cap;
-    std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count));
+    std::uninitialized_copy_n(begin, count, ptr_ + size_);
     size_ += count;
     begin += count;
   }
@@ -787,7 +886,7 @@
 struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
 }  // namespace detail
 
-FMT_MODULE_EXPORT_BEGIN
+FMT_BEGIN_EXPORT
 
 // The number of characters to store in the basic_memory_buffer object itself
 // to avoid dynamic memory allocation.
@@ -820,8 +919,8 @@
  private:
   T store_[SIZE];
 
-  // Don't inherit from Allocator avoid generating type_info for it.
-  Allocator alloc_;
+  // Don't inherit from Allocator to avoid generating type_info for it.
+  FMT_NO_UNIQUE_ADDRESS Allocator alloc_;
 
   // Deallocate memory allocated by the buffer.
   FMT_CONSTEXPR20 void deallocate() {
@@ -830,7 +929,28 @@
   }
 
  protected:
-  FMT_CONSTEXPR20 void grow(size_t size) override;
+  FMT_CONSTEXPR20 void grow(size_t size) override {
+    detail::abort_fuzzing_if(size > 5000);
+    const size_t max_size = std::allocator_traits<Allocator>::max_size(alloc_);
+    size_t old_capacity = this->capacity();
+    size_t new_capacity = old_capacity + old_capacity / 2;
+    if (size > new_capacity)
+      new_capacity = size;
+    else if (new_capacity > max_size)
+      new_capacity = size > max_size ? size : max_size;
+    T* old_data = this->data();
+    T* new_data =
+        std::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
+    // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481).
+    detail::assume(this->size() <= new_capacity);
+    // The following code doesn't throw, so the raw pointer above doesn't leak.
+    std::uninitialized_copy_n(old_data, this->size(), new_data);
+    this->set(new_data, new_capacity);
+    // deallocate must not throw according to the standard, but even if it does,
+    // the buffer already uses the new storage and will deallocate it in
+    // destructor.
+    if (old_data != store_) alloc_.deallocate(old_data, old_capacity);
+  }
 
  public:
   using value_type = T;
@@ -852,8 +972,7 @@
     size_t size = other.size(), capacity = other.capacity();
     if (data == other.store_) {
       this->set(store_, capacity);
-      detail::copy_str<T>(other.store_, other.store_ + size,
-                          detail::make_checked(store_, capacity));
+      detail::copy_str<T>(other.store_, other.store_ + size, store_);
     } else {
       this->set(data, capacity);
       // Set pointer to the inline array so that delete is not called
@@ -907,55 +1026,29 @@
   }
 };
 
-template <typename T, size_t SIZE, typename Allocator>
-FMT_CONSTEXPR20 void basic_memory_buffer<T, SIZE, Allocator>::grow(
-    size_t size) {
-  detail::abort_fuzzing_if(size > 5000);
-  const size_t max_size = std::allocator_traits<Allocator>::max_size(alloc_);
-  size_t old_capacity = this->capacity();
-  size_t new_capacity = old_capacity + old_capacity / 2;
-  if (size > new_capacity)
-    new_capacity = size;
-  else if (new_capacity > max_size)
-    new_capacity = size > max_size ? size : max_size;
-  T* old_data = this->data();
-  T* new_data =
-      std::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
-  // The following code doesn't throw, so the raw pointer above doesn't leak.
-  std::uninitialized_copy(old_data, old_data + this->size(),
-                          detail::make_checked(new_data, new_capacity));
-  this->set(new_data, new_capacity);
-  // deallocate must not throw according to the standard, but even if it does,
-  // the buffer already uses the new storage and will deallocate it in
-  // destructor.
-  if (old_data != store_) alloc_.deallocate(old_data, old_capacity);
-}
-
 using memory_buffer = basic_memory_buffer<char>;
 
 template <typename T, size_t SIZE, typename Allocator>
 struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
 };
 
+FMT_END_EXPORT
 namespace detail {
-#ifdef _WIN32
 FMT_API bool write_console(std::FILE* f, string_view text);
-#endif
 FMT_API void print(std::FILE*, string_view);
 }  // namespace detail
 
-/** A formatting error such as invalid format string. */
-FMT_CLASS_API
-class FMT_API format_error : public std::runtime_error {
+FMT_BEGIN_EXPORT
+
+// Suppress a misleading warning in older versions of clang.
+#if FMT_CLANG_VERSION
+#  pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+/** An error reported from a formatting function. */
+class FMT_VISIBILITY("default") format_error : public std::runtime_error {
  public:
-  explicit format_error(const char* message) : std::runtime_error(message) {}
-  explicit format_error(const std::string& message)
-      : std::runtime_error(message) {}
-  format_error(const format_error&) = default;
-  format_error& operator=(const format_error&) = default;
-  format_error(format_error&&) = default;
-  format_error& operator=(format_error&&) = default;
-  ~format_error() noexcept override FMT_MSC_DEFAULT;
+  using std::runtime_error::runtime_error;
 };
 
 namespace detail_exported {
@@ -984,16 +1077,52 @@
 }
 }  // namespace detail_exported
 
-FMT_BEGIN_DETAIL_NAMESPACE
+class loc_value {
+ private:
+  basic_format_arg<format_context> value_;
 
-template <typename T> struct is_integral : std::is_integral<T> {};
-template <> struct is_integral<int128_opt> : std::true_type {};
-template <> struct is_integral<uint128_t> : std::true_type {};
+ public:
+  template <typename T, FMT_ENABLE_IF(!detail::is_float128<T>::value)>
+  loc_value(T value) : value_(detail::make_arg<format_context>(value)) {}
 
-template <typename T>
-using is_signed =
-    std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
-                                     std::is_same<T, int128_opt>::value>;
+  template <typename T, FMT_ENABLE_IF(detail::is_float128<T>::value)>
+  loc_value(T) {}
+
+  template <typename Visitor> auto visit(Visitor&& vis) -> decltype(vis(0)) {
+    return visit_format_arg(vis, value_);
+  }
+};
+
+// A locale facet that formats values in UTF-8.
+// It is parameterized on the locale to avoid the heavy <locale> include.
+template <typename Locale> class format_facet : public Locale::facet {
+ private:
+  std::string separator_;
+  std::string grouping_;
+  std::string decimal_point_;
+
+ protected:
+  virtual auto do_put(appender out, loc_value val,
+                      const format_specs<>& specs) const -> bool;
+
+ public:
+  static FMT_API typename Locale::id id;
+
+  explicit format_facet(Locale& loc);
+  explicit format_facet(string_view sep = "",
+                        std::initializer_list<unsigned char> g = {3},
+                        std::string decimal_point = ".")
+      : separator_(sep.data(), sep.size()),
+        grouping_(g.begin(), g.end()),
+        decimal_point_(decimal_point) {}
+
+  auto put(appender out, loc_value val, const format_specs<>& specs) const
+      -> bool {
+    return do_put(out, val, specs);
+  }
+};
+
+namespace detail {
 
 // Returns true if value is negative, false otherwise.
 // Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
@@ -1122,7 +1251,7 @@
 FMT_INLINE auto do_count_digits(uint32_t n) -> int {
 // An optimization by Kendall Willets from https://bit.ly/3uOIQrB.
 // This increments the upper 32 bits (log10(T) - 1) when >= T is added.
-#  define FMT_INC(T) (((sizeof(#  T) - 1ull) << 32) - T)
+#  define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T)
   static constexpr uint64_t table[] = {
       FMT_INC(0),          FMT_INC(0),          FMT_INC(0),           // 8
       FMT_INC(10),         FMT_INC(10),         FMT_INC(10),          // 64
@@ -1195,7 +1324,14 @@
 template <typename Char>
 FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) {
   if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) {
+#if FMT_GCC_VERSION && FMT_GCC_VERSION >= 1000
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
     memcpy(dst, src, 2);
+#if FMT_GCC_VERSION && FMT_GCC_VERSION >= 1000
+#  pragma GCC diagnostic pop
+#endif
     return;
   }
   *dst++ = static_cast<Char>(*src++);
@@ -1238,7 +1374,7 @@
 FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size)
     -> format_decimal_result<Iterator> {
   // Buffer is large enough to hold all digits (digits10 + 1).
-  Char buffer[digits10<UInt>() + 1];
+  Char buffer[digits10<UInt>() + 1] = {};
   auto end = format_decimal(buffer, value, size).end;
   return {out, detail::copy_str_noinline<Char>(buffer, end, out)};
 }
@@ -1258,8 +1394,8 @@
 }
 
 template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
-inline auto format_uint(It out, UInt value, int num_digits, bool upper = false)
-    -> It {
+FMT_CONSTEXPR inline auto format_uint(It out, UInt value, int num_digits,
+                                      bool upper = false) -> It {
   if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
     format_uint<BASE_BITS>(ptr, value, num_digits, upper);
     return out;
@@ -1283,7 +1419,139 @@
   auto str() const -> std::wstring { return {&buffer_[0], size()}; }
 };
 
+enum class to_utf8_error_policy { abort, replace };
+
+// A converter from UTF-16/UTF-32 (host endian) to UTF-8.
+template <typename WChar, typename Buffer = memory_buffer> class to_utf8 {
+ private:
+  Buffer buffer_;
+
+ public:
+  to_utf8() {}
+  explicit to_utf8(basic_string_view<WChar> s,
+                   to_utf8_error_policy policy = to_utf8_error_policy::abort) {
+    static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4,
+                  "Expect utf16 or utf32");
+    if (!convert(s, policy))
+      FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16"
+                                                      : "invalid utf32"));
+  }
+  operator string_view() const { return string_view(&buffer_[0], size()); }
+  size_t size() const { return buffer_.size() - 1; }
+  const char* c_str() const { return &buffer_[0]; }
+  std::string str() const { return std::string(&buffer_[0], size()); }
+
+  // Performs conversion returning a bool instead of throwing exception on
+  // conversion error. This method may still throw in case of memory allocation
+  // error.
+  bool convert(basic_string_view<WChar> s,
+               to_utf8_error_policy policy = to_utf8_error_policy::abort) {
+    if (!convert(buffer_, s, policy)) return false;
+    buffer_.push_back(0);
+    return true;
+  }
+  static bool convert(
+      Buffer& buf, basic_string_view<WChar> s,
+      to_utf8_error_policy policy = to_utf8_error_policy::abort) {
+    for (auto p = s.begin(); p != s.end(); ++p) {
+      uint32_t c = static_cast<uint32_t>(*p);
+      if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
+        // Handle a surrogate pair.
+        ++p;
+        if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
+          if (policy == to_utf8_error_policy::abort) return false;
+          buf.append(string_view("\xEF\xBF\xBD"));
+          --p;
+        } else {
+          c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
+        }
+      } else if (c < 0x80) {
+        buf.push_back(static_cast<char>(c));
+      } else if (c < 0x800) {
+        buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
+        buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+      } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
+        buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
+        buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
+        buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+      } else if (c >= 0x10000 && c <= 0x10ffff) {
+        buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
+        buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
+        buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
+        buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+      } else {
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
+inline uint128_fallback umul128(uint64_t x, uint64_t y) noexcept {
+#if FMT_USE_INT128
+  auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
+  return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)};
+#elif defined(_MSC_VER) && defined(_M_X64)
+  auto hi = uint64_t();
+  auto lo = _umul128(x, y, &hi);
+  return {hi, lo};
+#else
+  const uint64_t mask = static_cast<uint64_t>(max_value<uint32_t>());
+
+  uint64_t a = x >> 32;
+  uint64_t b = x & mask;
+  uint64_t c = y >> 32;
+  uint64_t d = y & mask;
+
+  uint64_t ac = a * c;
+  uint64_t bc = b * c;
+  uint64_t ad = a * d;
+  uint64_t bd = b * d;
+
+  uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
+
+  return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
+          (intermediate << 32) + (bd & mask)};
+#endif
+}
+
 namespace dragonbox {
+// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from
+// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1.
+inline int floor_log10_pow2(int e) noexcept {
+  FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent");
+  static_assert((-1 >> 1) == -1, "right shift is not arithmetic");
+  return (e * 315653) >> 20;
+}
+
+inline int floor_log2_pow10(int e) noexcept {
+  FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent");
+  return (e * 1741647) >> 19;
+}
+
+// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
+inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept {
+#if FMT_USE_INT128
+  auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
+  return static_cast<uint64_t>(p >> 64);
+#elif defined(_MSC_VER) && defined(_M_X64)
+  return __umulh(x, y);
+#else
+  return umul128(x, y).high();
+#endif
+}
+
+// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a
+// 128-bit unsigned integer.
+inline uint128_fallback umul192_upper128(uint64_t x,
+                                         uint128_fallback y) noexcept {
+  uint128_fallback r = umul128(x, y.high());
+  r += umul128_upper64(x, y.low());
+  return r;
+}
+
+FMT_API uint128_fallback get_cached_power(int k) noexcept;
 
 // Type-specific information that Dragonbox uses.
 template <typename T, typename Enable = void> struct float_info;
@@ -1307,7 +1575,7 @@
   static const int big_divisor = 1000;
   static const int small_divisor = 100;
   static const int min_k = -292;
-  static const int max_k = 326;
+  static const int max_k = 341;
   static const int shorter_interval_tie_lower_threshold = -77;
   static const int shorter_interval_tie_upper_threshold = -77;
 };
@@ -1354,8 +1622,8 @@
 template <typename Float>
 constexpr auto exponent_mask() ->
     typename dragonbox::float_info<Float>::carrier_uint {
-  using uint = typename dragonbox::float_info<Float>::carrier_uint;
-  return ((uint(1) << dragonbox::float_info<Float>::exponent_bits) - 1)
+  using float_uint = typename dragonbox::float_info<Float>::carrier_uint;
+  return ((float_uint(1) << dragonbox::float_info<Float>::exponent_bits) - 1)
          << num_significand_bits<Float>();
 }
 template <typename Float> constexpr auto exponent_bias() -> int {
@@ -1476,157 +1744,31 @@
 }
 
 template <typename T = void> struct basic_data {
-  // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
-  // These are generated by support/compute-powers.py.
-  static constexpr uint64_t pow10_significands[87] = {
-      0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
-      0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
-      0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
-      0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
-      0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
-      0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
-      0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
-      0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
-      0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
-      0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
-      0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
-      0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
-      0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
-      0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
-      0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
-      0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
-      0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
-      0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
-      0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
-      0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
-      0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
-      0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
-      0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
-      0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
-      0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
-      0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
-      0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
-      0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
-      0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
+  // For checking rounding thresholds.
+  // The kth entry is chosen to be the smallest integer such that the
+  // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k.
+  static constexpr uint32_t fractional_part_rounding_thresholds[8] = {
+      2576980378U,  // ceil(2^31 + 2^32/10^1)
+      2190433321U,  // ceil(2^31 + 2^32/10^2)
+      2151778616U,  // ceil(2^31 + 2^32/10^3)
+      2147913145U,  // ceil(2^31 + 2^32/10^4)
+      2147526598U,  // ceil(2^31 + 2^32/10^5)
+      2147487943U,  // ceil(2^31 + 2^32/10^6)
+      2147484078U,  // ceil(2^31 + 2^32/10^7)
+      2147483691U   // ceil(2^31 + 2^32/10^8)
   };
-
-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wnarrowing"
-#endif
-  // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
-  // to significands above.
-  static constexpr int16_t pow10_exponents[87] = {
-      -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
-      -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,  -688, -661,
-      -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,  -422,  -396, -369,
-      -343,  -316,  -289,  -263,  -236,  -210,  -183,  -157,  -130,  -103, -77,
-      -50,   -24,   3,     30,    56,    83,    109,   136,   162,   189,  216,
-      242,   269,   295,   322,   348,   375,   402,   428,   455,   481,  508,
-      534,   561,   588,   614,   641,   667,   694,   720,   747,   774,  800,
-      827,   853,   880,   907,   933,   960,   986,   1013,  1039,  1066};
-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
-#  pragma GCC diagnostic pop
-#endif
-
-  static constexpr uint64_t power_of_10_64[20] = {
-      1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL),
-      10000000000000000000ULL};
 };
-
-#if FMT_CPLUSPLUS < 201703L
-template <typename T> constexpr uint64_t basic_data<T>::pow10_significands[];
-template <typename T> constexpr int16_t basic_data<T>::pow10_exponents[];
-template <typename T> constexpr uint64_t basic_data<T>::power_of_10_64[];
-#endif
-
 // This is a struct rather than an alias to avoid shadowing warnings in gcc.
 struct data : basic_data<> {};
 
-// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its
-// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`.
-FMT_CONSTEXPR inline fp get_cached_power(int min_exponent,
-                                         int& pow10_exponent) {
-  const int shift = 32;
-  // log10(2) = 0x0.4d104d427de7fbcc...
-  const int64_t significand = 0x4d104d427de7fbcc;
-  int index = static_cast<int>(
-      ((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) +
-       ((int64_t(1) << shift) - 1))  // ceil
-      >> 32                          // arithmetic shift
-  );
-  // Decimal exponent of the first (smallest) cached power of 10.
-  const int first_dec_exp = -348;
-  // Difference between 2 consecutive decimal exponents in cached powers of 10.
-  const int dec_exp_step = 8;
-  index = (index - first_dec_exp - 1) / dec_exp_step + 1;
-  pow10_exponent = first_dec_exp + index * dec_exp_step;
-  // Using *(x + index) instead of x[index] avoids an issue with some compilers
-  // using the EDG frontend (e.g. nvhpc/22.3 in C++17 mode).
-  return {*(data::pow10_significands + index),
-          *(data::pow10_exponents + index)};
-}
-
-#ifndef _MSC_VER
-#  define FMT_SNPRINTF snprintf
-#else
-FMT_API auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...) -> int;
-#  define FMT_SNPRINTF fmt_snprintf
-#endif  // _MSC_VER
-
-// Formats a floating-point number with snprintf using the hexfloat format.
+#if FMT_CPLUSPLUS < 201703L
 template <typename T>
-auto snprintf_float(T value, int precision, float_specs specs,
-                    buffer<char>& buf) -> int {
-  // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
-  FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
-  FMT_ASSERT(specs.format == float_format::hex, "");
-  static_assert(!std::is_same<T, float>::value, "");
+constexpr uint32_t basic_data<T>::fractional_part_rounding_thresholds[];
+#endif
 
-  // Build the format string.
-  char format[7];  // The longest format is "%#.*Le".
-  char* format_ptr = format;
-  *format_ptr++ = '%';
-  if (specs.showpoint) *format_ptr++ = '#';
-  if (precision >= 0) {
-    *format_ptr++ = '.';
-    *format_ptr++ = '*';
-  }
-  if (std::is_same<T, long double>()) *format_ptr++ = 'L';
-  *format_ptr++ = specs.upper ? 'A' : 'a';
-  *format_ptr = '\0';
-
-  // Format using snprintf.
-  auto offset = buf.size();
-  for (;;) {
-    auto begin = buf.data() + offset;
-    auto capacity = buf.capacity() - offset;
-    abort_fuzzing_if(precision > 100000);
-    // Suppress the warning about a nonliteral format string.
-    // Cannot use auto because of a bug in MinGW (#1532).
-    int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
-    int result = precision >= 0
-                     ? snprintf_ptr(begin, capacity, format, precision, value)
-                     : snprintf_ptr(begin, capacity, format, value);
-    if (result < 0) {
-      // The buffer will grow exponentially.
-      buf.try_reserve(buf.capacity() + 1);
-      continue;
-    }
-    auto size = to_unsigned(result);
-    // Size equal to capacity means that the last character was truncated.
-    if (size < capacity) {
-      buf.try_resize(size + offset);
-      return 0;
-    }
-    buf.try_reserve(size + offset + 1);  // Add 1 for the terminating '\0'.
-  }
-}
-
-template <typename T>
+template <typename T, bool doublish = num_bits<T>() == num_bits<double>()>
 using convert_float_result =
-    conditional_t<std::is_same<T, float>::value || sizeof(T) == sizeof(double),
-                  double, T>;
+    conditional_t<std::is_same<T, float>::value || doublish, double, T>;
 
 template <typename T>
 constexpr auto convert_float(T value) -> convert_float_result<T> {
@@ -1649,8 +1791,7 @@
 // width: output display width in (terminal) column positions.
 template <align::type align = align::left, typename OutputIt, typename Char,
           typename F>
-FMT_CONSTEXPR auto write_padded(OutputIt out,
-                                const basic_format_specs<Char>& specs,
+FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs<Char>& specs,
                                 size_t size, size_t width, F&& f) -> OutputIt {
   static_assert(align == align::left || align == align::right, "");
   unsigned spec_width = to_unsigned(specs.width);
@@ -1669,15 +1810,14 @@
 
 template <align::type align = align::left, typename OutputIt, typename Char,
           typename F>
-constexpr auto write_padded(OutputIt out, const basic_format_specs<Char>& specs,
+constexpr auto write_padded(OutputIt out, const format_specs<Char>& specs,
                             size_t size, F&& f) -> OutputIt {
   return write_padded<align>(out, specs, size, size, f);
 }
 
 template <align::type align = align::left, typename Char, typename OutputIt>
 FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes,
-                               const basic_format_specs<Char>& specs)
-    -> OutputIt {
+                               const format_specs<Char>& specs) -> OutputIt {
   return write_padded<align>(
       out, specs, bytes.size(), [bytes](reserve_iterator<OutputIt> it) {
         const char* data = bytes.data();
@@ -1686,8 +1826,8 @@
 }
 
 template <typename Char, typename OutputIt, typename UIntPtr>
-auto write_ptr(OutputIt out, UIntPtr value,
-               const basic_format_specs<Char>* specs) -> OutputIt {
+auto write_ptr(OutputIt out, UIntPtr value, const format_specs<Char>* specs)
+    -> OutputIt {
   int num_digits = count_digits<4>(value);
   auto size = to_unsigned(num_digits) + size_t(2);
   auto write = [=](reserve_iterator<OutputIt> it) {
@@ -1749,7 +1889,7 @@
   [] {                                                                        \
     /* Use the hidden visibility as a workaround for a GCC bug (#1973). */    \
     /* Use a macro-like name to avoid shadowing warnings. */                  \
-    struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base {              \
+    struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base {               \
       using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t<decltype(s[0])>; \
       FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit                                 \
       operator fmt::basic_string_view<char_type>() const {                    \
@@ -1806,16 +1946,14 @@
     *out++ = static_cast<Char>('\\');
     break;
   default:
-    if (is_utf8()) {
-      if (escape.cp < 0x100) {
-        return write_codepoint<2, Char>(out, 'x', escape.cp);
-      }
-      if (escape.cp < 0x10000) {
-        return write_codepoint<4, Char>(out, 'u', escape.cp);
-      }
-      if (escape.cp < 0x110000) {
-        return write_codepoint<8, Char>(out, 'U', escape.cp);
-      }
+    if (escape.cp < 0x100) {
+      return write_codepoint<2, Char>(out, 'x', escape.cp);
+    }
+    if (escape.cp < 0x10000) {
+      return write_codepoint<4, Char>(out, 'u', escape.cp);
+    }
+    if (escape.cp < 0x110000) {
+      return write_codepoint<8, Char>(out, 'U', escape.cp);
     }
     for (Char escape_char : basic_string_view<Char>(
              escape.begin, to_unsigned(escape.end - escape.begin))) {
@@ -1860,8 +1998,7 @@
 
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR auto write_char(OutputIt out, Char value,
-                              const basic_format_specs<Char>& specs)
-    -> OutputIt {
+                              const format_specs<Char>& specs) -> OutputIt {
   bool is_debug = specs.type == presentation_type::debug;
   return write_padded(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
     if (is_debug) return write_escaped_char(it, value);
@@ -1871,11 +2008,14 @@
 }
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR auto write(OutputIt out, Char value,
-                         const basic_format_specs<Char>& specs,
-                         locale_ref loc = {}) -> OutputIt {
+                         const format_specs<Char>& specs, locale_ref loc = {})
+    -> OutputIt {
+  // char is formatted as unsigned char for consistency across platforms.
+  using unsigned_type =
+      conditional_t<std::is_same<Char, char>::value, unsigned char, unsigned>;
   return check_char_specs(specs)
              ? write_char(out, value, specs)
-             : write(out, static_cast<int>(value), specs, loc);
+             : write(out, static_cast<unsigned_type>(value), specs, loc);
 }
 
 // Data for write_int that doesn't depend on output iterator type. It is used to
@@ -1885,7 +2025,7 @@
   size_t padding;
 
   FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix,
-                               const basic_format_specs<Char>& specs)
+                               const format_specs<Char>& specs)
       : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
     if (specs.align == align::numeric) {
       auto width = to_unsigned(specs.width);
@@ -1907,7 +2047,7 @@
 template <typename OutputIt, typename Char, typename W>
 FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits,
                                         unsigned prefix,
-                                        const basic_format_specs<Char>& specs,
+                                        const format_specs<Char>& specs,
                                         W write_digits) -> OutputIt {
   // Slightly faster check for specs.width == 0 && specs.precision == -1.
   if ((specs.width | (specs.precision + 1)) == 0) {
@@ -1930,19 +2070,19 @@
 
 template <typename Char> class digit_grouping {
  private:
-  thousands_sep_result<Char> sep_;
+  std::string grouping_;
+  std::basic_string<Char> thousands_sep_;
 
   struct next_state {
     std::string::const_iterator group;
     int pos;
   };
-  next_state initial_state() const { return {sep_.grouping.begin(), 0}; }
+  next_state initial_state() const { return {grouping_.begin(), 0}; }
 
   // Returns the next digit group separator position.
   int next(next_state& state) const {
-    if (!sep_.thousands_sep) return max_value<int>();
-    if (state.group == sep_.grouping.end())
-      return state.pos += sep_.grouping.back();
+    if (thousands_sep_.empty()) return max_value<int>();
+    if (state.group == grouping_.end()) return state.pos += grouping_.back();
     if (*state.group <= 0 || *state.group == max_value<char>())
       return max_value<int>();
     state.pos += *state.group++;
@@ -1951,14 +2091,15 @@
 
  public:
   explicit digit_grouping(locale_ref loc, bool localized = true) {
-    if (localized)
-      sep_ = thousands_sep<Char>(loc);
-    else
-      sep_.thousands_sep = Char();
+    if (!localized) return;
+    auto sep = thousands_sep<Char>(loc);
+    grouping_ = sep.grouping;
+    if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
   }
-  explicit digit_grouping(thousands_sep_result<Char> sep) : sep_(sep) {}
+  digit_grouping(std::string grouping, std::basic_string<Char> sep)
+      : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
 
-  Char separator() const { return sep_.thousands_sep; }
+  bool has_separator() const { return !thousands_sep_.empty(); }
 
   int count_separators(int num_digits) const {
     int count = 0;
@@ -1981,7 +2122,9 @@
     for (int i = 0, sep_index = static_cast<int>(separators.size() - 1);
          i < num_digits; ++i) {
       if (num_digits - i == separators[sep_index]) {
-        *out++ = separator();
+        out =
+            copy_str<Char>(thousands_sep_.data(),
+                           thousands_sep_.data() + thousands_sep_.size(), out);
         --sep_index;
       }
       *out++ = static_cast<Char>(digits[to_unsigned(i)]);
@@ -1990,10 +2133,11 @@
   }
 };
 
+// Writes a decimal integer with digit grouping.
 template <typename OutputIt, typename UInt, typename Char>
-auto write_int_localized(OutputIt out, UInt value, unsigned prefix,
-                         const basic_format_specs<Char>& specs,
-                         const digit_grouping<Char>& grouping) -> OutputIt {
+auto write_int(OutputIt out, UInt value, unsigned prefix,
+               const format_specs<Char>& specs,
+               const digit_grouping<Char>& grouping) -> OutputIt {
   static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
   int num_digits = count_digits(value);
   char digits[40];
@@ -2010,13 +2154,13 @@
       });
 }
 
-template <typename OutputIt, typename UInt, typename Char>
-auto write_int_localized(OutputIt& out, UInt value, unsigned prefix,
-                         const basic_format_specs<Char>& specs, locale_ref loc)
-    -> bool {
-  auto grouping = digit_grouping<Char>(loc);
-  out = write_int_localized(out, value, prefix, specs, grouping);
-  return true;
+// Writes a localized value.
+FMT_API auto write_loc(appender out, loc_value value,
+                       const format_specs<>& specs, locale_ref loc) -> bool;
+template <typename OutputIt, typename Char>
+inline auto write_loc(OutputIt, loc_value, const format_specs<Char>&,
+                      locale_ref) -> bool {
+  return false;
 }
 
 FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
@@ -2045,21 +2189,37 @@
   return {abs_value, prefix};
 }
 
+template <typename Char = char> struct loc_writer {
+  buffer_appender<Char> out;
+  const format_specs<Char>& specs;
+  std::basic_string<Char> sep;
+  std::string grouping;
+  std::basic_string<Char> decimal_point;
+
+  template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
+  auto operator()(T value) -> bool {
+    auto arg = make_write_int_arg(value, specs.sign);
+    write_int(out, static_cast<uint64_or_128_t<T>>(arg.abs_value), arg.prefix,
+              specs, digit_grouping<Char>(grouping, sep));
+    return true;
+  }
+
+  template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
+  auto operator()(T) -> bool {
+    return false;
+  }
+};
+
 template <typename Char, typename OutputIt, typename T>
 FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
-                                        const basic_format_specs<Char>& specs,
-                                        locale_ref loc) -> OutputIt {
+                                        const format_specs<Char>& specs,
+                                        locale_ref) -> OutputIt {
   static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value, "");
   auto abs_value = arg.abs_value;
   auto prefix = arg.prefix;
   switch (specs.type) {
   case presentation_type::none:
   case presentation_type::dec: {
-    if (specs.localized &&
-        write_int_localized(out, static_cast<uint64_or_128_t<T>>(abs_value),
-                            prefix, specs, loc)) {
-      return out;
-    }
     auto num_digits = count_digits(abs_value);
     return write_int(
         out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
@@ -2102,13 +2262,13 @@
   case presentation_type::chr:
     return write_char(out, static_cast<Char>(abs_value), specs);
   default:
-    throw_format_error("invalid type specifier");
+    throw_format_error("invalid format specifier");
   }
   return out;
 }
 template <typename Char, typename OutputIt, typename T>
 FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline(
-    OutputIt out, write_int_arg<T> arg, const basic_format_specs<Char>& specs,
+    OutputIt out, write_int_arg<T> arg, const format_specs<Char>& specs,
     locale_ref loc) -> OutputIt {
   return write_int(out, arg, specs, loc);
 }
@@ -2117,8 +2277,9 @@
                         !std::is_same<T, bool>::value &&
                         std::is_same<OutputIt, buffer_appender<Char>>::value)>
 FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
-                                    const basic_format_specs<Char>& specs,
+                                    const format_specs<Char>& specs,
                                     locale_ref loc) -> OutputIt {
+  if (specs.localized && write_loc(out, value, specs, loc)) return out;
   return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs,
                             loc);
 }
@@ -2128,8 +2289,9 @@
                         !std::is_same<T, bool>::value &&
                         !std::is_same<OutputIt, buffer_appender<Char>>::value)>
 FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
-                                    const basic_format_specs<Char>& specs,
+                                    const format_specs<Char>& specs,
                                     locale_ref loc) -> OutputIt {
+  if (specs.localized && write_loc(out, value, specs, loc)) return out;
   return write_int(out, make_write_int_arg(value, specs.sign), specs, loc);
 }
 
@@ -2175,7 +2337,7 @@
 
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> s,
-                         const basic_format_specs<Char>& specs) -> OutputIt {
+                         const format_specs<Char>& specs) -> OutputIt {
   auto data = s.data();
   auto size = s.size();
   if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
@@ -2197,16 +2359,15 @@
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR auto write(OutputIt out,
                          basic_string_view<type_identity_t<Char>> s,
-                         const basic_format_specs<Char>& specs, locale_ref)
+                         const format_specs<Char>& specs, locale_ref)
     -> OutputIt {
-  check_string_type_spec(specs.type);
   return write(out, s, specs);
 }
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR auto write(OutputIt out, const Char* s,
-                         const basic_format_specs<Char>& specs, locale_ref)
+                         const format_specs<Char>& specs, locale_ref)
     -> OutputIt {
-  return check_cstring_type_spec(specs.type)
+  return specs.type != presentation_type::pointer
              ? write(out, basic_string_view<Char>(s), specs, {})
              : write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
 }
@@ -2233,9 +2394,114 @@
   return base_iterator(out, it);
 }
 
+// DEPRECATED!
+template <typename Char>
+FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
+                               format_specs<Char>& specs) -> const Char* {
+  FMT_ASSERT(begin != end, "");
+  auto align = align::none;
+  auto p = begin + code_point_length(begin);
+  if (end - p <= 0) p = begin;
+  for (;;) {
+    switch (to_ascii(*p)) {
+    case '<':
+      align = align::left;
+      break;
+    case '>':
+      align = align::right;
+      break;
+    case '^':
+      align = align::center;
+      break;
+    }
+    if (align != align::none) {
+      if (p != begin) {
+        auto c = *begin;
+        if (c == '}') return begin;
+        if (c == '{') {
+          throw_format_error("invalid fill character '{'");
+          return begin;
+        }
+        specs.fill = {begin, to_unsigned(p - begin)};
+        begin = p + 1;
+      } else {
+        ++begin;
+      }
+      break;
+    } else if (p == begin) {
+      break;
+    }
+    p = begin;
+  }
+  specs.align = align;
+  return begin;
+}
+
+// A floating-point presentation format.
+enum class float_format : unsigned char {
+  general,  // General: exponent notation or fixed point based on magnitude.
+  exp,      // Exponent notation with the default precision of 6, e.g. 1.2e-3.
+  fixed,    // Fixed point with the default precision of 6, e.g. 0.0012.
+  hex
+};
+
+struct float_specs {
+  int precision;
+  float_format format : 8;
+  sign_t sign : 8;
+  bool upper : 1;
+  bool locale : 1;
+  bool binary32 : 1;
+  bool showpoint : 1;
+};
+
+template <typename ErrorHandler = error_handler, typename Char>
+FMT_CONSTEXPR auto parse_float_type_spec(const format_specs<Char>& specs,
+                                         ErrorHandler&& eh = {})
+    -> float_specs {
+  auto result = float_specs();
+  result.showpoint = specs.alt;
+  result.locale = specs.localized;
+  switch (specs.type) {
+  case presentation_type::none:
+    result.format = float_format::general;
+    break;
+  case presentation_type::general_upper:
+    result.upper = true;
+    FMT_FALLTHROUGH;
+  case presentation_type::general_lower:
+    result.format = float_format::general;
+    break;
+  case presentation_type::exp_upper:
+    result.upper = true;
+    FMT_FALLTHROUGH;
+  case presentation_type::exp_lower:
+    result.format = float_format::exp;
+    result.showpoint |= specs.precision != 0;
+    break;
+  case presentation_type::fixed_upper:
+    result.upper = true;
+    FMT_FALLTHROUGH;
+  case presentation_type::fixed_lower:
+    result.format = float_format::fixed;
+    result.showpoint |= specs.precision != 0;
+    break;
+  case presentation_type::hexfloat_upper:
+    result.upper = true;
+    FMT_FALLTHROUGH;
+  case presentation_type::hexfloat_lower:
+    result.format = float_format::hex;
+    break;
+  default:
+    eh.on_error("invalid format specifier");
+    break;
+  }
+  return result;
+}
+
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
-                                     basic_format_specs<Char> specs,
+                                     format_specs<Char> specs,
                                      const float_specs& fspecs) -> OutputIt {
   auto str =
       isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf");
@@ -2281,7 +2547,7 @@
 FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
                                        int significand_size, int exponent,
                                        const Grouping& grouping) -> OutputIt {
-  if (!grouping.separator()) {
+  if (!grouping.has_separator()) {
     out = write_significand<Char>(out, significand, significand_size);
     return detail::fill_n(out, exponent, static_cast<Char>('0'));
   }
@@ -2343,7 +2609,7 @@
                                        int significand_size, int integral_size,
                                        Char decimal_point,
                                        const Grouping& grouping) -> OutputIt {
-  if (!grouping.separator()) {
+  if (!grouping.has_separator()) {
     return write_significand(out, significand, significand_size, integral_size,
                              decimal_point);
   }
@@ -2359,7 +2625,7 @@
 template <typename OutputIt, typename DecimalFP, typename Char,
           typename Grouping = digit_grouping<Char>>
 FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
-                                    const basic_format_specs<Char>& specs,
+                                    const format_specs<Char>& specs,
                                     float_specs fspecs, locale_ref loc)
     -> OutputIt {
   auto significand = f.significand;
@@ -2418,7 +2684,7 @@
     abort_fuzzing_if(num_zeros > 5000);
     if (fspecs.showpoint) {
       ++size;
-      if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1;
+      if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0;
       if (num_zeros > 0) size += to_unsigned(num_zeros);
     }
     auto grouping = Grouping(loc, fspecs.locale);
@@ -2436,7 +2702,7 @@
     int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
     size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
     auto grouping = Grouping(loc, fspecs.locale);
-    size += to_unsigned(grouping.count_separators(significand_size));
+    size += to_unsigned(grouping.count_separators(exp));
     return write_padded<align::right>(out, specs, size, [&](iterator it) {
       if (sign) *it++ = detail::sign<Char>(sign);
       it = write_significand(it, significand, significand_size, exp,
@@ -2466,7 +2732,7 @@
  public:
   constexpr fallback_digit_grouping(locale_ref, bool) {}
 
-  constexpr Char separator() const { return Char(); }
+  constexpr bool has_separator() const { return false; }
 
   constexpr int count_separators(int) const { return 0; }
 
@@ -2478,7 +2744,7 @@
 
 template <typename OutputIt, typename DecimalFP, typename Char>
 FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f,
-                                 const basic_format_specs<Char>& specs,
+                                 const format_specs<Char>& specs,
                                  float_specs fspecs, locale_ref loc)
     -> OutputIt {
   if (is_constant_evaluated()) {
@@ -2506,14 +2772,14 @@
 FMT_CONSTEXPR20 bool isfinite(T value) {
   constexpr T inf = T(std::numeric_limits<double>::infinity());
   if (is_constant_evaluated())
-    return !detail::isnan(value) && value != inf && value != -inf;
+    return !detail::isnan(value) && value < inf && value > -inf;
   return std::isfinite(value);
 }
 template <typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
 FMT_CONSTEXPR bool isfinite(T value) {
   T inf = T(std::numeric_limits<double>::infinity());
   // std::isfinite doesn't support __float128.
-  return !detail::isnan(value) && value != inf && value != -inf;
+  return !detail::isnan(value) && value < inf && value > -inf;
 }
 
 template <typename T, FMT_ENABLE_IF(is_floating_point<T>::value)>
@@ -2529,78 +2795,6 @@
   return std::signbit(static_cast<double>(value));
 }
 
-enum class round_direction { unknown, up, down };
-
-// Given the divisor (normally a power of 10), the remainder = v % divisor for
-// some number v and the error, returns whether v should be rounded up, down, or
-// whether the rounding direction can't be determined due to error.
-// error should be less than divisor / 2.
-FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor,
-                                                         uint64_t remainder,
-                                                         uint64_t error) {
-  FMT_ASSERT(remainder < divisor, "");  // divisor - remainder won't overflow.
-  FMT_ASSERT(error < divisor, "");      // divisor - error won't overflow.
-  FMT_ASSERT(error < divisor - error, "");  // error * 2 won't overflow.
-  // Round down if (remainder + error) * 2 <= divisor.
-  if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2)
-    return round_direction::down;
-  // Round up if (remainder - error) * 2 >= divisor.
-  if (remainder >= error &&
-      remainder - error >= divisor - (remainder - error)) {
-    return round_direction::up;
-  }
-  return round_direction::unknown;
-}
-
-namespace digits {
-enum result {
-  more,  // Generate more digits.
-  done,  // Done generating digits.
-  error  // Digit generation cancelled due to an error.
-};
-}
-
-struct gen_digits_handler {
-  char* buf;
-  int size;
-  int precision;
-  int exp10;
-  bool fixed;
-
-  FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor,
-                                        uint64_t remainder, uint64_t error,
-                                        bool integral) {
-    FMT_ASSERT(remainder < divisor, "");
-    buf[size++] = digit;
-    if (!integral && error >= remainder) return digits::error;
-    if (size < precision) return digits::more;
-    if (!integral) {
-      // Check if error * 2 < divisor with overflow prevention.
-      // The check is not needed for the integral part because error = 1
-      // and divisor > (1 << 32) there.
-      if (error >= divisor || error >= divisor - error) return digits::error;
-    } else {
-      FMT_ASSERT(error == 1 && divisor > 2, "");
-    }
-    auto dir = get_round_direction(divisor, remainder, error);
-    if (dir != round_direction::up)
-      return dir == round_direction::down ? digits::done : digits::error;
-    ++buf[size - 1];
-    for (int i = size - 1; i > 0 && buf[i] > '9'; --i) {
-      buf[i] = '0';
-      ++buf[i - 1];
-    }
-    if (buf[0] > '9') {
-      buf[0] = '1';
-      if (fixed)
-        buf[size++] = '0';
-      else
-        ++exp10;
-    }
-    return digits::done;
-  }
-};
-
 inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) {
   // Adjust fixed precision by exponent because it is relative to decimal
   // point.
@@ -2609,101 +2803,6 @@
   precision += exp10;
 }
 
-// Generates output using the Grisu digit-gen algorithm.
-// error: the size of the region (lower, upper) outside of which numbers
-// definitely do not round to value (Delta in Grisu3).
-FMT_INLINE FMT_CONSTEXPR20 auto grisu_gen_digits(fp value, uint64_t error,
-                                                 int& exp,
-                                                 gen_digits_handler& handler)
-    -> digits::result {
-  const fp one(1ULL << -value.e, value.e);
-  // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be
-  // zero because it contains a product of two 64-bit numbers with MSB set (due
-  // to normalization) - 1, shifted right by at most 60 bits.
-  auto integral = static_cast<uint32_t>(value.f >> -one.e);
-  FMT_ASSERT(integral != 0, "");
-  FMT_ASSERT(integral == value.f >> -one.e, "");
-  // The fractional part of scaled value (p2 in Grisu) c = value % one.
-  uint64_t fractional = value.f & (one.f - 1);
-  exp = count_digits(integral);  // kappa in Grisu.
-  // Non-fixed formats require at least one digit and no precision adjustment.
-  if (handler.fixed) {
-    adjust_precision(handler.precision, exp + handler.exp10);
-    // Check if precision is satisfied just by leading zeros, e.g.
-    // format("{:.2f}", 0.001) gives "0.00" without generating any digits.
-    if (handler.precision <= 0) {
-      if (handler.precision < 0) return digits::done;
-      // Divide by 10 to prevent overflow.
-      uint64_t divisor = data::power_of_10_64[exp - 1] << -one.e;
-      auto dir = get_round_direction(divisor, value.f / 10, error * 10);
-      if (dir == round_direction::unknown) return digits::error;
-      handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0';
-      return digits::done;
-    }
-  }
-  // Generate digits for the integral part. This can produce up to 10 digits.
-  do {
-    uint32_t digit = 0;
-    auto divmod_integral = [&](uint32_t divisor) {
-      digit = integral / divisor;
-      integral %= divisor;
-    };
-    // This optimization by Milo Yip reduces the number of integer divisions by
-    // one per iteration.
-    switch (exp) {
-    case 10:
-      divmod_integral(1000000000);
-      break;
-    case 9:
-      divmod_integral(100000000);
-      break;
-    case 8:
-      divmod_integral(10000000);
-      break;
-    case 7:
-      divmod_integral(1000000);
-      break;
-    case 6:
-      divmod_integral(100000);
-      break;
-    case 5:
-      divmod_integral(10000);
-      break;
-    case 4:
-      divmod_integral(1000);
-      break;
-    case 3:
-      divmod_integral(100);
-      break;
-    case 2:
-      divmod_integral(10);
-      break;
-    case 1:
-      digit = integral;
-      integral = 0;
-      break;
-    default:
-      FMT_ASSERT(false, "invalid number of digits");
-    }
-    --exp;
-    auto remainder = (static_cast<uint64_t>(integral) << -one.e) + fractional;
-    auto result = handler.on_digit(static_cast<char>('0' + digit),
-                                   data::power_of_10_64[exp] << -one.e,
-                                   remainder, error, true);
-    if (result != digits::more) return result;
-  } while (exp > 0);
-  // Generate digits for the fractional part.
-  for (;;) {
-    fractional *= 10;
-    error *= 10;
-    char digit = static_cast<char>('0' + (fractional >> -one.e));
-    fractional &= one.f - 1;
-    --exp;
-    auto result = handler.on_digit(digit, one.f, fractional, error, false);
-    if (result != digits::more) return result;
-  }
-}
-
 class bigint {
  private:
   // A bigint is stored as an array of bigits (big digits), with bigit at index
@@ -2804,7 +2903,7 @@
     auto size = other.bigits_.size();
     bigits_.resize(size);
     auto data = other.bigits_.data();
-    std::copy(data, data + size, make_checked(bigits_.data(), size));
+    copy_str<bigit>(data, data + size, bigits_.data());
     exp_ = other.exp_;
   }
 
@@ -3018,6 +3117,7 @@
   }
   int even = static_cast<int>((value.f & 1) == 0);
   if (!upper) upper = &lower;
+  bool shortest = num_digits < 0;
   if ((flags & dragon::fixup) != 0) {
     if (add_compare(numerator, *upper, denominator) + even <= 0) {
       --exp10;
@@ -3030,7 +3130,7 @@
     if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
   }
   // Invariant: value == (numerator / denominator) * pow(10, exp10).
-  if (num_digits < 0) {
+  if (shortest) {
     // Generate the shortest representation.
     num_digits = 0;
     char* data = buf.data();
@@ -3060,7 +3160,7 @@
   }
   // Generate the given number of digits.
   exp10 -= num_digits - 1;
-  if (num_digits == 0) {
+  if (num_digits <= 0) {
     denominator *= 10;
     auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0';
     buf.push_back(digit);
@@ -3085,7 +3185,8 @@
       }
       if (buf[0] == overflow) {
         buf[0] = '1';
-        ++exp10;
+        if ((flags & dragon::fixed) != 0) buf.push_back('0');
+        else ++exp10;
       }
       return;
     }
@@ -3094,6 +3195,94 @@
   buf[num_digits - 1] = static_cast<char>('0' + digit);
 }
 
+// Formats a floating-point number using the hexfloat format.
+template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
+FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
+                                     float_specs specs, buffer<char>& buf) {
+  // float is passed as double to reduce the number of instantiations and to
+  // simplify implementation.
+  static_assert(!std::is_same<Float, float>::value, "");
+
+  using info = dragonbox::float_info<Float>;
+
+  // Assume Float is in the format [sign][exponent][significand].
+  using carrier_uint = typename info::carrier_uint;
+
+  constexpr auto num_float_significand_bits =
+      detail::num_significand_bits<Float>();
+
+  basic_fp<carrier_uint> f(value);
+  f.e += num_float_significand_bits;
+  if (!has_implicit_bit<Float>()) --f.e;
+
+  constexpr auto num_fraction_bits =
+      num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
+  constexpr auto num_xdigits = (num_fraction_bits + 3) / 4;
+
+  constexpr auto leading_shift = ((num_xdigits - 1) * 4);
+  const auto leading_mask = carrier_uint(0xF) << leading_shift;
+  const auto leading_xdigit =
+      static_cast<uint32_t>((f.f & leading_mask) >> leading_shift);
+  if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
+
+  int print_xdigits = num_xdigits - 1;
+  if (precision >= 0 && print_xdigits > precision) {
+    const int shift = ((print_xdigits - precision - 1) * 4);
+    const auto mask = carrier_uint(0xF) << shift;
+    const auto v = static_cast<uint32_t>((f.f & mask) >> shift);
+
+    if (v >= 8) {
+      const auto inc = carrier_uint(1) << (shift + 4);
+      f.f += inc;
+      f.f &= ~(inc - 1);
+    }
+
+    // Check long double overflow
+    if (!has_implicit_bit<Float>()) {
+      const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
+      if ((f.f & implicit_bit) == implicit_bit) {
+        f.f >>= 4;
+        f.e += 4;
+      }
+    }
+
+    print_xdigits = precision;
+  }
+
+  char xdigits[num_bits<carrier_uint>() / 4];
+  detail::fill_n(xdigits, sizeof(xdigits), '0');
+  format_uint<4>(xdigits, f.f, num_xdigits, specs.upper);
+
+  // Remove zero tail
+  while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits;
+
+  buf.push_back('0');
+  buf.push_back(specs.upper ? 'X' : 'x');
+  buf.push_back(xdigits[0]);
+  if (specs.showpoint || print_xdigits > 0 || print_xdigits < precision)
+    buf.push_back('.');
+  buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
+  for (; print_xdigits < precision; ++print_xdigits) buf.push_back('0');
+
+  buf.push_back(specs.upper ? 'P' : 'p');
+
+  uint32_t abs_e;
+  if (f.e < 0) {
+    buf.push_back('-');
+    abs_e = static_cast<uint32_t>(-f.e);
+  } else {
+    buf.push_back('+');
+    abs_e = static_cast<uint32_t>(f.e);
+  }
+  format_decimal<char>(appender(buf), abs_e, detail::count_digits(abs_e));
+}
+
+template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
+FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
+                                     float_specs specs, buffer<char>& buf) {
+  format_hexfloat(static_cast<double>(value), precision, specs, buf);
+}
+
 template <typename Float>
 FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
                                   buffer<char>& buf) -> int {
@@ -3116,7 +3305,7 @@
   int exp = 0;
   bool use_dragon = true;
   unsigned dragon_flags = 0;
-  if (!is_fast_float<Float>()) {
+  if (!is_fast_float<Float>() || is_constant_evaluated()) {
     const auto inv_log2_10 = 0.3010299956639812;  // 1 / log2(10)
     using info = dragonbox::float_info<decltype(converted_value)>;
     const auto f = basic_fp<typename info::carrier_uint>(converted_value);
@@ -3124,10 +3313,11 @@
     //   10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1).
     // This is based on log10(value) == log2(value) / log2(10) and approximation
     // of log2(value) by e + num_fraction_bits idea from double-conversion.
-    exp = static_cast<int>(
-        std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10));
+    auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
+    exp = static_cast<int>(e);
+    if (e > exp) ++exp;  // Compute ceil.
     dragon_flags = dragon::fixup;
-  } else if (!is_constant_evaluated() && precision < 0) {
+  } else if (precision < 0) {
     // Use Dragonbox for the shortest format.
     if (specs.binary32) {
       auto dec = dragonbox::to_decimal(static_cast<float>(value));
@@ -3138,23 +3328,244 @@
     write<char>(buffer_appender<char>(buf), dec.significand);
     return dec.exponent;
   } else {
-    // Use Grisu + Dragon4 for the given precision:
-    // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf.
-    const int min_exp = -60;  // alpha in Grisu.
-    int cached_exp10 = 0;     // K in Grisu.
-    fp normalized = normalize(fp(converted_value));
-    const auto cached_pow = get_cached_power(
-        min_exp - (normalized.e + fp::num_significand_bits), cached_exp10);
-    normalized = normalized * cached_pow;
-    gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed};
-    if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error &&
-        !is_constant_evaluated()) {
-      exp += handler.exp10;
-      buf.try_resize(to_unsigned(handler.size));
-      use_dragon = false;
+    // Extract significand bits and exponent bits.
+    using info = dragonbox::float_info<double>;
+    auto br = bit_cast<uint64_t>(static_cast<double>(value));
+
+    const uint64_t significand_mask =
+        (static_cast<uint64_t>(1) << num_significand_bits<double>()) - 1;
+    uint64_t significand = (br & significand_mask);
+    int exponent = static_cast<int>((br & exponent_mask<double>()) >>
+                                    num_significand_bits<double>());
+
+    if (exponent != 0) {  // Check if normal.
+      exponent -= exponent_bias<double>() + num_significand_bits<double>();
+      significand |=
+          (static_cast<uint64_t>(1) << num_significand_bits<double>());
+      significand <<= 1;
     } else {
-      exp += handler.size - cached_exp10 - 1;
-      precision = handler.precision;
+      // Normalize subnormal inputs.
+      FMT_ASSERT(significand != 0, "zeros should not appear here");
+      int shift = countl_zero(significand);
+      FMT_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
+                 "");
+      shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
+      exponent = (std::numeric_limits<double>::min_exponent -
+                  num_significand_bits<double>()) -
+                 shift;
+      significand <<= shift;
+    }
+
+    // Compute the first several nonzero decimal significand digits.
+    // We call the number we get the first segment.
+    const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
+    exp = -k;
+    const int beta = exponent + dragonbox::floor_log2_pow10(k);
+    uint64_t first_segment;
+    bool has_more_segments;
+    int digits_in_the_first_segment;
+    {
+      const auto r = dragonbox::umul192_upper128(
+          significand << beta, dragonbox::get_cached_power(k));
+      first_segment = r.high();
+      has_more_segments = r.low() != 0;
+
+      // The first segment can have 18 ~ 19 digits.
+      if (first_segment >= 1000000000000000000ULL) {
+        digits_in_the_first_segment = 19;
+      } else {
+        // When it is of 18-digits, we align it to 19-digits by adding a bogus
+        // zero at the end.
+        digits_in_the_first_segment = 18;
+        first_segment *= 10;
+      }
+    }
+
+    // Compute the actual number of decimal digits to print.
+    if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
+
+    // Use Dragon4 only when there might be not enough digits in the first
+    // segment.
+    if (digits_in_the_first_segment > precision) {
+      use_dragon = false;
+
+      if (precision <= 0) {
+        exp += digits_in_the_first_segment;
+
+        if (precision < 0) {
+          // Nothing to do, since all we have are just leading zeros.
+          buf.try_resize(0);
+        } else {
+          // We may need to round-up.
+          buf.try_resize(1);
+          if ((first_segment | static_cast<uint64_t>(has_more_segments)) >
+              5000000000000000000ULL) {
+            buf[0] = '1';
+          } else {
+            buf[0] = '0';
+          }
+        }
+      }  // precision <= 0
+      else {
+        exp += digits_in_the_first_segment - precision;
+
+        // When precision > 0, we divide the first segment into three
+        // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits
+        // in 32-bits which usually allows faster calculation than in
+        // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize
+        // division-by-constant for large 64-bit divisors, we do it here
+        // manually. The magic number 7922816251426433760 below is equal to
+        // ceil(2^(64+32) / 10^10).
+        const uint32_t first_subsegment = static_cast<uint32_t>(
+            dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
+            32);
+        const uint64_t second_third_subsegments =
+            first_segment - first_subsegment * 10000000000ULL;
+
+        uint64_t prod;
+        uint32_t digits;
+        bool should_round_up;
+        int number_of_digits_to_print = precision > 9 ? 9 : precision;
+
+        // Print a 9-digits subsegment, either the first or the second.
+        auto print_subsegment = [&](uint32_t subsegment, char* buffer) {
+          int number_of_digits_printed = 0;
+
+          // If we want to print an odd number of digits from the subsegment,
+          if ((number_of_digits_to_print & 1) != 0) {
+            // Convert to 64-bit fixed-point fractional form with 1-digit
+            // integer part. The magic number 720575941 is a good enough
+            // approximation of 2^(32 + 24) / 10^8; see
+            // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case
+            // for details.
+            prod = ((subsegment * static_cast<uint64_t>(720575941)) >> 24) + 1;
+            digits = static_cast<uint32_t>(prod >> 32);
+            *buffer = static_cast<char>('0' + digits);
+            number_of_digits_printed++;
+          }
+          // If we want to print an even number of digits from the
+          // first_subsegment,
+          else {
+            // Convert to 64-bit fixed-point fractional form with 2-digits
+            // integer part. The magic number 450359963 is a good enough
+            // approximation of 2^(32 + 20) / 10^7; see
+            // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case
+            // for details.
+            prod = ((subsegment * static_cast<uint64_t>(450359963)) >> 20) + 1;
+            digits = static_cast<uint32_t>(prod >> 32);
+            copy2(buffer, digits2(digits));
+            number_of_digits_printed += 2;
+          }
+
+          // Print all digit pairs.
+          while (number_of_digits_printed < number_of_digits_to_print) {
+            prod = static_cast<uint32_t>(prod) * static_cast<uint64_t>(100);
+            digits = static_cast<uint32_t>(prod >> 32);
+            copy2(buffer + number_of_digits_printed, digits2(digits));
+            number_of_digits_printed += 2;
+          }
+        };
+
+        // Print first subsegment.
+        print_subsegment(first_subsegment, buf.data());
+
+        // Perform rounding if the first subsegment is the last subsegment to
+        // print.
+        if (precision <= 9) {
+          // Rounding inside the subsegment.
+          // We round-up if:
+          //  - either the fractional part is strictly larger than 1/2, or
+          //  - the fractional part is exactly 1/2 and the last digit is odd.
+          // We rely on the following observations:
+          //  - If fractional_part >= threshold, then the fractional part is
+          //    strictly larger than 1/2.
+          //  - If the MSB of fractional_part is set, then the fractional part
+          //    must be at least 1/2.
+          //  - When the MSB of fractional_part is set, either
+          //    second_third_subsegments being nonzero or has_more_segments
+          //    being true means there are further digits not printed, so the
+          //    fractional part is strictly larger than 1/2.
+          if (precision < 9) {
+            uint32_t fractional_part = static_cast<uint32_t>(prod);
+            should_round_up = fractional_part >=
+                                  data::fractional_part_rounding_thresholds
+                                      [8 - number_of_digits_to_print] ||
+                              ((fractional_part >> 31) &
+                               ((digits & 1) | (second_third_subsegments != 0) |
+                                has_more_segments)) != 0;
+          }
+          // Rounding at the subsegment boundary.
+          // In this case, the fractional part is at least 1/2 if and only if
+          // second_third_subsegments >= 5000000000ULL, and is strictly larger
+          // than 1/2 if we further have either second_third_subsegments >
+          // 5000000000ULL or has_more_segments == true.
+          else {
+            should_round_up = second_third_subsegments > 5000000000ULL ||
+                              (second_third_subsegments == 5000000000ULL &&
+                               ((digits & 1) != 0 || has_more_segments));
+          }
+        }
+        // Otherwise, print the second subsegment.
+        else {
+          // Compilers are not aware of how to leverage the maximum value of
+          // second_third_subsegments to find out a better magic number which
+          // allows us to eliminate an additional shift. 1844674407370955162 =
+          // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))).
+          const uint32_t second_subsegment =
+              static_cast<uint32_t>(dragonbox::umul128_upper64(
+                  second_third_subsegments, 1844674407370955162ULL));
+          const uint32_t third_subsegment =
+              static_cast<uint32_t>(second_third_subsegments) -
+              second_subsegment * 10;
+
+          number_of_digits_to_print = precision - 9;
+          print_subsegment(second_subsegment, buf.data() + 9);
+
+          // Rounding inside the subsegment.
+          if (precision < 18) {
+            // The condition third_subsegment != 0 implies that the segment was
+            // of 19 digits, so in this case the third segment should be
+            // consisting of a genuine digit from the input.
+            uint32_t fractional_part = static_cast<uint32_t>(prod);
+            should_round_up = fractional_part >=
+                                  data::fractional_part_rounding_thresholds
+                                      [8 - number_of_digits_to_print] ||
+                              ((fractional_part >> 31) &
+                               ((digits & 1) | (third_subsegment != 0) |
+                                has_more_segments)) != 0;
+          }
+          // Rounding at the subsegment boundary.
+          else {
+            // In this case, the segment must be of 19 digits, thus
+            // the third subsegment should be consisting of a genuine digit from
+            // the input.
+            should_round_up = third_subsegment > 5 ||
+                              (third_subsegment == 5 &&
+                               ((digits & 1) != 0 || has_more_segments));
+          }
+        }
+
+        // Round-up if necessary.
+        if (should_round_up) {
+          ++buf[precision - 1];
+          for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) {
+            buf[i] = '0';
+            ++buf[i - 1];
+          }
+          if (buf[0] > '9') {
+            buf[0] = '1';
+            if (fixed)
+              buf[precision++] = '0';
+            else
+              ++exp;
+          }
+        }
+        buf.try_resize(to_unsigned(precision));
+      }
+    }  // if (digits_in_the_first_segment > precision)
+    else {
+      // Adjust the exponent for its use in Dragon4.
+      exp += digits_in_the_first_segment - 1;
     }
   }
   if (use_dragon) {
@@ -3181,13 +3592,10 @@
   }
   return exp;
 }
-
-template <typename Char, typename OutputIt, typename T,
-          FMT_ENABLE_IF(is_floating_point<T>::value)>
-FMT_CONSTEXPR20 auto write(OutputIt out, T value,
-                           basic_format_specs<Char> specs, locale_ref loc = {})
+template <typename Char, typename OutputIt, typename T>
+FMT_CONSTEXPR20 auto write_float(OutputIt out, T value,
+                                 format_specs<Char> specs, locale_ref loc)
     -> OutputIt {
-  if (const_check(!is_supported_floating_point(value))) return out;
   float_specs fspecs = parse_float_type_spec(specs);
   fspecs.sign = specs.sign;
   if (detail::signbit(value)) {  // value < 0 is false for NaN so use signbit.
@@ -3211,7 +3619,7 @@
   memory_buffer buffer;
   if (fspecs.format == float_format::hex) {
     if (fspecs.sign) buffer.push_back(detail::sign<char>(fspecs.sign));
-    snprintf_float(convert_float(value), specs.precision, fspecs, buffer);
+    format_hexfloat(convert_float(value), specs.precision, fspecs, buffer);
     return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
                                      specs);
   }
@@ -3234,10 +3642,19 @@
 }
 
 template <typename Char, typename OutputIt, typename T,
+          FMT_ENABLE_IF(is_floating_point<T>::value)>
+FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs<Char> specs,
+                           locale_ref loc = {}) -> OutputIt {
+  if (const_check(!is_supported_floating_point(value))) return out;
+  return specs.localized && write_loc(out, value, specs, loc)
+             ? out
+             : write_float(out, value, specs, loc);
+}
+
+template <typename Char, typename OutputIt, typename T,
           FMT_ENABLE_IF(is_fast_float<T>::value)>
 FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
-  if (is_constant_evaluated())
-    return write(out, value, basic_format_specs<Char>());
+  if (is_constant_evaluated()) return write(out, value, format_specs<Char>());
   if (const_check(!is_supported_floating_point(value))) return out;
 
   auto fspecs = float_specs();
@@ -3246,11 +3663,11 @@
     value = -value;
   }
 
-  constexpr auto specs = basic_format_specs<Char>();
+  constexpr auto specs = format_specs<Char>();
   using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
-  using uint = typename dragonbox::float_info<floaty>::carrier_uint;
-  uint mask = exponent_mask<floaty>();
-  if ((bit_cast<uint>(value) & mask) == mask)
+  using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
+  floaty_uint mask = exponent_mask<floaty>();
+  if ((bit_cast<floaty_uint>(value) & mask) == mask)
     return write_nonfinite(out, std::isnan(value), specs, fspecs);
 
   auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
@@ -3261,12 +3678,12 @@
           FMT_ENABLE_IF(is_floating_point<T>::value &&
                         !is_fast_float<T>::value)>
 inline auto write(OutputIt out, T value) -> OutputIt {
-  return write(out, value, basic_format_specs<Char>());
+  return write(out, value, format_specs<Char>());
 }
 
 template <typename Char, typename OutputIt>
-auto write(OutputIt out, monostate, basic_format_specs<Char> = {},
-           locale_ref = {}) -> OutputIt {
+auto write(OutputIt out, monostate, format_specs<Char> = {}, locale_ref = {})
+    -> OutputIt {
   FMT_ASSERT(false, "");
   return out;
 }
@@ -3300,8 +3717,8 @@
 template <typename Char, typename OutputIt, typename T,
           FMT_ENABLE_IF(std::is_same<T, bool>::value)>
 FMT_CONSTEXPR auto write(OutputIt out, T value,
-                         const basic_format_specs<Char>& specs = {},
-                         locale_ref = {}) -> OutputIt {
+                         const format_specs<Char>& specs = {}, locale_ref = {})
+    -> OutputIt {
   return specs.type != presentation_type::none &&
                  specs.type != presentation_type::string
              ? write(out, value ? 1 : 0, specs, {})
@@ -3318,20 +3735,15 @@
 template <typename Char, typename OutputIt>
 FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value)
     -> OutputIt {
-  if (!value) {
-    throw_format_error("string pointer is null");
-  } else {
-    out = write(out, basic_string_view<Char>(value));
-  }
+  if (value) return write(out, basic_string_view<Char>(value));
+  throw_format_error("string pointer is null");
   return out;
 }
 
 template <typename Char, typename OutputIt, typename T,
           FMT_ENABLE_IF(std::is_same<T, void>::value)>
-auto write(OutputIt out, const T* value,
-           const basic_format_specs<Char>& specs = {}, locale_ref = {})
-    -> OutputIt {
-  check_pointer_type_spec(specs.type, error_handler());
+auto write(OutputIt out, const T* value, const format_specs<Char>& specs = {},
+           locale_ref = {}) -> OutputIt {
   return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
 }
 
@@ -3341,8 +3753,8 @@
 FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t<
     std::is_class<T>::value && !is_string<T>::value &&
         !is_floating_point<T>::value && !std::is_same<T, Char>::value &&
-        !std::is_same<const T&,
-                      decltype(arg_mapper<Context>().map(value))>::value,
+        !std::is_same<T, remove_cvref_t<decltype(arg_mapper<Context>().map(
+                             value))>>::value,
     OutputIt> {
   return write<Char>(out, arg_mapper<Context>().map(value));
 }
@@ -3352,12 +3764,8 @@
 FMT_CONSTEXPR auto write(OutputIt out, const T& value)
     -> enable_if_t<mapped_type_constant<T, Context>::value == type::custom_type,
                    OutputIt> {
-  using formatter_type =
-      conditional_t<has_formatter<T, Context>::value,
-                    typename Context::template formatter_type<T>,
-                    fallback_formatter<T, Char>>;
   auto ctx = Context(out, {}, {});
-  return formatter_type().format(value, ctx);
+  return typename Context::template formatter_type<T>().format(value, ctx);
 }
 
 // An argument visitor that formats the argument and writes it via the output
@@ -3386,7 +3794,7 @@
   using context = buffer_context<Char>;
 
   iterator out;
-  const basic_format_specs<Char>& specs;
+  const format_specs<Char>& specs;
   locale_ref locale;
 
   template <typename T>
@@ -3411,12 +3819,6 @@
   template <typename T> void operator()(T) const {}
 };
 
-template <typename T>
-using is_integer =
-    bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
-                  !std::is_same<T, char>::value &&
-                  !std::is_same<T, wchar_t>::value>;
-
 template <typename ErrorHandler> class width_checker {
  public:
   explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {}
@@ -3466,55 +3868,12 @@
 }
 
 template <typename Context, typename ID>
-FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) ->
-    typename Context::format_arg {
+FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) {
   auto arg = ctx.arg(id);
   if (!arg) ctx.on_error("argument not found");
   return arg;
 }
 
-// The standard format specifier handler with checking.
-template <typename Char> class specs_handler : public specs_setter<Char> {
- private:
-  basic_format_parse_context<Char>& parse_context_;
-  buffer_context<Char>& context_;
-
-  // This is only needed for compatibility with gcc 4.4.
-  using format_arg = basic_format_arg<buffer_context<Char>>;
-
-  FMT_CONSTEXPR auto get_arg(auto_id) -> format_arg {
-    return detail::get_arg(context_, parse_context_.next_arg_id());
-  }
-
-  FMT_CONSTEXPR auto get_arg(int arg_id) -> format_arg {
-    parse_context_.check_arg_id(arg_id);
-    return detail::get_arg(context_, arg_id);
-  }
-
-  FMT_CONSTEXPR auto get_arg(basic_string_view<Char> arg_id) -> format_arg {
-    parse_context_.check_arg_id(arg_id);
-    return detail::get_arg(context_, arg_id);
-  }
-
- public:
-  FMT_CONSTEXPR specs_handler(basic_format_specs<Char>& specs,
-                              basic_format_parse_context<Char>& parse_ctx,
-                              buffer_context<Char>& ctx)
-      : specs_setter<Char>(specs), parse_context_(parse_ctx), context_(ctx) {}
-
-  template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
-    this->specs_.width = get_dynamic_spec<width_checker>(
-        get_arg(arg_id), context_.error_handler());
-  }
-
-  template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
-    this->specs_.precision = get_dynamic_spec<precision_checker>(
-        get_arg(arg_id), context_.error_handler());
-  }
-
-  void on_error(const char* message) { context_.on_error(message); }
-};
-
 template <template <typename> class Handler, typename Context>
 FMT_CONSTEXPR void handle_dynamic_spec(int& value,
                                        arg_ref<typename Context::char_type> ref,
@@ -3523,26 +3882,17 @@
   case arg_id_kind::none:
     break;
   case arg_id_kind::index:
-    value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index),
+    value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.index),
                                               ctx.error_handler());
     break;
   case arg_id_kind::name:
-    value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name),
+    value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.name),
                                               ctx.error_handler());
     break;
   }
 }
 
 #if FMT_USE_USER_DEFINED_LITERALS
-template <typename Char> struct udl_formatter {
-  basic_string_view<Char> str;
-
-  template <typename... T>
-  auto operator()(T&&... args) const -> std::basic_string<Char> {
-    return vformat(str, fmt::make_format_args<buffer_context<Char>>(args...));
-  }
-};
-
 #  if FMT_USE_NONTYPE_TEMPLATE_ARGS
 template <typename T, typename Char, size_t N,
           fmt::detail_exported::fixed_string<Char, N> Str>
@@ -3581,12 +3931,12 @@
 #endif  // FMT_USE_USER_DEFINED_LITERALS
 
 template <typename Locale, typename Char>
-auto vformat(const Locale& loc, basic_string_view<Char> format_str,
+auto vformat(const Locale& loc, basic_string_view<Char> fmt,
              basic_format_args<buffer_context<type_identity_t<Char>>> args)
     -> std::basic_string<Char> {
-  basic_memory_buffer<Char> buffer;
-  detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
-  return {buffer.data(), buffer.size()};
+  auto buf = basic_memory_buffer<Char>();
+  detail::vformat_to(buf, fmt, args, detail::locale_ref(loc));
+  return {buf.data(), buf.size()};
 }
 
 using format_func = void (*)(detail::buffer<char>&, int, const char*);
@@ -3596,28 +3946,28 @@
 
 FMT_API void report_error(format_func func, int error_code,
                           const char* message) noexcept;
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
 FMT_API auto vsystem_error(int error_code, string_view format_str,
                            format_args args) -> std::system_error;
 
 /**
- \rst
- Constructs :class:`std::system_error` with a message formatted with
- ``fmt::format(fmt, args...)``.
+  \rst
+  Constructs :class:`std::system_error` with a message formatted with
+  ``fmt::format(fmt, args...)``.
   *error_code* is a system error code as given by ``errno``.
 
- **Example**::
+  **Example**::
 
-   // This throws std::system_error with the description
-   //   cannot open file 'madeup': No such file or directory
-   // or similar (system message may vary).
-   const char* filename = "madeup";
-   std::FILE* file = std::fopen(filename, "r");
-   if (!file)
-     throw fmt::system_error(errno, "cannot open file '{}'", filename);
- \endrst
-*/
+    // This throws std::system_error with the description
+    //   cannot open file 'madeup': No such file or directory
+    // or similar (system message may vary).
+    const char* filename = "madeup";
+    std::FILE* file = std::fopen(filename, "r");
+    if (!file)
+      throw fmt::system_error(errno, "cannot open file '{}'", filename);
+  \endrst
+ */
 template <typename... T>
 auto system_error(int error_code, format_string<T...> fmt, T&&... args)
     -> std::system_error {
@@ -3708,93 +4058,35 @@
 };
 
 template <typename T, typename Char>
-template <typename FormatContext>
-FMT_CONSTEXPR FMT_INLINE auto
-formatter<T, Char,
-          enable_if_t<detail::type_constant<T, Char>::value !=
-                      detail::type::custom_type>>::format(const T& val,
-                                                          FormatContext& ctx)
-    const -> decltype(ctx.out()) {
-  if (specs_.width_ref.kind != detail::arg_id_kind::none ||
-      specs_.precision_ref.kind != detail::arg_id_kind::none) {
-    auto specs = specs_;
-    detail::handle_dynamic_spec<detail::width_checker>(specs.width,
-                                                       specs.width_ref, ctx);
-    detail::handle_dynamic_spec<detail::precision_checker>(
-        specs.precision, specs.precision_ref, ctx);
-    return detail::write<Char>(ctx.out(), val, specs, ctx.locale());
-  }
-  return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
-}
+struct formatter<T, Char, enable_if_t<detail::has_format_as<T>::value>>
+    : private formatter<detail::format_as_t<T>, Char> {
+  using base = formatter<detail::format_as_t<T>, Char>;
+  using base::parse;
 
-template <typename Char>
-struct formatter<void*, Char> : formatter<const void*, Char> {
   template <typename FormatContext>
-  auto format(void* val, FormatContext& ctx) const -> decltype(ctx.out()) {
-    return formatter<const void*, Char>::format(val, ctx);
+  auto format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) {
+    return base::format(format_as(value), ctx);
   }
 };
 
+#define FMT_FORMAT_AS(Type, Base) \
+  template <typename Char>        \
+  struct formatter<Type, Char> : formatter<Base, Char> {}
+
+FMT_FORMAT_AS(signed char, int);
+FMT_FORMAT_AS(unsigned char, unsigned);
+FMT_FORMAT_AS(short, int);
+FMT_FORMAT_AS(unsigned short, unsigned);
+FMT_FORMAT_AS(long, detail::long_type);
+FMT_FORMAT_AS(unsigned long, detail::ulong_type);
+FMT_FORMAT_AS(Char*, const Char*);
+FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
+FMT_FORMAT_AS(std::nullptr_t, const void*);
+FMT_FORMAT_AS(detail::std_string_view<Char>, basic_string_view<Char>);
+FMT_FORMAT_AS(void*, const void*);
+
 template <typename Char, size_t N>
-struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
-  template <typename FormatContext>
-  FMT_CONSTEXPR auto format(const Char* val, FormatContext& ctx) const
-      -> decltype(ctx.out()) {
-    return formatter<basic_string_view<Char>, Char>::format(val, ctx);
-  }
-};
-
-// A formatter for types known only at run time such as variant alternatives.
-//
-// Usage:
-//   using variant = std::variant<int, std::string>;
-//   template <>
-//   struct formatter<variant>: dynamic_formatter<> {
-//     auto format(const variant& v, format_context& ctx) {
-//       return visit([&](const auto& val) {
-//           return dynamic_formatter<>::format(val, ctx);
-//       }, v);
-//     }
-//   };
-template <typename Char = char> class dynamic_formatter {
- private:
-  detail::dynamic_format_specs<Char> specs_;
-  const Char* format_str_;
-
-  struct null_handler : detail::error_handler {
-    void on_align(align_t) {}
-    void on_sign(sign_t) {}
-    void on_hash() {}
-  };
-
-  template <typename Context> void handle_specs(Context& ctx) {
-    detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
-                                                       specs_.width_ref, ctx);
-    detail::handle_dynamic_spec<detail::precision_checker>(
-        specs_.precision, specs_.precision_ref, ctx);
-  }
-
- public:
-  template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    format_str_ = ctx.begin();
-    // Checks are deferred to formatting time when the argument type is known.
-    detail::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
-    return detail::parse_format_specs(ctx.begin(), ctx.end(), handler);
-  }
-
-  template <typename T, typename FormatContext>
-  auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
-    handle_specs(ctx);
-    detail::specs_checker<null_handler> checker(
-        null_handler(), detail::mapped_type_constant<T, FormatContext>::value);
-    checker.on_align(specs_.align);
-    if (specs_.sign != sign::none) checker.on_sign(specs_.sign);
-    if (specs_.alt) checker.on_hash();
-    if (specs_.precision >= 0) checker.end_precision();
-    return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
-  }
-};
+struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {};
 
 /**
   \rst
@@ -3809,7 +4101,8 @@
   static_assert(std::is_pointer<T>::value, "");
   return detail::bit_cast<const void*>(p);
 }
-template <typename T> auto ptr(const std::unique_ptr<T>& p) -> const void* {
+template <typename T, typename Deleter>
+auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
   return p.get();
 }
 template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
@@ -3849,17 +4142,13 @@
 
 template <> struct formatter<bytes> {
  private:
-  detail::dynamic_format_specs<char> specs_;
+  detail::dynamic_format_specs<> specs_;
 
  public:
   template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    using handler_type = detail::dynamic_specs_handler<ParseContext>;
-    detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
-                                                detail::type::string_type);
-    auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
-    detail::check_string_type_spec(specs_.type, ctx.error_handler());
-    return it;
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* {
+    return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
+                              detail::type::string_type);
   }
 
   template <typename FormatContext>
@@ -3873,7 +4162,9 @@
 };
 
 // group_digits_view is not derived from view because it copies the argument.
-template <typename T> struct group_digits_view { T value; };
+template <typename T> struct group_digits_view {
+  T value;
+};
 
 /**
   \rst
@@ -3892,17 +4183,13 @@
 
 template <typename T> struct formatter<group_digits_view<T>> : formatter<T> {
  private:
-  detail::dynamic_format_specs<char> specs_;
+  detail::dynamic_format_specs<> specs_;
 
  public:
   template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    using handler_type = detail::dynamic_specs_handler<ParseContext>;
-    detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
-                                                detail::type::int_type);
-    auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
-    detail::check_string_type_spec(specs_.type, ctx.error_handler());
-    return it;
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* {
+    return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
+                              detail::type::int_type);
   }
 
   template <typename FormatContext>
@@ -3912,12 +4199,13 @@
                                                        specs_.width_ref, ctx);
     detail::handle_dynamic_spec<detail::precision_checker>(
         specs_.precision, specs_.precision_ref, ctx);
-    return detail::write_int_localized(
+    return detail::write_int(
         ctx.out(), static_cast<detail::uint64_or_128_t<T>>(t.value), 0, specs_,
-        detail::digit_grouping<char>({"\3", ','}));
+        detail::digit_grouping<char>("\3", ","));
   }
 };
 
+// DEPRECATED! join_view will be moved to ranges.h.
 template <typename It, typename Sentinel, typename Char = char>
 struct join_view : detail::view {
   It begin;
@@ -3937,30 +4225,11 @@
 #else
       typename std::iterator_traits<It>::value_type;
 #endif
-  using context = buffer_context<Char>;
-  using mapper = detail::arg_mapper<context>;
-
-  template <typename T, FMT_ENABLE_IF(has_formatter<T, context>::value)>
-  static auto map(const T& value) -> const T& {
-    return value;
-  }
-  template <typename T, FMT_ENABLE_IF(!has_formatter<T, context>::value)>
-  static auto map(const T& value) -> decltype(mapper().map(value)) {
-    return mapper().map(value);
-  }
-
-  using formatter_type =
-      conditional_t<is_formattable<value_type, Char>::value,
-                    formatter<remove_cvref_t<decltype(map(
-                                  std::declval<const value_type&>()))>,
-                              Char>,
-                    detail::fallback_formatter<value_type, Char>>;
-
-  formatter_type value_formatter_;
+  formatter<remove_cvref_t<value_type>, Char> value_formatter_;
 
  public:
   template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
     return value_formatter_.parse(ctx);
   }
 
@@ -3970,12 +4239,12 @@
     auto it = value.begin;
     auto out = ctx.out();
     if (it != value.end) {
-      out = value_formatter_.format(map(*it), ctx);
+      out = value_formatter_.format(*it, ctx);
       ++it;
       while (it != value.end) {
         out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out);
         ctx.advance_to(out);
-        out = value_formatter_.format(map(*it), ctx);
+        out = value_formatter_.format(*it, ctx);
         ++it;
       }
     }
@@ -4025,11 +4294,12 @@
     std::string answer = fmt::to_string(42);
   \endrst
  */
-template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
+template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
+                                    !detail::has_format_as<T>::value)>
 inline auto to_string(const T& value) -> std::string {
-  auto result = std::string();
-  detail::write<char>(std::back_inserter(result), value);
-  return result;
+  auto buffer = memory_buffer();
+  detail::write<char>(appender(buffer), value);
+  return {buffer.data(), buffer.size()};
 }
 
 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
@@ -4050,27 +4320,19 @@
   return std::basic_string<Char>(buf.data(), size);
 }
 
-FMT_BEGIN_DETAIL_NAMESPACE
+template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
+                                    detail::has_format_as<T>::value)>
+inline auto to_string(const T& value) -> std::string {
+  return to_string(format_as(value));
+}
+
+FMT_END_EXPORT
+
+namespace detail {
 
 template <typename Char>
-void vformat_to(
-    buffer<Char>& buf, basic_string_view<Char> fmt,
-    basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
-    locale_ref loc) {
-  // workaround for msvc bug regarding name-lookup in module
-  // link names into function scope
-  using detail::arg_formatter;
-  using detail::buffer_appender;
-  using detail::custom_formatter;
-  using detail::default_arg_formatter;
-  using detail::get_arg;
-  using detail::locale_ref;
-  using detail::parse_format_specs;
-  using detail::specs_checker;
-  using detail::specs_handler;
-  using detail::to_unsigned;
-  using detail::type;
-  using detail::write;
+void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
+                typename vformat_args<Char>::type args, locale_ref loc) {
   auto out = buffer_appender<Char>(buf);
   if (fmt.size() == 2 && equal2(fmt.data(), "{}")) {
     auto arg = args.get(0);
@@ -4117,15 +4379,16 @@
         -> const Char* {
       auto arg = get_arg(context, id);
       if (arg.type() == type::custom_type) {
-        parse_context.advance_to(parse_context.begin() +
-                                 (begin - &*parse_context.begin()));
+        parse_context.advance_to(begin);
         visit_format_arg(custom_formatter<Char>{parse_context, context}, arg);
         return parse_context.begin();
       }
-      auto specs = basic_format_specs<Char>();
-      specs_checker<specs_handler<Char>> handler(
-          specs_handler<Char>(specs, parse_context, context), arg.type());
-      begin = parse_format_specs(begin, end, handler);
+      auto specs = detail::dynamic_format_specs<Char>();
+      begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
+      detail::handle_dynamic_spec<detail::width_checker>(
+          specs.width, specs.width_ref, context);
+      detail::handle_dynamic_spec<detail::precision_checker>(
+          specs.precision, specs.precision_ref, context);
       if (begin == end || *begin != '}')
         on_error("missing '}' in format string");
       auto f = arg_formatter<Char>{context.out(), specs, context.locale()};
@@ -4136,7 +4399,12 @@
   detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
 }
 
+FMT_BEGIN_EXPORT
+
 #ifndef FMT_HEADER_ONLY
+extern template FMT_API void vformat_to(buffer<char>&, string_view,
+                                        typename vformat_args<>::type,
+                                        locale_ref);
 extern template FMT_API auto thousands_sep_impl<char>(locale_ref)
     -> thousands_sep_result<char>;
 extern template FMT_API auto thousands_sep_impl<wchar_t>(locale_ref)
@@ -4145,7 +4413,7 @@
 extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
 #endif  // FMT_HEADER_ONLY
 
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
 #if FMT_USE_USER_DEFINED_LITERALS
 inline namespace literals {
@@ -4182,7 +4450,7 @@
           FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
 inline auto format(const Locale& loc, format_string<T...> fmt, T&&... args)
     -> std::string {
-  return vformat(loc, string_view(fmt), fmt::make_format_args(args...));
+  return fmt::vformat(loc, string_view(fmt), fmt::make_format_args(args...));
 }
 
 template <typename OutputIt, typename Locale,
@@ -4193,7 +4461,7 @@
   using detail::get_buffer;
   auto&& buf = get_buffer<char>(out);
   detail::vformat_to(buf, fmt, args, detail::locale_ref(loc));
-  return detail::get_iterator(buf);
+  return detail::get_iterator(buf, out);
 }
 
 template <typename OutputIt, typename Locale, typename... T,
@@ -4204,7 +4472,39 @@
   return vformat_to(out, loc, fmt, fmt::make_format_args(args...));
 }
 
-FMT_MODULE_EXPORT_END
+template <typename Locale, typename... T,
+          FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
+FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc,
+                                             format_string<T...> fmt,
+                                             T&&... args) -> size_t {
+  auto buf = detail::counting_buffer<>();
+  detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...),
+                           detail::locale_ref(loc));
+  return buf.count();
+}
+
+FMT_END_EXPORT
+
+template <typename T, typename Char>
+template <typename FormatContext>
+FMT_CONSTEXPR FMT_INLINE auto
+formatter<T, Char,
+          enable_if_t<detail::type_constant<T, Char>::value !=
+                      detail::type::custom_type>>::format(const T& val,
+                                                          FormatContext& ctx)
+    const -> decltype(ctx.out()) {
+  if (specs_.width_ref.kind != detail::arg_id_kind::none ||
+      specs_.precision_ref.kind != detail::arg_id_kind::none) {
+    auto specs = specs_;
+    detail::handle_dynamic_spec<detail::width_checker>(specs.width,
+                                                       specs.width_ref, ctx);
+    detail::handle_dynamic_spec<detail::precision_checker>(
+        specs.precision, specs.precision_ref, ctx);
+    return detail::write<Char>(ctx.out(), val, specs, ctx.locale());
+  }
+  return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
+}
+
 FMT_END_NAMESPACE
 
 #ifdef FMT_HEADER_ONLY
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
index d82be11..2126424 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
@@ -71,7 +71,7 @@
 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
 
 FMT_BEGIN_NAMESPACE
-FMT_MODULE_EXPORT_BEGIN
+FMT_BEGIN_EXPORT
 
 /**
   \rst
@@ -120,51 +120,13 @@
 using cstring_view = basic_cstring_view<char>;
 using wcstring_view = basic_cstring_view<wchar_t>;
 
-template <typename Char> struct formatter<std::error_code, Char> {
-  template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    return ctx.begin();
-  }
-
-  template <typename FormatContext>
-  FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-      -> decltype(ctx.out()) {
-    auto out = ctx.out();
-    out = detail::write_bytes(out, ec.category().name(),
-                              basic_format_specs<Char>());
-    out = detail::write<Char>(out, Char(':'));
-    out = detail::write<Char>(out, ec.value());
-    return out;
-  }
-};
-
 #ifdef _WIN32
 FMT_API const std::error_category& system_category() noexcept;
 
-FMT_BEGIN_DETAIL_NAMESPACE
-// A converter from UTF-16 to UTF-8.
-// It is only provided for Windows since other systems support UTF-8 natively.
-class utf16_to_utf8 {
- private:
-  memory_buffer buffer_;
-
- public:
-  utf16_to_utf8() {}
-  FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s);
-  operator string_view() const { return string_view(&buffer_[0], size()); }
-  size_t size() const { return buffer_.size() - 1; }
-  const char* c_str() const { return &buffer_[0]; }
-  std::string str() const { return std::string(&buffer_[0], size()); }
-
-  // Performs conversion returning a system error code instead of
-  // throwing exception on conversion error. This method may still throw
-  // in case of memory allocation error.
-  FMT_API int convert(basic_string_view<wchar_t> s);
-};
-
+namespace detail {
 FMT_API void format_windows_error(buffer<char>& out, int error_code,
                                   const char* message) noexcept;
-FMT_END_DETAIL_NAMESPACE
+}
 
 FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
                                          format_args args);
@@ -355,12 +317,18 @@
   // Creates a buffered_file object associated with this file and detaches
   // this file object from the file.
   buffered_file fdopen(const char* mode);
+
+#  if defined(_WIN32) && !defined(__MINGW32__)
+  // Opens a file and constructs a file object representing this file by
+  // wcstring_view filename. Windows only.
+  static file open_windows_file(wcstring_view path, int oflag);
+#  endif
 };
 
 // Returns the memory page size.
 long getpagesize();
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 struct buffer_size {
   buffer_size() = default;
@@ -397,56 +365,61 @@
 #  endif
 };
 
-FMT_END_DETAIL_NAMESPACE
+class file_buffer final : public buffer<char> {
+  file file_;
+
+  FMT_API void grow(size_t) override;
+
+ public:
+  FMT_API file_buffer(cstring_view path, const ostream_params& params);
+  FMT_API file_buffer(file_buffer&& other);
+  FMT_API ~file_buffer();
+
+  void flush() {
+    if (size() == 0) return;
+    file_.write(data(), size() * sizeof(data()[0]));
+    clear();
+  }
+
+  void close() {
+    flush();
+    file_.close();
+  }
+};
+
+}  // namespace detail
 
 // Added {} below to work around default constructor error known to
 // occur in Xcode versions 7.2.1 and 8.2.1.
 constexpr detail::buffer_size buffer_size{};
 
 /** A fast output stream which is not thread-safe. */
-class FMT_API ostream final : private detail::buffer<char> {
+class FMT_API ostream {
  private:
-  file file_;
-
-  void grow(size_t) override;
+  FMT_MSC_WARNING(suppress : 4251)
+  detail::file_buffer buffer_;
 
   ostream(cstring_view path, const detail::ostream_params& params)
-      : file_(path, params.oflag) {
-    set(new char[params.buffer_size], params.buffer_size);
-  }
+      : buffer_(path, params) {}
 
  public:
-  ostream(ostream&& other)
-      : detail::buffer<char>(other.data(), other.size(), other.capacity()),
-        file_(std::move(other.file_)) {
-    other.clear();
-    other.set(nullptr, 0);
-  }
-  ~ostream() {
-    flush();
-    delete[] data();
-  }
+  ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {}
 
-  void flush() {
-    if (size() == 0) return;
-    file_.write(data(), size());
-    clear();
-  }
+  ~ostream();
+
+  void flush() { buffer_.flush(); }
 
   template <typename... T>
   friend ostream output_file(cstring_view path, T... params);
 
-  void close() {
-    flush();
-    file_.close();
-  }
+  void close() { buffer_.close(); }
 
   /**
     Formats ``args`` according to specifications in ``fmt`` and writes the
     output to the file.
    */
   template <typename... T> void print(format_string<T...> fmt, T&&... args) {
-    vformat_to(detail::buffer_appender<char>(*this), fmt,
+    vformat_to(detail::buffer_appender<char>(buffer_), fmt,
                fmt::make_format_args(args...));
   }
 };
@@ -472,7 +445,7 @@
 }
 #endif  // FMT_USE_FCNTL
 
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_OS_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
index c3cdd4a..a112fe7 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
@@ -8,8 +8,8 @@
 #ifndef FMT_OSTREAM_H_
 #define FMT_OSTREAM_H_
 
-#include <fstream>
-#include <ostream>
+#include <fstream>  // std::filebuf
+
 #if defined(_WIN32) && defined(__GLIBCXX__)
 #  include <ext/stdio_filebuf.h>
 #  include <ext/stdio_sync_filebuf.h>
@@ -21,48 +21,14 @@
 
 FMT_BEGIN_NAMESPACE
 
-template <typename OutputIt, typename Char> class basic_printf_context;
-
 namespace detail {
 
-// Checks if T has a user-defined operator<<.
-template <typename T, typename Char, typename Enable = void>
-class is_streamable {
- private:
-  template <typename U>
-  static auto test(int)
-      -> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
-                              << std::declval<U>()) != 0>;
-
-  template <typename> static auto test(...) -> std::false_type;
-
-  using result = decltype(test<T>(0));
-
- public:
-  is_streamable() = default;
-
-  static const bool value = result::value;
-};
-
-// Formatting of built-in types and arrays is intentionally disabled because
-// it's handled by standard (non-ostream) formatters.
-template <typename T, typename Char>
-struct is_streamable<
-    T, Char,
-    enable_if_t<
-        std::is_arithmetic<T>::value || std::is_array<T>::value ||
-        std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
-        std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
-        std::is_same<T, std_string_view<Char>>::value ||
-        (std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
-    : std::false_type {};
-
 // Generate a unique explicit instantion in every translation unit using a tag
 // type in an anonymous namespace.
 namespace {
 struct file_access_tag {};
 }  // namespace
-template <class Tag, class BufType, FILE* BufType::*FileMemberPtr>
+template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
 class file_access {
   friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
 };
@@ -84,8 +50,8 @@
 #elif defined(_WIN32) && defined(__GLIBCXX__)
   auto* rdbuf = os.rdbuf();
   FILE* c_file;
-  if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
-    c_file = fbuf->file();
+  if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
+    c_file = sfbuf->file();
   else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
     c_file = fbuf->file();
   else
@@ -145,7 +111,7 @@
   auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
       -> OutputIt {
     auto buffer = basic_memory_buffer<Char>();
-    format_value(buffer, value, ctx.locale());
+    detail::format_value(buffer, value, ctx.locale());
     return formatter<basic_string_view<Char>, Char>::format(
         {buffer.data(), buffer.size()}, ctx);
   }
@@ -180,13 +146,6 @@
 
 namespace detail {
 
-// Formats an object of type T that has an overloaded ostream operator<<.
-template <typename T, typename Char>
-struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
-    : basic_ostream_formatter<Char> {
-  using basic_ostream_formatter<Char>::format;
-};
-
 inline void vprint_directly(std::ostream& os, string_view format_str,
                             format_args args) {
   auto buffer = memory_buffer();
@@ -196,7 +155,7 @@
 
 }  // namespace detail
 
-FMT_MODULE_EXPORT template <typename Char>
+FMT_EXPORT template <typename Char>
 void vprint(std::basic_ostream<Char>& os,
             basic_string_view<type_identity_t<Char>> format_str,
             basic_format_args<buffer_context<type_identity_t<Char>>> args) {
@@ -215,7 +174,7 @@
     fmt::print(cerr, "Don't {}!", "panic");
   \endrst
  */
-FMT_MODULE_EXPORT template <typename... T>
+FMT_EXPORT template <typename... T>
 void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
   const auto& vargs = fmt::make_format_args(args...);
   if (detail::is_utf8())
@@ -224,7 +183,7 @@
     detail::vprint_directly(os, fmt, vargs);
 }
 
-FMT_MODULE_EXPORT
+FMT_EXPORT
 template <typename... Args>
 void print(std::wostream& os,
            basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
@@ -232,6 +191,19 @@
   vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
 }
 
+FMT_EXPORT template <typename... T>
+void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
+  fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
+}
+
+FMT_EXPORT
+template <typename... Args>
+void println(std::wostream& os,
+             basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
+             Args&&... args) {
+  print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
+}
+
 FMT_END_NAMESPACE
 
 #endif  // FMT_OSTREAM_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
index 70a592d..adef6ad 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
@@ -14,24 +14,18 @@
 #include "format.h"
 
 FMT_BEGIN_NAMESPACE
-FMT_MODULE_EXPORT_BEGIN
+FMT_BEGIN_EXPORT
 
 template <typename T> struct printf_formatter { printf_formatter() = delete; };
 
-template <typename Char>
-class basic_printf_parse_context : public basic_format_parse_context<Char> {
-  using basic_format_parse_context<Char>::basic_format_parse_context;
-};
-
-template <typename OutputIt, typename Char> class basic_printf_context {
+template <typename Char> class basic_printf_context {
  private:
-  OutputIt out_;
+  detail::buffer_appender<Char> out_;
   basic_format_args<basic_printf_context> args_;
 
  public:
   using char_type = Char;
-  using format_arg = basic_format_arg<basic_printf_context>;
-  using parse_context_type = basic_printf_parse_context<Char>;
+  using parse_context_type = basic_format_parse_context<Char>;
   template <typename T> using formatter_type = printf_formatter<T>;
 
   /**
@@ -40,68 +34,68 @@
     stored in the context object so make sure they have appropriate lifetimes.
     \endrst
    */
-  basic_printf_context(OutputIt out,
+  basic_printf_context(detail::buffer_appender<Char> out,
                        basic_format_args<basic_printf_context> args)
       : out_(out), args_(args) {}
 
-  OutputIt out() { return out_; }
-  void advance_to(OutputIt it) { out_ = it; }
+  auto out() -> detail::buffer_appender<Char> { return out_; }
+  void advance_to(detail::buffer_appender<Char>) {}
 
-  detail::locale_ref locale() { return {}; }
+  auto locale() -> detail::locale_ref { return {}; }
 
-  format_arg arg(int id) const { return args_.get(id); }
+  auto arg(int id) const -> basic_format_arg<basic_printf_context> {
+    return args_.get(id);
+  }
 
   FMT_CONSTEXPR void on_error(const char* message) {
     detail::error_handler().on_error(message);
   }
 };
 
-FMT_BEGIN_DETAIL_NAMESPACE
+namespace detail {
 
 // Checks if a value fits in int - used to avoid warnings about comparing
 // signed and unsigned integers.
 template <bool IsSigned> struct int_checker {
-  template <typename T> static bool fits_in_int(T value) {
+  template <typename T> static auto fits_in_int(T value) -> bool {
     unsigned max = max_value<int>();
     return value <= max;
   }
-  static bool fits_in_int(bool) { return true; }
+  static auto fits_in_int(bool) -> bool { return true; }
 };
 
 template <> struct int_checker<true> {
-  template <typename T> static bool fits_in_int(T value) {
+  template <typename T> static auto fits_in_int(T value) -> bool {
     return value >= (std::numeric_limits<int>::min)() &&
            value <= max_value<int>();
   }
-  static bool fits_in_int(int) { return true; }
+  static auto fits_in_int(int) -> bool { return true; }
 };
 
-class printf_precision_handler {
- public:
+struct printf_precision_handler {
   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
-  int operator()(T value) {
+  auto operator()(T value) -> int {
     if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
-      FMT_THROW(format_error("number is too big"));
+      throw_format_error("number is too big");
     return (std::max)(static_cast<int>(value), 0);
   }
 
   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
-  int operator()(T) {
-    FMT_THROW(format_error("precision is not integer"));
+  auto operator()(T) -> int {
+    throw_format_error("precision is not integer");
     return 0;
   }
 };
 
 // An argument visitor that returns true iff arg is a zero integer.
-class is_zero_int {
- public:
+struct is_zero_int {
   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
-  bool operator()(T value) {
+  auto operator()(T value) -> bool {
     return value == 0;
   }
 
   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
-  bool operator()(T) {
+  auto operator()(T) -> bool {
     return false;
   }
 };
@@ -132,22 +126,23 @@
     if (const_check(sizeof(target_type) <= sizeof(int))) {
       // Extra casts are used to silence warnings.
       if (is_signed) {
-        arg_ = detail::make_arg<Context>(
-            static_cast<int>(static_cast<target_type>(value)));
+        auto n = static_cast<int>(static_cast<target_type>(value));
+        arg_ = detail::make_arg<Context>(n);
       } else {
         using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
-        arg_ = detail::make_arg<Context>(
-            static_cast<unsigned>(static_cast<unsigned_type>(value)));
+        auto n = static_cast<unsigned>(static_cast<unsigned_type>(value));
+        arg_ = detail::make_arg<Context>(n);
       }
     } else {
       if (is_signed) {
         // glibc's printf doesn't sign extend arguments of smaller types:
         //   std::printf("%lld", -42);  // prints "4294967254"
         // but we don't have to do the same because it's a UB.
-        arg_ = detail::make_arg<Context>(static_cast<long long>(value));
+        auto n = static_cast<long long>(value);
+        arg_ = detail::make_arg<Context>(n);
       } else {
-        arg_ = detail::make_arg<Context>(
-            static_cast<typename make_unsigned_or_bool<U>::type>(value));
+        auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value);
+        arg_ = detail::make_arg<Context>(n);
       }
     }
   }
@@ -175,8 +170,8 @@
 
   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
   void operator()(T value) {
-    arg_ = detail::make_arg<Context>(
-        static_cast<typename Context::char_type>(value));
+    auto c = static_cast<typename Context::char_type>(value);
+    arg_ = detail::make_arg<Context>(c);
   }
 
   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
@@ -186,122 +181,131 @@
 // An argument visitor that return a pointer to a C string if argument is a
 // string or null otherwise.
 template <typename Char> struct get_cstring {
-  template <typename T> const Char* operator()(T) { return nullptr; }
-  const Char* operator()(const Char* s) { return s; }
+  template <typename T> auto operator()(T) -> const Char* { return nullptr; }
+  auto operator()(const Char* s) -> const Char* { return s; }
 };
 
 // Checks if an argument is a valid printf width specifier and sets
 // left alignment if it is negative.
 template <typename Char> class printf_width_handler {
  private:
-  using format_specs = basic_format_specs<Char>;
-
-  format_specs& specs_;
+  format_specs<Char>& specs_;
 
  public:
-  explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
+  explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {}
 
   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
-  unsigned operator()(T value) {
+  auto operator()(T value) -> unsigned {
     auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
     if (detail::is_negative(value)) {
       specs_.align = align::left;
       width = 0 - width;
     }
     unsigned int_max = max_value<int>();
-    if (width > int_max) FMT_THROW(format_error("number is too big"));
+    if (width > int_max) throw_format_error("number is too big");
     return static_cast<unsigned>(width);
   }
 
   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
-  unsigned operator()(T) {
-    FMT_THROW(format_error("width is not integer"));
+  auto operator()(T) -> unsigned {
+    throw_format_error("width is not integer");
     return 0;
   }
 };
 
+// Workaround for a bug with the XL compiler when initializing
+// printf_arg_formatter's base class.
+template <typename Char>
+auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s)
+    -> arg_formatter<Char> {
+  return {iter, s, locale_ref()};
+}
+
 // The ``printf`` argument formatter.
-template <typename OutputIt, typename Char>
+template <typename Char>
 class printf_arg_formatter : public arg_formatter<Char> {
  private:
   using base = arg_formatter<Char>;
-  using context_type = basic_printf_context<OutputIt, Char>;
-  using format_specs = basic_format_specs<Char>;
+  using context_type = basic_printf_context<Char>;
 
   context_type& context_;
 
-  OutputIt write_null_pointer(bool is_string = false) {
+  void write_null_pointer(bool is_string = false) {
     auto s = this->specs;
     s.type = presentation_type::none;
-    return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
+    write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
   }
 
  public:
-  printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
-      : base{iter, s, locale_ref()}, context_(ctx) {}
+  printf_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s,
+                       context_type& ctx)
+      : base(make_arg_formatter(iter, s)), context_(ctx) {}
 
-  OutputIt operator()(monostate value) { return base::operator()(value); }
+  void operator()(monostate value) { base::operator()(value); }
 
   template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
-  OutputIt operator()(T value) {
+  void operator()(T value) {
     // MSVC2013 fails to compile separate overloads for bool and Char so use
     // std::is_same instead.
-    if (std::is_same<T, Char>::value) {
-      format_specs fmt_specs = this->specs;
-      if (fmt_specs.type != presentation_type::none &&
-          fmt_specs.type != presentation_type::chr) {
-        return (*this)(static_cast<int>(value));
-      }
-      fmt_specs.sign = sign::none;
-      fmt_specs.alt = false;
-      fmt_specs.fill[0] = ' ';  // Ignore '0' flag for char types.
-      // align::numeric needs to be overwritten here since the '0' flag is
-      // ignored for non-numeric types
-      if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
-        fmt_specs.align = align::right;
-      return write<Char>(this->out, static_cast<Char>(value), fmt_specs);
+    if (!std::is_same<T, Char>::value) {
+      base::operator()(value);
+      return;
     }
-    return base::operator()(value);
+    format_specs<Char> fmt_specs = this->specs;
+    if (fmt_specs.type != presentation_type::none &&
+        fmt_specs.type != presentation_type::chr) {
+      return (*this)(static_cast<int>(value));
+    }
+    fmt_specs.sign = sign::none;
+    fmt_specs.alt = false;
+    fmt_specs.fill[0] = ' ';  // Ignore '0' flag for char types.
+    // align::numeric needs to be overwritten here since the '0' flag is
+    // ignored for non-numeric types
+    if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
+      fmt_specs.align = align::right;
+    write<Char>(this->out, static_cast<Char>(value), fmt_specs);
   }
 
   template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
-  OutputIt operator()(T value) {
-    return base::operator()(value);
+  void operator()(T value) {
+    base::operator()(value);
   }
 
   /** Formats a null-terminated C string. */
-  OutputIt operator()(const char* value) {
-    if (value) return base::operator()(value);
-    return write_null_pointer(this->specs.type != presentation_type::pointer);
+  void operator()(const char* value) {
+    if (value)
+      base::operator()(value);
+    else
+      write_null_pointer(this->specs.type != presentation_type::pointer);
   }
 
   /** Formats a null-terminated wide C string. */
-  OutputIt operator()(const wchar_t* value) {
-    if (value) return base::operator()(value);
-    return write_null_pointer(this->specs.type != presentation_type::pointer);
+  void operator()(const wchar_t* value) {
+    if (value)
+      base::operator()(value);
+    else
+      write_null_pointer(this->specs.type != presentation_type::pointer);
   }
 
-  OutputIt operator()(basic_string_view<Char> value) {
-    return base::operator()(value);
-  }
+  void operator()(basic_string_view<Char> value) { base::operator()(value); }
 
   /** Formats a pointer. */
-  OutputIt operator()(const void* value) {
-    return value ? base::operator()(value) : write_null_pointer();
+  void operator()(const void* value) {
+    if (value)
+      base::operator()(value);
+    else
+      write_null_pointer();
   }
 
   /** Formats an argument of a custom (user-defined) type. */
-  OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
-    auto parse_ctx =
-        basic_printf_parse_context<Char>(basic_string_view<Char>());
+  void operator()(typename basic_format_arg<context_type>::handle handle) {
+    auto parse_ctx = basic_format_parse_context<Char>({});
     handle.format(parse_ctx, context_);
-    return this->out;
   }
 };
 
 template <typename Char>
-void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
-                 const Char* end) {
+void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
   for (; it != end; ++it) {
     switch (*it) {
     case '-':
@@ -314,9 +318,7 @@
       specs.fill[0] = '0';
       break;
     case ' ':
-      if (specs.sign != sign::plus) {
-        specs.sign = sign::space;
-      }
+      if (specs.sign != sign::plus) specs.sign = sign::space;
       break;
     case '#':
       specs.alt = true;
@@ -328,8 +330,8 @@
 }
 
 template <typename Char, typename GetArg>
-int parse_header(const Char*& it, const Char* end,
-                 basic_format_specs<Char>& specs, GetArg get_arg) {
+auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
+                  GetArg get_arg) -> int {
   int arg_index = -1;
   Char c = *it;
   if (c >= '0' && c <= '9') {
@@ -344,7 +346,7 @@
       if (value != 0) {
         // Nonzero value means that we parsed width and don't need to
         // parse it or flags again, so return now.
-        if (value == -1) FMT_THROW(format_error("number is too big"));
+        if (value == -1) throw_format_error("number is too big");
         specs.width = value;
         return arg_index;
       }
@@ -355,7 +357,7 @@
   if (it != end) {
     if (*it >= '0' && *it <= '9') {
       specs.width = parse_nonnegative_int(it, end, -1);
-      if (specs.width == -1) FMT_THROW(format_error("number is too big"));
+      if (specs.width == -1) throw_format_error("number is too big");
     } else if (*it == '*') {
       ++it;
       specs.width = static_cast<int>(visit_format_arg(
@@ -365,13 +367,53 @@
   return arg_index;
 }
 
+inline auto parse_printf_presentation_type(char c, type t)
+    -> presentation_type {
+  using pt = presentation_type;
+  constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
+  switch (c) {
+  case 'd':
+    return in(t, integral_set) ? pt::dec : pt::none;
+  case 'o':
+    return in(t, integral_set) ? pt::oct : pt::none;
+  case 'x':
+    return in(t, integral_set) ? pt::hex_lower : pt::none;
+  case 'X':
+    return in(t, integral_set) ? pt::hex_upper : pt::none;
+  case 'a':
+    return in(t, float_set) ? pt::hexfloat_lower : pt::none;
+  case 'A':
+    return in(t, float_set) ? pt::hexfloat_upper : pt::none;
+  case 'e':
+    return in(t, float_set) ? pt::exp_lower : pt::none;
+  case 'E':
+    return in(t, float_set) ? pt::exp_upper : pt::none;
+  case 'f':
+    return in(t, float_set) ? pt::fixed_lower : pt::none;
+  case 'F':
+    return in(t, float_set) ? pt::fixed_upper : pt::none;
+  case 'g':
+    return in(t, float_set) ? pt::general_lower : pt::none;
+  case 'G':
+    return in(t, float_set) ? pt::general_upper : pt::none;
+  case 'c':
+    return in(t, integral_set) ? pt::chr : pt::none;
+  case 's':
+    return in(t, string_set | cstring_set) ? pt::string : pt::none;
+  case 'p':
+    return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
+  default:
+    return pt::none;
+  }
+}
+
 template <typename Char, typename Context>
 void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
              basic_format_args<Context> args) {
-  using OutputIt = buffer_appender<Char>;
-  auto out = OutputIt(buf);
-  auto context = basic_printf_context<OutputIt, Char>(out, args);
-  auto parse_ctx = basic_printf_parse_context<Char>(format);
+  using iterator = buffer_appender<Char>;
+  auto out = iterator(buf);
+  auto context = basic_printf_context<Char>(out, args);
+  auto parse_ctx = basic_format_parse_context<Char>(format);
 
   // Returns the argument with specified index or, if arg_index is -1, the next
   // argument.
@@ -387,26 +429,24 @@
   const Char* end = parse_ctx.end();
   auto it = start;
   while (it != end) {
-    if (!detail::find<false, Char>(it, end, '%', it)) {
-      it = end;  // detail::find leaves it == nullptr if it doesn't find '%'
+    if (!find<false, Char>(it, end, '%', it)) {
+      it = end;  // find leaves it == nullptr if it doesn't find '%'.
       break;
     }
     Char c = *it++;
     if (it != end && *it == c) {
-      out = detail::write(
-          out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
+      write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
       start = ++it;
       continue;
     }
-    out = detail::write(out, basic_string_view<Char>(
-                                 start, detail::to_unsigned(it - 1 - start)));
+    write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
 
-    basic_format_specs<Char> specs;
+    auto specs = format_specs<Char>();
     specs.align = align::right;
 
     // Parse argument index, flags and width.
     int arg_index = parse_header(it, end, specs, get_arg);
-    if (arg_index == 0) parse_ctx.on_error("argument not found");
+    if (arg_index == 0) throw_format_error("argument not found");
 
     // Parse precision.
     if (it != end && *it == '.') {
@@ -417,7 +457,7 @@
       } else if (c == '*') {
         ++it;
         specs.precision = static_cast<int>(
-            visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
+            visit_format_arg(printf_precision_handler(), get_arg(-1)));
       } else {
         specs.precision = 0;
       }
@@ -426,20 +466,19 @@
     auto arg = get_arg(arg_index);
     // For d, i, o, u, x, and X conversion specifiers, if a precision is
     // specified, the '0' flag is ignored
-    if (specs.precision >= 0 && arg.is_integral())
-      specs.fill[0] =
-          ' ';  // Ignore '0' flag for non-numeric types or if '-' present.
-    if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
-      auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
+    if (specs.precision >= 0 && arg.is_integral()) {
+      // Ignore '0' for non-numeric types or if '-' present.
+      specs.fill[0] = ' ';
+    }
+    if (specs.precision >= 0 && arg.type() == type::cstring_type) {
+      auto str = visit_format_arg(get_cstring<Char>(), arg);
       auto str_end = str + specs.precision;
       auto nul = std::find(str, str_end, Char());
-      arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
-          basic_string_view<Char>(
-              str, detail::to_unsigned(nul != str_end ? nul - str
-                                                      : specs.precision)));
+      auto sv = basic_string_view<Char>(
+          str, to_unsigned(nul != str_end ? nul - str : specs.precision));
+      arg = make_arg<basic_printf_context<Char>>(sv);
     }
-    if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
-      specs.alt = false;
+    if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false;
     if (specs.fill[0] == '0') {
       if (arg.is_arithmetic() && specs.align != align::left)
         specs.align = align::numeric;
@@ -451,7 +490,6 @@
     // Parse length and convert the argument to the required type.
     c = it != end ? *it++ : 0;
     Char t = it != end ? *it : 0;
-    using detail::convert_arg;
     switch (c) {
     case 'h':
       if (t == 'h') {
@@ -490,7 +528,7 @@
     }
 
     // Parse type.
-    if (it == end) FMT_THROW(format_error("invalid format string"));
+    if (it == end) throw_format_error("invalid format string");
     char type = static_cast<char>(*it++);
     if (arg.is_integral()) {
       // Normalize type.
@@ -500,32 +538,25 @@
         type = 'd';
         break;
       case 'c':
-        visit_format_arg(
-            detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
-            arg);
+        visit_format_arg(char_converter<basic_printf_context<Char>>(arg), arg);
         break;
       }
     }
-    specs.type = parse_presentation_type(type);
+    specs.type = parse_printf_presentation_type(type, arg.type());
     if (specs.type == presentation_type::none)
-      parse_ctx.on_error("invalid type specifier");
+      throw_format_error("invalid format specifier");
 
     start = it;
 
     // Format argument.
-    out = visit_format_arg(
-        detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
+    visit_format_arg(printf_arg_formatter<Char>(out, specs, context), arg);
   }
-  detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
+  write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
 }
-FMT_END_DETAIL_NAMESPACE
+}  // namespace detail
 
-template <typename Char>
-using basic_printf_context_t =
-    basic_printf_context<detail::buffer_appender<Char>, Char>;
-
-using printf_context = basic_printf_context_t<char>;
-using wprintf_context = basic_printf_context_t<wchar_t>;
+using printf_context = basic_printf_context<char>;
+using wprintf_context = basic_printf_context<wchar_t>;
 
 using printf_args = basic_format_args<printf_context>;
 using wprintf_args = basic_format_args<wprintf_context>;
@@ -542,26 +573,21 @@
   return {args...};
 }
 
-/**
-  \rst
-  Constructs an `~fmt::format_arg_store` object that contains references to
-  arguments and can be implicitly converted to `~fmt::wprintf_args`.
-  \endrst
- */
+// DEPRECATED!
 template <typename... T>
 inline auto make_wprintf_args(const T&... args)
     -> format_arg_store<wprintf_context, T...> {
   return {args...};
 }
 
-template <typename S, typename Char = char_t<S>>
+template <typename Char>
 inline auto vsprintf(
-    const S& fmt,
-    basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+    basic_string_view<Char> fmt,
+    basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
     -> std::basic_string<Char> {
-  basic_memory_buffer<Char> buffer;
-  vprintf(buffer, detail::to_string_view(fmt), args);
-  return to_string(buffer);
+  auto buf = basic_memory_buffer<Char>();
+  detail::vprintf(buf, fmt, args);
+  return to_string(buf);
 }
 
 /**
@@ -576,20 +602,19 @@
 template <typename S, typename... T,
           typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
 inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
-  using context = basic_printf_context_t<Char>;
   return vsprintf(detail::to_string_view(fmt),
-                  fmt::make_format_args<context>(args...));
+                  fmt::make_format_args<basic_printf_context<Char>>(args...));
 }
 
-template <typename S, typename Char = char_t<S>>
+template <typename Char>
 inline auto vfprintf(
-    std::FILE* f, const S& fmt,
-    basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+    std::FILE* f, basic_string_view<Char> fmt,
+    basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
     -> int {
-  basic_memory_buffer<Char> buffer;
-  vprintf(buffer, detail::to_string_view(fmt), args);
-  size_t size = buffer.size();
-  return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
+  auto buf = basic_memory_buffer<Char>();
+  detail::vprintf(buf, fmt, args);
+  size_t size = buf.size();
+  return std::fwrite(buf.data(), sizeof(Char), size, f) < size
              ? -1
              : static_cast<int>(size);
 }
@@ -605,17 +630,16 @@
  */
 template <typename S, typename... T, typename Char = char_t<S>>
 inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
-  using context = basic_printf_context_t<Char>;
   return vfprintf(f, detail::to_string_view(fmt),
-                  fmt::make_format_args<context>(args...));
+                  fmt::make_format_args<basic_printf_context<Char>>(args...));
 }
 
-template <typename S, typename Char = char_t<S>>
-inline auto vprintf(
-    const S& fmt,
-    basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+template <typename Char>
+FMT_DEPRECATED inline auto vprintf(
+    basic_string_view<Char> fmt,
+    basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
     -> int {
-  return vfprintf(stdout, detail::to_string_view(fmt), args);
+  return vfprintf(stdout, fmt, args);
 }
 
 /**
@@ -627,14 +651,17 @@
     fmt::printf("Elapsed time: %.2f seconds", 1.23);
   \endrst
  */
-template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
-inline auto printf(const S& fmt, const T&... args) -> int {
-  return vprintf(
-      detail::to_string_view(fmt),
-      fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
+template <typename... T>
+inline auto printf(string_view fmt, const T&... args) -> int {
+  return vfprintf(stdout, fmt, make_printf_args(args...));
+}
+template <typename... T>
+FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
+                                  const T&... args) -> int {
+  return vfprintf(stdout, fmt, make_wprintf_args(args...));
 }
 
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_PRINTF_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
index dea7d60..65beba5 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
@@ -22,27 +22,25 @@
 
 namespace detail {
 
-template <typename RangeT, typename OutputIterator>
-OutputIterator copy(const RangeT& range, OutputIterator out) {
+template <typename Range, typename OutputIt>
+auto copy(const Range& range, OutputIt out) -> OutputIt {
   for (auto it = range.begin(), end = range.end(); it != end; ++it)
     *out++ = *it;
   return out;
 }
 
-template <typename OutputIterator>
-OutputIterator copy(const char* str, OutputIterator out) {
+template <typename OutputIt>
+auto copy(const char* str, OutputIt out) -> OutputIt {
   while (*str) *out++ = *str++;
   return out;
 }
 
-template <typename OutputIterator>
-OutputIterator copy(char ch, OutputIterator out) {
+template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
   *out++ = ch;
   return out;
 }
 
-template <typename OutputIterator>
-OutputIterator copy(wchar_t ch, OutputIterator out) {
+template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
   *out++ = ch;
   return out;
 }
@@ -69,7 +67,7 @@
   template <typename> static void check(...);
 
  public:
-#ifdef FMT_FORMAT_MAP_AS_LIST
+#ifdef FMT_FORMAT_MAP_AS_LIST  // DEPRECATED!
   static constexpr const bool value = false;
 #else
   static constexpr const bool value =
@@ -82,7 +80,7 @@
   template <typename> static void check(...);
 
  public:
-#ifdef FMT_FORMAT_SET_AS_LIST
+#ifdef FMT_FORMAT_SET_AS_LIST  // DEPRECATED!
   static constexpr const bool value = false;
 #else
   static constexpr const bool value =
@@ -157,8 +155,9 @@
 struct has_mutable_begin_end<
     T, void_t<decltype(detail::range_begin(std::declval<T>())),
               decltype(detail::range_end(std::declval<T>())),
-              enable_if_t<std::is_copy_constructible<T>::value>>>
-    : std::true_type {};
+              // the extra int here is because older versions of MSVC don't
+              // SFINAE properly unless there are distinct types
+              int>> : std::true_type {};
 
 template <typename T>
 struct is_range_<T, void>
@@ -211,41 +210,61 @@
   static constexpr const bool value = false;
 };
 template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
-  template <std::size_t... I>
-  static std::true_type check2(index_sequence<I...>,
-                               integer_sequence<bool, (I == I)...>);
+  template <std::size_t... Is>
+  static std::true_type check2(index_sequence<Is...>,
+                               integer_sequence<bool, (Is == Is)...>);
   static std::false_type check2(...);
-  template <std::size_t... I>
+  template <std::size_t... Is>
   static decltype(check2(
-      index_sequence<I...>{},
+      index_sequence<Is...>{},
       integer_sequence<
-          bool, (is_formattable<typename std::tuple_element<I, T>::type,
-                                C>::value)...>{})) check(index_sequence<I...>);
+          bool, (is_formattable<typename std::tuple_element<Is, T>::type,
+                                C>::value)...>{})) check(index_sequence<Is...>);
 
  public:
   static constexpr const bool value =
       decltype(check(tuple_index_sequence<T>{}))::value;
 };
 
-template <class Tuple, class F, size_t... Is>
-void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
+template <typename Tuple, typename F, size_t... Is>
+FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
   using std::get;
-  // using free function get<I>(T) now.
-  const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
-  (void)_;  // blocks warnings
+  // Using a free function get<Is>(Tuple) now.
+  const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
+  ignore_unused(unused);
 }
 
-template <class T>
-FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
-    T const&) {
-  return {};
+template <typename Tuple, typename F>
+FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
+  for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
+           std::forward<Tuple>(t), std::forward<F>(f));
 }
 
-template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
-  const auto indexes = get_indexes(tup);
-  for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
+template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
+void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
+  using std::get;
+  const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
+  ignore_unused(unused);
 }
 
+template <typename Tuple1, typename Tuple2, typename F>
+void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
+  for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
+            std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
+            std::forward<F>(f));
+}
+
+namespace tuple {
+// Workaround a bug in MSVC 2019 (v140).
+template <typename Char, typename... T>
+using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
+
+using std::get;
+template <typename Tuple, typename Char, std::size_t... Is>
+auto get_formatters(index_sequence<Is...>)
+    -> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
+}  // namespace tuple
+
 #if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
 // Older MSVC doesn't get the reference type correctly for arrays.
 template <typename R> struct range_reference_type_impl {
@@ -269,45 +288,37 @@
 template <typename Range>
 using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
 
-template <typename Range>
-using uncvref_first_type =
-    remove_cvref_t<decltype(std::declval<range_reference_type<Range>>().first)>;
-
-template <typename Range>
-using uncvref_second_type = remove_cvref_t<
-    decltype(std::declval<range_reference_type<Range>>().second)>;
-
-template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
-  *out++ = ',';
-  *out++ = ' ';
-  return out;
+template <typename Formatter>
+FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
+    -> decltype(f.set_debug_format(set)) {
+  f.set_debug_format(set);
 }
+template <typename Formatter>
+FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
 
-template <typename Char, typename OutputIt>
-auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
-  return write_escaped_string(out, str);
-}
+// These are not generic lambdas for compatibility with C++11.
+template <typename ParseContext> struct parse_empty_specs {
+  template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
+    f.parse(ctx);
+    detail::maybe_set_debug_format(f, true);
+  }
+  ParseContext& ctx;
+};
+template <typename FormatContext> struct format_tuple_element {
+  using char_type = typename FormatContext::char_type;
 
-template <typename Char, typename OutputIt, typename T,
-          FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
-inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
-  auto sv = std_string_view<Char>(str);
-  return write_range_entry<Char>(out, basic_string_view<Char>(sv));
-}
+  template <typename T>
+  void operator()(const formatter<T, char_type>& f, const T& v) {
+    if (i > 0)
+      ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
+    ctx.advance_to(f.format(v, ctx));
+    ++i;
+  }
 
-template <typename Char, typename OutputIt, typename Arg,
-          FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
-OutputIt write_range_entry(OutputIt out, const Arg v) {
-  return write_escaped_char(out, v);
-}
-
-template <
-    typename Char, typename OutputIt, typename Arg,
-    FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
-                  !std::is_same<Arg, Char>::value)>
-OutputIt write_range_entry(OutputIt out, const Arg& v) {
-  return write<Char>(out, v);
-}
+  int i;
+  FormatContext& ctx;
+  basic_string_view<char_type> separator;
+};
 
 }  // namespace detail
 
@@ -321,29 +332,20 @@
       detail::is_tuple_formattable_<T, C>::value;
 };
 
-template <typename TupleT, typename Char>
-struct formatter<TupleT, Char,
-                 enable_if_t<fmt::is_tuple_like<TupleT>::value &&
-                             fmt::is_tuple_formattable<TupleT, Char>::value>> {
+template <typename Tuple, typename Char>
+struct formatter<Tuple, Char,
+                 enable_if_t<fmt::is_tuple_like<Tuple>::value &&
+                             fmt::is_tuple_formattable<Tuple, Char>::value>> {
  private:
+  decltype(detail::tuple::get_formatters<Tuple, Char>(
+      detail::tuple_index_sequence<Tuple>())) formatters_;
+
   basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
   basic_string_view<Char> opening_bracket_ =
       detail::string_literal<Char, '('>{};
   basic_string_view<Char> closing_bracket_ =
       detail::string_literal<Char, ')'>{};
 
-  // C++11 generic lambda for format().
-  template <typename FormatContext> struct format_each {
-    template <typename T> void operator()(const T& v) {
-      if (i > 0) out = detail::copy_str<Char>(separator, out);
-      out = detail::write_range_entry<Char>(out, v);
-      ++i;
-    }
-    int i;
-    typename FormatContext::iterator& out;
-    basic_string_view<Char> separator;
-  };
-
  public:
   FMT_CONSTEXPR formatter() {}
 
@@ -359,17 +361,21 @@
 
   template <typename ParseContext>
   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    return ctx.begin();
+    auto it = ctx.begin();
+    if (it != ctx.end() && *it != '}')
+      FMT_THROW(format_error("invalid format specifier"));
+    detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
+    return it;
   }
 
-  template <typename FormatContext = format_context>
-  auto format(const TupleT& values, FormatContext& ctx) const
+  template <typename FormatContext>
+  auto format(const Tuple& value, FormatContext& ctx) const
       -> decltype(ctx.out()) {
-    auto out = ctx.out();
-    out = detail::copy_str<Char>(opening_bracket_, out);
-    detail::for_each(values, format_each<FormatContext>{0, out, separator_});
-    out = detail::copy_str<Char>(closing_bracket_, out);
-    return out;
+    ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
+    detail::for_each2(
+        formatters_, value,
+        detail::format_tuple_element<FormatContext>{0, ctx, separator_});
+    return detail::copy_str<Char>(closing_bracket_, ctx.out());
   }
 };
 
@@ -398,12 +404,10 @@
 };
 
 template <typename Char, typename Element>
-using range_formatter_type = conditional_t<
-    is_formattable<Element, Char>::value,
+using range_formatter_type =
     formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
                   std::declval<Element>()))>,
-              Char>,
-    fallback_formatter<Element, Char>>;
+              Char>;
 
 template <typename R>
 using maybe_const_range =
@@ -413,11 +417,8 @@
 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
 template <typename R, typename Char>
 struct is_formattable_delayed
-    : disjunction<
-          is_formattable<uncvref_type<maybe_const_range<R>>, Char>,
-          has_fallback_formatter<uncvref_type<maybe_const_range<R>>, Char>> {};
+    : is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
 #endif
-
 }  // namespace detail
 
 template <typename T, typename Char, typename Enable = void>
@@ -426,32 +427,16 @@
 template <typename T, typename Char>
 struct range_formatter<
     T, Char,
-    enable_if_t<conjunction<
-        std::is_same<T, remove_cvref_t<T>>,
-        disjunction<is_formattable<T, Char>,
-                    detail::has_fallback_formatter<T, Char>>>::value>> {
+    enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
+                            is_formattable<T, Char>>::value>> {
  private:
   detail::range_formatter_type<Char, T> underlying_;
-  bool custom_specs_ = false;
   basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
   basic_string_view<Char> opening_bracket_ =
       detail::string_literal<Char, '['>{};
   basic_string_view<Char> closing_bracket_ =
       detail::string_literal<Char, ']'>{};
 
-  template <class U>
-  FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, int)
-      -> decltype(u.set_debug_format()) {
-    u.set_debug_format();
-  }
-
-  template <class U>
-  FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
-
-  FMT_CONSTEXPR void maybe_set_debug_format() {
-    maybe_set_debug_format(underlying_, 0);
-  }
-
  public:
   FMT_CONSTEXPR range_formatter() {}
 
@@ -473,31 +458,24 @@
   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
     auto it = ctx.begin();
     auto end = ctx.end();
-    if (it == end || *it == '}') {
-      maybe_set_debug_format();
-      return it;
-    }
 
-    if (*it == 'n') {
+    if (it != end && *it == 'n') {
       set_brackets({}, {});
       ++it;
     }
 
-    if (*it == '}') {
-      maybe_set_debug_format();
-      return it;
+    if (it != end && *it != '}') {
+      if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
+      ++it;
+    } else {
+      detail::maybe_set_debug_format(underlying_, true);
     }
 
-    if (*it != ':')
-      FMT_THROW(format_error("no other top-level range formatters supported"));
-
-    custom_specs_ = true;
-    ++it;
     ctx.advance_to(it);
     return underlying_.parse(ctx);
   }
 
-  template <typename R, class FormatContext>
+  template <typename R, typename FormatContext>
   auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
     detail::range_mapper<buffer_context<Char>> mapper;
     auto out = ctx.out();
@@ -507,7 +485,6 @@
     auto end = detail::range_end(range);
     for (; it != end; ++it) {
       if (i > 0) out = detail::copy_str<Char>(separator_, out);
-      ;
       ctx.advance_to(out);
       out = underlying_.format(mapper.map(*it), ctx);
       ++i;
@@ -520,13 +497,14 @@
 enum class range_format { disabled, map, set, sequence, string, debug_string };
 
 namespace detail {
-template <typename T> struct range_format_kind_ {
-  static constexpr auto value = std::is_same<range_reference_type<T>, T>::value
-                                    ? range_format::disabled
-                                : is_map<T>::value ? range_format::map
-                                : is_set<T>::value ? range_format::set
-                                                   : range_format::sequence;
-};
+template <typename T>
+struct range_format_kind_
+    : std::integral_constant<range_format,
+                             std::is_same<uncvref_type<T>, T>::value
+                                 ? range_format::disabled
+                             : is_map<T>::value ? range_format::map
+                             : is_set<T>::value ? range_format::set
+                                                : range_format::sequence> {};
 
 template <range_format K, typename R, typename Char, typename Enable = void>
 struct range_default_formatter;
@@ -601,9 +579,6 @@
       : tuple(t), sep{s} {}
 };
 
-template <typename Char, typename... T>
-using tuple_arg_join = tuple_join_view<Char, T...>;
-
 // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
 // support in tuple_join. It is disabled by default because of issues with
 // the dynamic width and precision.
@@ -673,7 +648,45 @@
   }
 };
 
-FMT_MODULE_EXPORT_BEGIN
+namespace detail {
+// Check if T has an interface like a container adaptor (e.g. std::stack,
+// std::queue, std::priority_queue).
+template <typename T> class is_container_adaptor_like {
+  template <typename U> static auto check(U* p) -> typename U::container_type;
+  template <typename> static void check(...);
+
+ public:
+  static constexpr const bool value =
+      !std::is_void<decltype(check<T>(nullptr))>::value;
+};
+
+template <typename Container> struct all {
+  const Container& c;
+  auto begin() const -> typename Container::const_iterator { return c.begin(); }
+  auto end() const -> typename Container::const_iterator { return c.end(); }
+};
+}  // namespace detail
+
+template <typename T, typename Char>
+struct formatter<
+    T, Char,
+    enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
+                            bool_constant<range_format_kind<T, Char>::value ==
+                                          range_format::disabled>>::value>>
+    : formatter<detail::all<typename T::container_type>, Char> {
+  using all = detail::all<typename T::container_type>;
+  template <typename FormatContext>
+  auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
+    struct getter : T {
+      static auto get(const T& t) -> all {
+        return {t.*(&getter::c)};  // Access c through the derived class.
+      }
+    };
+    return formatter<all>::format(getter::get(t), ctx);
+  }
+};
+
+FMT_BEGIN_EXPORT
 
 /**
   \rst
@@ -716,7 +729,7 @@
   return join(std::begin(list), std::end(list), sep);
 }
 
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_RANGES_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/std.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/std.h
index 41d2b28..b4e055c 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/std.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/std.h
@@ -8,10 +8,18 @@
 #ifndef FMT_STD_H_
 #define FMT_STD_H_
 
+#include <atomic>
+#include <bitset>
+#include <cstdlib>
+#include <exception>
+#include <memory>
 #include <thread>
 #include <type_traits>
+#include <typeinfo>
 #include <utility>
+#include <vector>
 
+#include "format.h"
 #include "ostream.h"
 
 #if FMT_HAS_INCLUDE(<version>)
@@ -25,6 +33,30 @@
 #  if FMT_HAS_INCLUDE(<variant>)
 #    include <variant>
 #  endif
+#  if FMT_HAS_INCLUDE(<optional>)
+#    include <optional>
+#  endif
+#endif
+
+// GCC 4 does not support FMT_HAS_INCLUDE.
+#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
+#  include <cxxabi.h>
+// Android NDK with gabi++ library on some architectures does not implement
+// abi::__cxa_demangle().
+#  ifndef __GABIXX_CXXABI_H__
+#    define FMT_HAS_ABI_CXA_DEMANGLE
+#  endif
+#endif
+
+// Check if typeid is available.
+#ifndef FMT_USE_TYPEID
+// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI.
+#  if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \
+      defined(__INTEL_RTTI__) || defined(__RTTI)
+#    define FMT_USE_TYPEID 1
+#  else
+#    define FMT_USE_TYPEID 0
+#  endif
 #endif
 
 #ifdef __cpp_lib_filesystem
@@ -32,21 +64,32 @@
 
 namespace detail {
 
+template <typename Char> auto get_path_string(const std::filesystem::path& p) {
+  return p.string<Char>();
+}
+
 template <typename Char>
 void write_escaped_path(basic_memory_buffer<Char>& quoted,
                         const std::filesystem::path& p) {
   write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
 }
+
 #  ifdef _WIN32
 template <>
-inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
-                                     const std::filesystem::path& p) {
-  auto s = p.u8string();
-  write_escaped_string<char>(
-      std::back_inserter(quoted),
-      string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
+inline auto get_path_string<char>(const std::filesystem::path& p) {
+  return to_utf8<wchar_t>(p.native(), to_utf8_error_policy::replace);
 }
-#  endif
+
+template <>
+inline void write_escaped_path<char>(memory_buffer& quoted,
+                                     const std::filesystem::path& p) {
+  auto buf = basic_memory_buffer<wchar_t>();
+  write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
+  bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
+  FMT_ASSERT(valid, "invalid utf16");
+}
+#  endif  // _WIN32
+
 template <>
 inline void write_escaped_path<std::filesystem::path::value_type>(
     basic_memory_buffer<std::filesystem::path::value_type>& quoted,
@@ -57,62 +100,118 @@
 
 }  // namespace detail
 
-template <typename Char>
-struct formatter<std::filesystem::path, Char>
-    : formatter<basic_string_view<Char>> {
+FMT_EXPORT
+template <typename Char> struct formatter<std::filesystem::path, Char> {
+ private:
+  format_specs<Char> specs_;
+  detail::arg_ref<Char> width_ref_;
+  bool debug_ = false;
+
+ public:
+  FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
+
+  template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
+    auto it = ctx.begin(), end = ctx.end();
+    if (it == end) return it;
+
+    it = detail::parse_align(it, end, specs_);
+    if (it == end) return it;
+
+    it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
+    if (it != end && *it == '?') {
+      debug_ = true;
+      ++it;
+    }
+    return it;
+  }
+
   template <typename FormatContext>
-  auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
-      typename FormatContext::iterator {
-    basic_memory_buffer<Char> quoted;
+  auto format(const std::filesystem::path& p, FormatContext& ctx) const {
+    auto specs = specs_;
+    detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
+                                                       ctx);
+    if (!debug_) {
+      auto s = detail::get_path_string<Char>(p);
+      return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
+    }
+    auto quoted = basic_memory_buffer<Char>();
     detail::write_escaped_path(quoted, p);
-    return formatter<basic_string_view<Char>>::format(
-        basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
+    return detail::write(ctx.out(),
+                         basic_string_view<Char>(quoted.data(), quoted.size()),
+                         specs);
   }
 };
 FMT_END_NAMESPACE
 #endif
 
 FMT_BEGIN_NAMESPACE
+FMT_EXPORT
 template <typename Char>
 struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
 FMT_END_NAMESPACE
 
-#ifdef __cpp_lib_variant
+#ifdef __cpp_lib_optional
 FMT_BEGIN_NAMESPACE
-template <typename Char> struct formatter<std::monostate, Char> {
-  template <typename ParseContext>
-  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
-    return ctx.begin();
+FMT_EXPORT
+template <typename T, typename Char>
+struct formatter<std::optional<T>, Char,
+                 std::enable_if_t<is_formattable<T, Char>::value>> {
+ private:
+  formatter<T, Char> underlying_;
+  static constexpr basic_string_view<Char> optional =
+      detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
+                             '('>{};
+  static constexpr basic_string_view<Char> none =
+      detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
+
+  template <class U>
+  FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
+      -> decltype(u.set_debug_format(set)) {
+    u.set_debug_format(set);
+  }
+
+  template <class U>
+  FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
+
+ public:
+  template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
+    maybe_set_debug_format(underlying_, true);
+    return underlying_.parse(ctx);
   }
 
   template <typename FormatContext>
-  auto format(const std::monostate&, FormatContext& ctx) const
+  auto format(std::optional<T> const& opt, FormatContext& ctx) const
       -> decltype(ctx.out()) {
+    if (!opt) return detail::write<Char>(ctx.out(), none);
+
     auto out = ctx.out();
-    out = detail::write<Char>(out, "monostate");
-    return out;
+    out = detail::write<Char>(out, optional);
+    ctx.advance_to(out);
+    out = underlying_.format(*opt, ctx);
+    return detail::write(out, ')');
   }
 };
+FMT_END_NAMESPACE
+#endif  // __cpp_lib_optional
 
+#ifdef __cpp_lib_variant
+FMT_BEGIN_NAMESPACE
 namespace detail {
 
 template <typename T>
 using variant_index_sequence =
     std::make_index_sequence<std::variant_size<T>::value>;
 
-// variant_size and variant_alternative check.
-template <typename T, typename U = void>
-struct is_variant_like_ : std::false_type {};
-template <typename T>
-struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>>
-    : std::true_type {};
+template <typename> struct is_variant_like_ : std::false_type {};
+template <typename... Types>
+struct is_variant_like_<std::variant<Types...>> : std::true_type {};
 
-// formattable element check
+// formattable element check.
 template <typename T, typename C> class is_variant_formattable_ {
-  template <std::size_t... I>
+  template <std::size_t... Is>
   static std::conjunction<
-      is_formattable<std::variant_alternative_t<I, T>, C>...>
-      check(std::index_sequence<I...>);
+      is_formattable<std::variant_alternative_t<Is, T>, C>...>
+      check(std::index_sequence<Is...>);
 
  public:
   static constexpr const bool value =
@@ -140,6 +239,21 @@
       detail::is_variant_formattable_<T, C>::value;
 };
 
+FMT_EXPORT
+template <typename Char> struct formatter<std::monostate, Char> {
+  template <typename ParseContext>
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+    return ctx.begin();
+  }
+
+  template <typename FormatContext>
+  auto format(const std::monostate&, FormatContext& ctx) const
+      -> decltype(ctx.out()) {
+    return detail::write<Char>(ctx.out(), "monostate");
+  }
+};
+
+FMT_EXPORT
 template <typename Variant, typename Char>
 struct formatter<
     Variant, Char,
@@ -156,16 +270,196 @@
     auto out = ctx.out();
 
     out = detail::write<Char>(out, "variant(");
-    std::visit(
-        [&](const auto& v) {
-          out = detail::write_variant_alternative<Char>(out, v);
-        },
-        value);
+    FMT_TRY {
+      std::visit(
+          [&](const auto& v) {
+            out = detail::write_variant_alternative<Char>(out, v);
+          },
+          value);
+    }
+    FMT_CATCH(const std::bad_variant_access&) {
+      detail::write<Char>(out, "valueless by exception");
+    }
     *out++ = ')';
     return out;
   }
 };
 FMT_END_NAMESPACE
+#endif  // __cpp_lib_variant
+
+FMT_BEGIN_NAMESPACE
+FMT_EXPORT
+template <typename Char> struct formatter<std::error_code, Char> {
+  template <typename ParseContext>
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+    return ctx.begin();
+  }
+
+  template <typename FormatContext>
+  FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
+      -> decltype(ctx.out()) {
+    auto out = ctx.out();
+    out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
+    out = detail::write<Char>(out, Char(':'));
+    out = detail::write<Char>(out, ec.value());
+    return out;
+  }
+};
+
+FMT_EXPORT
+template <typename T, typename Char>
+struct formatter<
+    T, Char,
+    typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
+ private:
+  bool with_typename_ = false;
+
+ public:
+  FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
+      -> decltype(ctx.begin()) {
+    auto it = ctx.begin();
+    auto end = ctx.end();
+    if (it == end || *it == '}') return it;
+    if (*it == 't') {
+      ++it;
+      with_typename_ = FMT_USE_TYPEID != 0;
+    }
+    return it;
+  }
+
+  template <typename OutputIt>
+  auto format(const std::exception& ex,
+              basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
+    format_specs<Char> spec;
+    auto out = ctx.out();
+    if (!with_typename_)
+      return detail::write_bytes(out, string_view(ex.what()), spec);
+
+#if FMT_USE_TYPEID
+    const std::type_info& ti = typeid(ex);
+#  ifdef FMT_HAS_ABI_CXA_DEMANGLE
+    int status = 0;
+    std::size_t size = 0;
+    std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr(
+        abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
+
+    string_view demangled_name_view;
+    if (demangled_name_ptr) {
+      demangled_name_view = demangled_name_ptr.get();
+
+      // Normalization of stdlib inline namespace names.
+      // libc++ inline namespaces.
+      //  std::__1::*       -> std::*
+      //  std::__1::__fs::* -> std::*
+      // libstdc++ inline namespaces.
+      //  std::__cxx11::*             -> std::*
+      //  std::filesystem::__cxx11::* -> std::filesystem::*
+      if (demangled_name_view.starts_with("std::")) {
+        char* begin = demangled_name_ptr.get();
+        char* to = begin + 5;  // std::
+        for (char *from = to, *end = begin + demangled_name_view.size();
+             from < end;) {
+          // This is safe, because demangled_name is NUL-terminated.
+          if (from[0] == '_' && from[1] == '_') {
+            char* next = from + 1;
+            while (next < end && *next != ':') next++;
+            if (next[0] == ':' && next[1] == ':') {
+              from = next + 2;
+              continue;
+            }
+          }
+          *to++ = *from++;
+        }
+        demangled_name_view = {begin, detail::to_unsigned(to - begin)};
+      }
+    } else {
+      demangled_name_view = string_view(ti.name());
+    }
+    out = detail::write_bytes(out, demangled_name_view, spec);
+#  elif FMT_MSC_VERSION
+    string_view demangled_name_view(ti.name());
+    if (demangled_name_view.starts_with("class "))
+      demangled_name_view.remove_prefix(6);
+    else if (demangled_name_view.starts_with("struct "))
+      demangled_name_view.remove_prefix(7);
+    out = detail::write_bytes(out, demangled_name_view, spec);
+#  else
+    out = detail::write_bytes(out, string_view(ti.name()), spec);
+#  endif
+    *out++ = ':';
+    *out++ = ' ';
+    return detail::write_bytes(out, string_view(ex.what()), spec);
+#endif
+  }
+};
+
+namespace detail {
+
+template <typename T, typename Enable = void>
+struct has_flip : std::false_type {};
+
+template <typename T>
+struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
+    : std::true_type {};
+
+template <typename T> struct is_bit_reference_like {
+  static constexpr const bool value =
+      std::is_convertible<T, bool>::value &&
+      std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
+};
+
+#ifdef _LIBCPP_VERSION
+
+// Workaround for libc++ incompatibility with C++ standard.
+// According to the Standard, `bitset::operator[] const` returns bool.
+template <typename C>
+struct is_bit_reference_like<std::__bit_const_reference<C>> {
+  static constexpr const bool value = true;
+};
+
 #endif
 
+}  // namespace detail
+
+// We can't use std::vector<bool, Allocator>::reference and
+// std::bitset<N>::reference because the compiler can't deduce Allocator and N
+// in partial specialization.
+FMT_EXPORT
+template <typename BitRef, typename Char>
+struct formatter<BitRef, Char,
+                 enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
+    : formatter<bool, Char> {
+  template <typename FormatContext>
+  FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
+      -> decltype(ctx.out()) {
+    return formatter<bool, Char>::format(v, ctx);
+  }
+};
+
+FMT_EXPORT
+template <typename T, typename Char>
+struct formatter<std::atomic<T>, Char,
+                 enable_if_t<is_formattable<T, Char>::value>>
+    : formatter<T, Char> {
+  template <typename FormatContext>
+  auto format(const std::atomic<T>& v, FormatContext& ctx) const
+      -> decltype(ctx.out()) {
+    return formatter<T, Char>::format(v.load(), ctx);
+  }
+};
+
+#ifdef __cpp_lib_atomic_flag_test
+FMT_EXPORT
+template <typename Char>
+struct formatter<std::atomic_flag, Char>
+    : formatter<bool, Char> {
+  template <typename FormatContext>
+  auto format(const std::atomic_flag& v, FormatContext& ctx) const
+      -> decltype(ctx.out()) {
+    return formatter<bool, Char>::format(v.test(), ctx);
+  }
+};
+#endif // __cpp_lib_atomic_flag_test
+
+FMT_END_NAMESPACE
 #endif  // FMT_STD_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
index fc3c67f..0f79c17 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
@@ -12,13 +12,32 @@
 
 #include "format.h"
 
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+#  include <locale>
+#endif
+
 FMT_BEGIN_NAMESPACE
 namespace detail {
+
 template <typename T>
 using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
-}
 
-FMT_MODULE_EXPORT_BEGIN
+inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out,
+                      loc_value value, const format_specs<wchar_t>& specs,
+                      locale_ref loc) -> bool {
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+  auto& numpunct =
+      std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
+  auto separator = std::wstring();
+  auto grouping = numpunct.grouping();
+  if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
+  return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
+#endif
+  return false;
+}
+}  // namespace detail
+
+FMT_BEGIN_EXPORT
 
 using wstring_view = basic_string_view<wchar_t>;
 using wformat_parse_context = basic_format_parse_context<wchar_t>;
@@ -33,7 +52,9 @@
 #else
 template <typename... Args>
 using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
-inline auto runtime(wstring_view s) -> basic_runtime<wchar_t> { return {{s}}; }
+inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
+  return {{s}};
+}
 #endif
 
 template <> struct is_char<wchar_t> : std::true_type {};
@@ -41,9 +62,9 @@
 template <> struct is_char<char16_t> : std::true_type {};
 template <> struct is_char<char32_t> : std::true_type {};
 
-template <typename... Args>
-constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
-    const Args&... args) {
+template <typename... T>
+constexpr format_arg_store<wformat_context, T...> make_wformat_args(
+    const T&... args) {
   return {args...};
 }
 
@@ -78,9 +99,9 @@
 auto vformat(basic_string_view<Char> format_str,
              basic_format_args<buffer_context<type_identity_t<Char>>> args)
     -> std::basic_string<Char> {
-  basic_memory_buffer<Char> buffer;
-  detail::vformat_to(buffer, format_str, args);
-  return to_string(buffer);
+  auto buf = basic_memory_buffer<Char>();
+  detail::vformat_to(buf, format_str, args);
+  return to_string(buf);
 }
 
 template <typename... T>
@@ -90,10 +111,10 @@
 
 // Pass char_t as a default template parameter instead of using
 // std::basic_string<char_t<S>> to reduce the symbol size.
-template <typename S, typename... Args, typename Char = char_t<S>,
+template <typename S, typename... T, typename Char = char_t<S>,
           FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
                         !std::is_same<Char, wchar_t>::value)>
-auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
+auto format(const S& format_str, T&&... args) -> std::basic_string<Char> {
   return vformat(detail::to_string_view(format_str),
                  fmt::make_format_args<buffer_context<Char>>(args...));
 }
@@ -108,11 +129,10 @@
   return detail::vformat(loc, detail::to_string_view(format_str), args);
 }
 
-template <typename Locale, typename S, typename... Args,
-          typename Char = char_t<S>,
+template <typename Locale, typename S, typename... T, typename Char = char_t<S>,
           FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
                             detail::is_exotic_char<Char>::value)>
-inline auto format(const Locale& loc, const S& format_str, Args&&... args)
+inline auto format(const Locale& loc, const S& format_str, T&&... args)
     -> std::basic_string<Char> {
   return detail::vformat(loc, detail::to_string_view(format_str),
                          fmt::make_format_args<buffer_context<Char>>(args...));
@@ -126,14 +146,14 @@
     -> OutputIt {
   auto&& buf = detail::get_buffer<Char>(out);
   detail::vformat_to(buf, detail::to_string_view(format_str), args);
-  return detail::get_iterator(buf);
+  return detail::get_iterator(buf, out);
 }
 
-template <typename OutputIt, typename S, typename... Args,
+template <typename OutputIt, typename S, typename... T,
           typename Char = char_t<S>,
           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
                             detail::is_exotic_char<Char>::value)>
-inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
+inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
   return vformat_to(out, detail::to_string_view(fmt),
                     fmt::make_format_args<buffer_context<Char>>(args...));
 }
@@ -149,18 +169,18 @@
   auto&& buf = detail::get_buffer<Char>(out);
   vformat_to(buf, detail::to_string_view(format_str), args,
              detail::locale_ref(loc));
-  return detail::get_iterator(buf);
+  return detail::get_iterator(buf, out);
 }
 
 template <
-    typename OutputIt, typename Locale, typename S, typename... Args,
+    typename OutputIt, typename Locale, typename S, typename... T,
     typename Char = char_t<S>,
     bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
         detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
 inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
-                      Args&&... args) ->
+                      T&&... args) ->
     typename std::enable_if<enable, OutputIt>::type {
-  return vformat_to(out, loc, to_string_view(format_str),
+  return vformat_to(out, loc, detail::to_string_view(format_str),
                     fmt::make_format_args<buffer_context<Char>>(args...));
 }
 
@@ -171,36 +191,36 @@
     OutputIt out, size_t n, basic_string_view<Char> format_str,
     basic_format_args<buffer_context<type_identity_t<Char>>> args)
     -> format_to_n_result<OutputIt> {
-  detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
-                                                                           n);
+  using traits = detail::fixed_buffer_traits;
+  auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
   detail::vformat_to(buf, format_str, args);
   return {buf.out(), buf.count()};
 }
 
-template <typename OutputIt, typename S, typename... Args,
+template <typename OutputIt, typename S, typename... T,
           typename Char = char_t<S>,
           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
                             detail::is_exotic_char<Char>::value)>
-inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
-                        const Args&... args) -> format_to_n_result<OutputIt> {
+inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
+    -> format_to_n_result<OutputIt> {
   return vformat_to_n(out, n, detail::to_string_view(fmt),
                       fmt::make_format_args<buffer_context<Char>>(args...));
 }
 
-template <typename S, typename... Args, typename Char = char_t<S>,
+template <typename S, typename... T, typename Char = char_t<S>,
           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
-inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
-  detail::counting_buffer<Char> buf;
+inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
+  auto buf = detail::counting_buffer<Char>();
   detail::vformat_to(buf, detail::to_string_view(fmt),
                      fmt::make_format_args<buffer_context<Char>>(args...));
   return buf.count();
 }
 
 inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
-  wmemory_buffer buffer;
-  detail::vformat_to(buffer, fmt, args);
-  buffer.push_back(L'\0');
-  std::fputws(buffer.data(), f);
+  auto buf = wmemory_buffer();
+  detail::vformat_to(buf, fmt, args);
+  buf.push_back(L'\0');
+  std::fputws(buf.data(), f);
 }
 
 inline void vprint(wstring_view fmt, wformat_args args) {
@@ -216,13 +236,22 @@
   return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
 }
 
+template <typename... T>
+void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
+  return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
+}
+
+template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
+  return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
+}
+
 /**
   Converts *value* to ``std::wstring`` using the default format for type *T*.
  */
 template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
   return format(FMT_STRING(L"{}"), value);
 }
-FMT_MODULE_EXPORT_END
+FMT_END_EXPORT
 FMT_END_NAMESPACE
 
 #endif  // FMT_XCHAR_H_
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp b/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
index 99b7e9d..391d3a2 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
@@ -28,12 +28,8 @@
 
 template FMT_API void buffer<char>::append(const char*, const char*);
 
-// DEPRECATED!
-// There is no correspondent extern template in format.h because of
-// incompatibility between clang and gcc (#2377).
 template FMT_API void vformat_to(buffer<char>&, string_view,
-                                 basic_format_args<FMT_BUFFER_CONTEXT(char)>,
-                                 locale_ref);
+                                 typename vformat_args<>::type, locale_ref);
 
 // Explicit instantiations for wchar_t.
 
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp b/wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
index 2c49951..d7ded50 100644
--- a/wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
@@ -18,6 +18,10 @@
 #  include <sys/stat.h>
 #  include <sys/types.h>
 
+#  ifdef _WRS_KERNEL   // VxWorks7 kernel
+#    include <ioLib.h> // getpagesize
+#  endif
+
 #  ifndef _WIN32
 #    include <unistd.h>
 #  else
@@ -72,34 +76,6 @@
 FMT_BEGIN_NAMESPACE
 
 #ifdef _WIN32
-detail::utf16_to_utf8::utf16_to_utf8(basic_string_view<wchar_t> s) {
-  if (int error_code = convert(s)) {
-    FMT_THROW(windows_error(error_code,
-                            "cannot convert string from UTF-16 to UTF-8"));
-  }
-}
-
-int detail::utf16_to_utf8::convert(basic_string_view<wchar_t> s) {
-  if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
-  int s_size = static_cast<int>(s.size());
-  if (s_size == 0) {
-    // WideCharToMultiByte does not support zero length, handle separately.
-    buffer_.resize(1);
-    buffer_[0] = 0;
-    return 0;
-  }
-
-  int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
-                                   nullptr, nullptr);
-  if (length == 0) return GetLastError();
-  buffer_.resize(length + 1);
-  length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
-                               length, nullptr, nullptr);
-  if (length == 0) return GetLastError();
-  buffer_[length] = 0;
-  return 0;
-}
-
 namespace detail {
 
 class system_message {
@@ -138,10 +114,10 @@
  public:
   const char* name() const noexcept override { return "system"; }
   std::string message(int error_code) const override {
-    system_message msg(error_code);
+    auto&& msg = system_message(error_code);
     if (msg) {
-      utf16_to_utf8 utf8_message;
-      if (utf8_message.convert(msg) == ERROR_SUCCESS) {
+      auto utf8_message = to_utf8<wchar_t>();
+      if (utf8_message.convert(msg)) {
         return utf8_message.str();
       }
     }
@@ -165,11 +141,12 @@
 void detail::format_windows_error(detail::buffer<char>& out, int error_code,
                                   const char* message) noexcept {
   FMT_TRY {
-    system_message msg(error_code);
+    auto&& msg = system_message(error_code);
     if (msg) {
-      utf16_to_utf8 utf8_message;
-      if (utf8_message.convert(msg) == ERROR_SUCCESS) {
-        fmt::format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
+      auto utf8_message = to_utf8<wchar_t>();
+      if (utf8_message.convert(msg)) {
+        fmt::format_to(appender(out), FMT_STRING("{}: {}"), message,
+                       string_view(utf8_message));
         return;
       }
     }
@@ -192,37 +169,47 @@
   FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
                 nullptr);
   if (!file_)
-    FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
+    FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"),
+                           filename.c_str()));
 }
 
 void buffered_file::close() {
   if (!file_) return;
   int result = FMT_SYSTEM(fclose(file_));
   file_ = nullptr;
-  if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
+  if (result != 0)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
 }
 
 int buffered_file::descriptor() const {
+#ifdef fileno  // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL.
+  int fd = fileno(file_);
+#else
   int fd = FMT_POSIX_CALL(fileno(file_));
-  if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
+#endif
+  if (fd == -1)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor")));
   return fd;
 }
 
 #if FMT_USE_FCNTL
-file::file(cstring_view path, int oflag) {
 #  ifdef _WIN32
-  using mode_t = int;
+using mode_t = int;
 #  endif
-  constexpr mode_t mode =
-      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+constexpr mode_t default_open_mode =
+    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+file::file(cstring_view path, int oflag) {
 #  if defined(_WIN32) && !defined(__MINGW32__)
   fd_ = -1;
-  FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
+  auto converted = detail::utf8_to_utf16(string_view(path.c_str()));
+  *this = file::open_windows_file(converted.c_str(), oflag);
 #  else
-  FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
-#  endif
+  FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode)));
   if (fd_ == -1)
-    FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
+    FMT_THROW(
+        system_error(errno, FMT_STRING("cannot open file {}"), path.c_str()));
+#  endif
 }
 
 file::~file() noexcept {
@@ -238,7 +225,8 @@
   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
   int result = FMT_POSIX_CALL(close(fd_));
   fd_ = -1;
-  if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
+  if (result != 0)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
 }
 
 long long file::size() const {
@@ -260,7 +248,7 @@
   using Stat = struct stat;
   Stat file_stat = Stat();
   if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
-    FMT_THROW(system_error(errno, "cannot get file attributes"));
+    FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes")));
   static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
                 "return type of file::size is not large enough");
   return file_stat.st_size;
@@ -270,14 +258,15 @@
 std::size_t file::read(void* buffer, std::size_t count) {
   rwresult result = 0;
   FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
-  if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
-  return detail::to_unsigned(result);
+  return count;
 }
 
 std::size_t file::write(const void* buffer, std::size_t count) {
   rwresult result = 0;
   FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
-  return count;
+  if (result < 0)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
+  return detail::to_unsigned(result);
 }
 
 file file::dup(int fd) {
@@ -285,7 +274,8 @@
   // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
   int new_fd = FMT_POSIX_CALL(dup(fd));
   if (new_fd == -1)
-    FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
+    FMT_THROW(system_error(
+        errno, FMT_STRING("cannot duplicate file descriptor {}"), fd));
   return file(new_fd);
 }
 
@@ -293,8 +283,9 @@
   int result = 0;
   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
   if (result == -1) {
-    FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
-                           fd_, fd));
+    FMT_THROW(system_error(
+        errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_,
+        fd));
   }
 }
 
@@ -319,7 +310,8 @@
   // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
   int result = FMT_POSIX_CALL(pipe(fds));
 #  endif
-  if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
+  if (result != 0)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe")));
   // The following assignments don't throw because read_fd and write_fd
   // are closed.
   read_end = file(fds[0]);
@@ -333,28 +325,72 @@
 #  else
   FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
 #  endif
-  if (!f)
-    FMT_THROW(
-        system_error(errno, "cannot associate stream with file descriptor"));
+  if (!f) {
+    FMT_THROW(system_error(
+        errno, FMT_STRING("cannot associate stream with file descriptor")));
+  }
   buffered_file bf(f);
   fd_ = -1;
   return bf;
 }
 
+#  if defined(_WIN32) && !defined(__MINGW32__)
+file file::open_windows_file(wcstring_view path, int oflag) {
+  int fd = -1;
+  auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode);
+  if (fd == -1) {
+    FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"),
+                           detail::to_utf8<wchar_t>(path.c_str()).c_str()));
+  }
+  return file(fd);
+}
+#  endif
+
+#  if !defined(__MSDOS__)
 long getpagesize() {
-#  ifdef _WIN32
+#    ifdef _WIN32
   SYSTEM_INFO si;
   GetSystemInfo(&si);
   return si.dwPageSize;
-#  else
+#    else
+#      ifdef _WRS_KERNEL
+  long size = FMT_POSIX_CALL(getpagesize());
+#      else
   long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
-  if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
-  return size;
-#  endif
-}
+#      endif
 
-FMT_API void ostream::grow(size_t) {
+  if (size < 0)
+    FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size")));
+  return size;
+#    endif
+}
+#  endif
+
+namespace detail {
+
+void file_buffer::grow(size_t) {
   if (this->size() == this->capacity()) flush();
 }
+
+file_buffer::file_buffer(cstring_view path,
+                         const detail::ostream_params& params)
+    : file_(path, params.oflag) {
+  set(new char[params.buffer_size], params.buffer_size);
+}
+
+file_buffer::file_buffer(file_buffer&& other)
+    : detail::buffer<char>(other.data(), other.size(), other.capacity()),
+      file_(std::move(other.file_)) {
+  other.clear();
+  other.set(nullptr, 0);
+}
+
+file_buffer::~file_buffer() {
+  flush();
+  delete[] data();
+}
+}  // namespace detail
+
+ostream::~ostream() = default;
 #endif  // FMT_USE_FCNTL
 FMT_END_NAMESPACE
diff --git a/wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp b/wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp
deleted file mode 100644
index 6cbc892..0000000
--- a/wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp
+++ /dev/null
@@ -1,5942 +0,0 @@
-//---------------------------------------------------------------------------------------
-//
-// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20
-//
-//---------------------------------------------------------------------------------------
-//
-// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
-//---------------------------------------------------------------------------------------
-//
-// To dynamically select std::filesystem where available on most platforms,
-// you could use:
-//
-// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
-// #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
-// #define GHC_USE_STD_FS
-// #include <filesystem>
-// namespace fs = std::filesystem;
-// #endif
-// #endif
-// #ifndef GHC_USE_STD_FS
-// #include <ghc/filesystem.hpp>
-// namespace fs = ghc::filesystem;
-// #endif
-//
-//---------------------------------------------------------------------------------------
-#ifndef GHC_FILESYSTEM_H
-#define GHC_FILESYSTEM_H
-
-// #define BSD manifest constant only in
-// sys/param.h
-#ifndef _WIN32
-#include <sys/param.h>
-#endif
-
-#ifndef GHC_OS_DETECTED
-#if defined(__APPLE__) && defined(__MACH__)
-#define GHC_OS_MACOS
-#elif defined(__linux__)
-#define GHC_OS_LINUX
-#if defined(__ANDROID__)
-#define GHC_OS_ANDROID
-#endif
-#elif defined(_WIN64)
-#define GHC_OS_WINDOWS
-#define GHC_OS_WIN64
-#elif defined(_WIN32)
-#define GHC_OS_WINDOWS
-#define GHC_OS_WIN32
-#elif defined(__CYGWIN__)
-#define GHC_OS_CYGWIN
-#elif defined(__svr4__)
-#define GHC_OS_SYS5R4
-#elif defined(BSD)
-#define GHC_OS_BSD
-#elif defined(__EMSCRIPTEN__)
-#define GHC_OS_WEB
-#include <wasi/api.h>
-#elif defined(__QNX__)
-#define GHC_OS_QNX
-#define GHC_NO_DIRENT_D_TYPE
-#else
-#error "Operating system currently not supported!"
-#endif
-#define GHC_OS_DETECTED
-#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
-#if _MSVC_LANG == 201703L
-#define GHC_FILESYSTEM_RUNNING_CPP17
-#else
-#define GHC_FILESYSTEM_RUNNING_CPP20
-#endif
-#elif (defined(__cplusplus) && __cplusplus >= 201703L)
-#if __cplusplus == 201703L
-#define GHC_FILESYSTEM_RUNNING_CPP17
-#else
-#define GHC_FILESYSTEM_RUNNING_CPP20
-#endif
-#endif
-#endif
-
-#if defined(GHC_FILESYSTEM_IMPLEMENTATION)
-#define GHC_EXPAND_IMPL
-#define GHC_INLINE
-#ifdef GHC_OS_WINDOWS
-#ifndef GHC_FS_API
-#define GHC_FS_API
-#endif
-#ifndef GHC_FS_API_CLASS
-#define GHC_FS_API_CLASS
-#endif
-#else
-#ifndef GHC_FS_API
-#define GHC_FS_API __attribute__((visibility("default")))
-#endif
-#ifndef GHC_FS_API_CLASS
-#define GHC_FS_API_CLASS __attribute__((visibility("default")))
-#endif
-#endif
-#elif defined(GHC_FILESYSTEM_FWD)
-#define GHC_INLINE
-#ifdef GHC_OS_WINDOWS
-#ifndef GHC_FS_API
-#define GHC_FS_API extern
-#endif
-#ifndef GHC_FS_API_CLASS
-#define GHC_FS_API_CLASS
-#endif
-#else
-#ifndef GHC_FS_API
-#define GHC_FS_API extern
-#endif
-#ifndef GHC_FS_API_CLASS
-#define GHC_FS_API_CLASS
-#endif
-#endif
-#else
-#define GHC_EXPAND_IMPL
-#define GHC_INLINE inline
-#ifndef GHC_FS_API
-#define GHC_FS_API
-#endif
-#ifndef GHC_FS_API_CLASS
-#define GHC_FS_API_CLASS
-#endif
-#endif
-
-#ifdef GHC_EXPAND_IMPL
-
-#ifdef GHC_OS_WINDOWS
-#include <windows.h>
-// additional includes
-#include <shellapi.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <wchar.h>
-#include <winioctl.h>
-#else
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#ifdef GHC_OS_ANDROID
-#include <android/api-level.h>
-#if __ANDROID_API__ < 12
-#include <sys/syscall.h>
-#endif
-#include <sys/vfs.h>
-#define statvfs statfs
-#else
-#include <sys/statvfs.h>
-#endif
-#ifdef GHC_OS_CYGWIN
-#include <strings.h>
-#endif
-#if !defined(__ANDROID__) || __ANDROID_API__ >= 26
-#include <langinfo.h>
-#endif
-#endif
-#ifdef GHC_OS_MACOS
-#include <Availability.h>
-#endif
-
-#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)
-#if __has_include(<compare>)
-#define GHC_HAS_THREEWAY_COMP
-#include <compare>
-#endif
-#endif
-
-#include <algorithm>
-#include <cctype>
-#include <chrono>
-#include <clocale>
-#include <cstdlib>
-#include <cstring>
-#include <fstream>
-#include <functional>
-#include <memory>
-#include <stack>
-#include <stdexcept>
-#include <string>
-#include <system_error>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-#else  // GHC_EXPAND_IMPL
-
-#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)
-#if __has_include(<compare>)
-#define GHC_HAS_THREEWAY_COMP
-#include <compare>
-#endif
-#endif
-#include <chrono>
-#include <fstream>
-#include <memory>
-#include <stack>
-#include <stdexcept>
-#include <string>
-#include <system_error>
-#ifdef GHC_OS_WINDOWS
-#include <vector>
-#endif
-#endif  // GHC_EXPAND_IMPL
-
-// After standard library includes.
-// Standard library support for std::string_view.
-#if defined(__cpp_lib_string_view)
-#define GHC_HAS_STD_STRING_VIEW
-#elif defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 4000) && (__cplusplus >= 201402)
-#define GHC_HAS_STD_STRING_VIEW
-#elif defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 7) && (__cplusplus >= 201703)
-#define GHC_HAS_STD_STRING_VIEW
-#elif defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)
-#define GHC_HAS_STD_STRING_VIEW
-#endif
-
-// Standard library support for std::experimental::string_view.
-#if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 3700 && _LIBCPP_VERSION < 7000) && (__cplusplus >= 201402)
-#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW
-#elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402)
-#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW
-#elif defined(__GLIBCXX__) && defined(_GLIBCXX_USE_DUAL_ABI) && (__cplusplus >= 201402)
-// macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5 and newer
-#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW
-#endif
-
-#if defined(GHC_HAS_STD_STRING_VIEW)
-#include <string_view>
-#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)
-#include <experimental/string_view>
-#endif
-
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp):
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Enforce C++17 API where possible when compiling for C++20, handles the following cases:
-// * fs::path::u8string() returns std::string instead of std::u8string
-// #define GHC_FILESYSTEM_ENFORCE_CPP17_API
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
-// configure LWG conformance ()
-#define LWG_2682_BEHAVIOUR
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
-// file with that name, it is superseded by P1164R1, so only activate if really needed
-// #define LWG_2935_BEHAVIOUR
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// LWG #2936 enables new element wise (more expensive) path comparison
-// * if this->root_name().native().compare(p.root_name().native()) != 0 return result
-// * if this->has_root_directory() and !p.has_root_directory() return -1
-// * if !this->has_root_directory() and p.has_root_directory() return -1
-// * else result of element wise comparison of path iteration where first comparison is != 0 or 0
-//   if all comparisons are 0 (on Windows this implementation does case insensitive root_name()
-//   comparison)
-#define LWG_2936_BEHAVIOUR
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
-#define LWG_2937_BEHAVIOUR
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the windows
-// version defaults to std::wstring storage backend. Still all std::string will be interpreted
-// as UTF-8 encoded. With this define you can enfoce the old behavior on Windows, using
-// std::string as backend and for fs::path::native() and char for fs::path::c_str(). This
-// needs more conversions so it is (an was before v1.5) slower, bot might help keeping source
-// homogeneous in a multi platform project.
-// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found,
-// instead of replacing them with the unicode replacement character (U+FFFD).
-// #define GHC_RAISE_UNICODE_ERRORS
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Automatic prefix windows path with "\\?\" if they would break the MAX_PATH length.
-// instead of replacing them with the unicode replacement character (U+FFFD).
-#ifndef GHC_WIN_DISABLE_AUTO_PREFIXES
-#define GHC_WIN_AUTO_PREFIX_LONG_PATH
-#endif  // GHC_WIN_DISABLE_AUTO_PREFIXES
-//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
-#define GHC_FILESYSTEM_VERSION 10506L
-
-#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
-#define GHC_WITH_EXCEPTIONS
-#endif
-#if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS)
-#error "Can't raise unicode errors with exception support disabled"
-#endif
-
-namespace ghc {
-namespace filesystem {
-
-#if defined(GHC_HAS_CUSTOM_STRING_VIEW)
-#define GHC_WITH_STRING_VIEW
-#elif defined(GHC_HAS_STD_STRING_VIEW)
-#define GHC_WITH_STRING_VIEW
-using std::basic_string_view;
-#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)
-#define GHC_WITH_STRING_VIEW
-using std::experimental::basic_string_view;
-#endif
-
-// temporary existing exception type for yet unimplemented parts
-class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error
-{
-public:
-    not_implemented_exception()
-        : std::logic_error("function not implemented yet.")
-    {
-    }
-};
-
-template <typename char_type>
-class path_helper_base
-{
-public:
-    using value_type = char_type;
-#ifdef GHC_OS_WINDOWS
-    static constexpr value_type preferred_separator = '\\';
-#else
-    static constexpr value_type preferred_separator = '/';
-#endif
-};
-
-#if __cplusplus < 201703L
-template <typename char_type>
-constexpr char_type path_helper_base<char_type>::preferred_separator;
-#endif
-
-#ifdef GHC_OS_WINDOWS
-class path;
-namespace detail {
-bool has_executable_extension(const path& p);
-}
-#endif
-
-// [fs.class.path] class path
-class GHC_FS_API_CLASS path
-#if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE)
-#define GHC_USE_WCHAR_T
-#define GHC_NATIVEWP(p) p.c_str()
-#define GHC_PLATFORM_LITERAL(str) L##str
-    : private path_helper_base<std::wstring::value_type>
-{
-public:
-    using path_helper_base<std::wstring::value_type>::value_type;
-#else
-#define GHC_NATIVEWP(p) p.wstring().c_str()
-#define GHC_PLATFORM_LITERAL(str) str
-    : private path_helper_base<std::string::value_type>
-{
-public:
-    using path_helper_base<std::string::value_type>::value_type;
-#endif
-    using string_type = std::basic_string<value_type>;
-    using path_helper_base<value_type>::preferred_separator;
-
-    // [fs.enum.path.format] enumeration format
-    /// The path format in which the constructor argument is given.
-    enum format {
-        generic_format,  ///< The generic format, internally used by
-                         ///< ghc::filesystem::path with slashes
-        native_format,   ///< The format native to the current platform this code
-                         ///< is build for
-        auto_format,     ///< Try to auto-detect the format, fallback to native
-    };
-
-    template <class T>
-    struct _is_basic_string : std::false_type
-    {
-    };
-    template <class CharT, class Traits, class Alloc>
-    struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type
-    {
-    };
-    template <class CharT>
-    struct _is_basic_string<std::basic_string<CharT, std::char_traits<CharT>, std::allocator<CharT>>> : std::true_type
-    {
-    };
-#ifdef GHC_WITH_STRING_VIEW
-    template <class CharT, class Traits>
-    struct _is_basic_string<basic_string_view<CharT, Traits>> : std::true_type
-    {
-    };
-    template <class CharT>
-    struct _is_basic_string<basic_string_view<CharT, std::char_traits<CharT>>> : std::true_type
-    {
-    };
-#endif
-
-    template <typename T1, typename T2 = void>
-    using path_type = typename std::enable_if<!std::is_same<path, T1>::value, path>::type;
-    template <typename T>
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-    using path_from_string =
-        typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value || std::is_same<char8_t const*, typename std::decay<T>::type>::value ||
-                                    std::is_same<char8_t*, typename std::decay<T>::type>::value || std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value ||
-                                    std::is_same<char32_t const*, typename std::decay<T>::type>::value || std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value ||
-                                    std::is_same<wchar_t*, typename std::decay<T>::type>::value,
-                                path>::type;
-    template <typename T>
-    using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char8_t>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
-#else
-    using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value ||
-                                    std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value || std::is_same<char32_t const*, typename std::decay<T>::type>::value ||
-                                    std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value,
-        path>::type;
-    template <typename T>
-    using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
-#endif
-    // [fs.path.construct] constructors and destructor
-    path() noexcept;
-    path(const path& p);
-    path(path&& p) noexcept;
-    path(string_type&& source, format fmt = auto_format);
-    template <class Source, typename = path_from_string<Source>>
-    path(const Source& source, format fmt = auto_format);
-    template <class InputIterator>
-    path(InputIterator first, InputIterator last, format fmt = auto_format);
-#ifdef GHC_WITH_EXCEPTIONS
-    template <class Source, typename = path_from_string<Source>>
-    path(const Source& source, const std::locale& loc, format fmt = auto_format);
-    template <class InputIterator>
-    path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format);
-#endif
-    ~path();
-
-    // [fs.path.assign] assignments
-    path& operator=(const path& p);
-    path& operator=(path&& p) noexcept;
-    path& operator=(string_type&& source);
-    path& assign(string_type&& source);
-    template <class Source>
-    path& operator=(const Source& source);
-    template <class Source>
-    path& assign(const Source& source);
-    template <class InputIterator>
-    path& assign(InputIterator first, InputIterator last);
-
-    // [fs.path.append] appends
-    path& operator/=(const path& p);
-    template <class Source>
-    path& operator/=(const Source& source);
-    template <class Source>
-    path& append(const Source& source);
-    template <class InputIterator>
-    path& append(InputIterator first, InputIterator last);
-
-    // [fs.path.concat] concatenation
-    path& operator+=(const path& x);
-    path& operator+=(const string_type& x);
-#ifdef GHC_WITH_STRING_VIEW
-    path& operator+=(basic_string_view<value_type> x);
-#endif
-    path& operator+=(const value_type* x);
-    path& operator+=(value_type x);
-    template <class Source>
-    path_from_string<Source>& operator+=(const Source& x);
-    template <class EcharT>
-    path_type_EcharT<EcharT>& operator+=(EcharT x);
-    template <class Source>
-    path& concat(const Source& x);
-    template <class InputIterator>
-    path& concat(InputIterator first, InputIterator last);
-
-    // [fs.path.modifiers] modifiers
-    void clear() noexcept;
-    path& make_preferred();
-    path& remove_filename();
-    path& replace_filename(const path& replacement);
-    path& replace_extension(const path& replacement = path());
-    void swap(path& rhs) noexcept;
-
-    // [fs.path.native.obs] native format observers
-    const string_type& native() const noexcept;
-    const value_type* c_str() const noexcept;
-    operator string_type() const;
-    template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>>
-    std::basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const;
-    std::string string() const;
-    std::wstring wstring() const;
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-    std::u8string u8string() const;
-#else
-    std::string u8string() const;
-#endif
-    std::u16string u16string() const;
-    std::u32string u32string() const;
-
-    // [fs.path.generic.obs] generic format observers
-    template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>>
-    std::basic_string<EcharT, traits, Allocator> generic_string(const Allocator& a = Allocator()) const;
-    std::string generic_string() const;
-    std::wstring generic_wstring() const;
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-    std::u8string generic_u8string() const;
-#else
-    std::string generic_u8string() const;
-#endif
-    std::u16string generic_u16string() const;
-    std::u32string generic_u32string() const;
-
-    // [fs.path.compare] compare
-    int compare(const path& p) const noexcept;
-    int compare(const string_type& s) const;
-#ifdef GHC_WITH_STRING_VIEW
-    int compare(basic_string_view<value_type> s) const;
-#endif
-    int compare(const value_type* s) const;
-
-    // [fs.path.decompose] decomposition
-    path root_name() const;
-    path root_directory() const;
-    path root_path() const;
-    path relative_path() const;
-    path parent_path() const;
-    path filename() const;
-    path stem() const;
-    path extension() const;
-
-    // [fs.path.query] query
-    bool empty() const noexcept;
-    bool has_root_name() const;
-    bool has_root_directory() const;
-    bool has_root_path() const;
-    bool has_relative_path() const;
-    bool has_parent_path() const;
-    bool has_filename() const;
-    bool has_stem() const;
-    bool has_extension() const;
-    bool is_absolute() const;
-    bool is_relative() const;
-
-    // [fs.path.gen] generation
-    path lexically_normal() const;
-    path lexically_relative(const path& base) const;
-    path lexically_proximate(const path& base) const;
-
-    // [fs.path.itr] iterators
-    class iterator;
-    using const_iterator = iterator;
-    iterator begin() const;
-    iterator end() const;
-
-private:
-    using impl_value_type = value_type;
-    using impl_string_type = std::basic_string<impl_value_type>;
-    friend class directory_iterator;
-    void append_name(const value_type* name);
-    static constexpr impl_value_type generic_separator = '/';
-    template <typename InputIterator>
-    class input_iterator_range
-    {
-    public:
-        typedef InputIterator iterator;
-        typedef InputIterator const_iterator;
-        typedef typename InputIterator::difference_type difference_type;
-
-        input_iterator_range(const InputIterator& first, const InputIterator& last)
-            : _first(first)
-            , _last(last)
-        {
-        }
-
-        InputIterator begin() const { return _first; }
-        InputIterator end() const { return _last; }
-
-    private:
-        InputIterator _first;
-        InputIterator _last;
-    };
-    friend void swap(path& lhs, path& rhs) noexcept;
-    friend size_t hash_value(const path& p) noexcept;
-    friend path canonical(const path& p, std::error_code& ec);
-    string_type::size_type root_name_length() const noexcept;
-    void postprocess_path_with_format(format fmt);
-    void check_long_path();
-    impl_string_type _path;
-#ifdef GHC_OS_WINDOWS
-    void handle_prefixes();
-    friend bool detail::has_executable_extension(const path& p);
-#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
-    string_type::size_type _prefixLength{0};
-#else  // GHC_WIN_AUTO_PREFIX_LONG_PATH
-    static const string_type::size_type _prefixLength{0};
-#endif  // GHC_WIN_AUTO_PREFIX_LONG_PATH
-#else
-    static const string_type::size_type _prefixLength{0};
-#endif
-};
-
-// [fs.path.nonmember] path non-member functions
-GHC_FS_API void swap(path& lhs, path& rhs) noexcept;
-GHC_FS_API size_t hash_value(const path& p) noexcept;
-#ifdef GHC_HAS_THREEWAY_COMP
-GHC_FS_API std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept;
-#endif
-GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept;
-GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept;
-GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept;
-GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept;
-GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept;
-GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept;
-GHC_FS_API path operator/(const path& lhs, const path& rhs);
-
-// [fs.path.io] path inserter and extractor
-template <class charT, class traits>
-std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p);
-template <class charT, class traits>
-std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p);
-
-// [pfs.path.factory] path factory functions
-template <class Source, typename = path::path_from_string<Source>>
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]]
-#endif
-path u8path(const Source& source);
-template <class InputIterator>
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]]
-#endif
-path u8path(InputIterator first, InputIterator last);
-
-// [fs.class.filesystem_error] class filesystem_error
-class GHC_FS_API_CLASS filesystem_error : public std::system_error
-{
-public:
-    filesystem_error(const std::string& what_arg, std::error_code ec);
-    filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec);
-    filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec);
-    const path& path1() const noexcept;
-    const path& path2() const noexcept;
-    const char* what() const noexcept override;
-
-private:
-    std::string _what_arg;
-    std::error_code _ec;
-    path _p1, _p2;
-};
-
-class GHC_FS_API_CLASS path::iterator
-{
-public:
-    using value_type = const path;
-    using difference_type = std::ptrdiff_t;
-    using pointer = const path*;
-    using reference = const path&;
-    using iterator_category = std::bidirectional_iterator_tag;
-
-    iterator();
-    iterator(const path& p, const impl_string_type::const_iterator& pos);
-    iterator& operator++();
-    iterator operator++(int);
-    iterator& operator--();
-    iterator operator--(int);
-    bool operator==(const iterator& other) const;
-    bool operator!=(const iterator& other) const;
-    reference operator*() const;
-    pointer operator->() const;
-
-private:
-    friend class path;
-    impl_string_type::const_iterator increment(const impl_string_type::const_iterator& pos) const;
-    impl_string_type::const_iterator decrement(const impl_string_type::const_iterator& pos) const;
-    void updateCurrent();
-    impl_string_type::const_iterator _first;
-    impl_string_type::const_iterator _last;
-    impl_string_type::const_iterator _prefix;
-    impl_string_type::const_iterator _root;
-    impl_string_type::const_iterator _iter;
-    path _current;
-};
-
-struct space_info
-{
-    uintmax_t capacity;
-    uintmax_t free;
-    uintmax_t available;
-};
-
-// [fs.enum] enumerations
-// [fs.enum.file_type]
-enum class file_type {
-    none,
-    not_found,
-    regular,
-    directory,
-    symlink,
-    block,
-    character,
-    fifo,
-    socket,
-    unknown,
-};
-
-// [fs.enum.perms]
-enum class perms : uint16_t {
-    none = 0,
-
-    owner_read = 0400,
-    owner_write = 0200,
-    owner_exec = 0100,
-    owner_all = 0700,
-
-    group_read = 040,
-    group_write = 020,
-    group_exec = 010,
-    group_all = 070,
-
-    others_read = 04,
-    others_write = 02,
-    others_exec = 01,
-    others_all = 07,
-
-    all = 0777,
-    set_uid = 04000,
-    set_gid = 02000,
-    sticky_bit = 01000,
-
-    mask = 07777,
-    unknown = 0xffff
-};
-
-// [fs.enum.perm.opts]
-enum class perm_options : uint16_t {
-    replace = 3,
-    add = 1,
-    remove = 2,
-    nofollow = 4,
-};
-
-// [fs.enum.copy.opts]
-enum class copy_options : uint16_t {
-    none = 0,
-
-    skip_existing = 1,
-    overwrite_existing = 2,
-    update_existing = 4,
-
-    recursive = 8,
-
-    copy_symlinks = 0x10,
-    skip_symlinks = 0x20,
-
-    directories_only = 0x40,
-    create_symlinks = 0x80,
-#ifndef GHC_OS_WEB
-    create_hard_links = 0x100
-#endif
-};
-
-// [fs.enum.dir.opts]
-enum class directory_options : uint16_t {
-    none = 0,
-    follow_directory_symlink = 1,
-    skip_permission_denied = 2,
-};
-
-// [fs.class.file_status] class file_status
-class GHC_FS_API_CLASS file_status
-{
-public:
-    // [fs.file_status.cons] constructors and destructor
-    file_status() noexcept;
-    explicit file_status(file_type ft, perms prms = perms::unknown) noexcept;
-    file_status(const file_status&) noexcept;
-    file_status(file_status&&) noexcept;
-    ~file_status();
-    // assignments:
-    file_status& operator=(const file_status&) noexcept;
-    file_status& operator=(file_status&&) noexcept;
-    // [fs.file_status.mods] modifiers
-    void type(file_type ft) noexcept;
-    void permissions(perms prms) noexcept;
-    // [fs.file_status.obs] observers
-    file_type type() const noexcept;
-    perms permissions() const noexcept;
-    friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }
-private:
-    file_type _type;
-    perms _perms;
-};
-
-using file_time_type = std::chrono::time_point<std::chrono::system_clock>;
-
-// [fs.class.directory_entry] Class directory_entry
-class GHC_FS_API_CLASS directory_entry
-{
-public:
-    // [fs.dir.entry.cons] constructors and destructor
-    directory_entry() noexcept = default;
-    directory_entry(const directory_entry&) = default;
-    directory_entry(directory_entry&&) noexcept = default;
-#ifdef GHC_WITH_EXCEPTIONS
-    explicit directory_entry(const path& p);
-#endif
-    directory_entry(const path& p, std::error_code& ec);
-    ~directory_entry();
-
-    // assignments:
-    directory_entry& operator=(const directory_entry&) = default;
-    directory_entry& operator=(directory_entry&&) noexcept = default;
-
-    // [fs.dir.entry.mods] modifiers
-#ifdef GHC_WITH_EXCEPTIONS
-    void assign(const path& p);
-    void replace_filename(const path& p);
-    void refresh();
-#endif
-    void assign(const path& p, std::error_code& ec);
-    void replace_filename(const path& p, std::error_code& ec);
-    void refresh(std::error_code& ec) noexcept;
-
-    // [fs.dir.entry.obs] observers
-    const filesystem::path& path() const noexcept;
-    operator const filesystem::path&() const noexcept;
-#ifdef GHC_WITH_EXCEPTIONS
-    bool exists() const;
-    bool is_block_file() const;
-    bool is_character_file() const;
-    bool is_directory() const;
-    bool is_fifo() const;
-    bool is_other() const;
-    bool is_regular_file() const;
-    bool is_socket() const;
-    bool is_symlink() const;
-    uintmax_t file_size() const;
-    file_time_type last_write_time() const;
-    file_status status() const;
-    file_status symlink_status() const;
-#endif
-    bool exists(std::error_code& ec) const noexcept;
-    bool is_block_file(std::error_code& ec) const noexcept;
-    bool is_character_file(std::error_code& ec) const noexcept;
-    bool is_directory(std::error_code& ec) const noexcept;
-    bool is_fifo(std::error_code& ec) const noexcept;
-    bool is_other(std::error_code& ec) const noexcept;
-    bool is_regular_file(std::error_code& ec) const noexcept;
-    bool is_socket(std::error_code& ec) const noexcept;
-    bool is_symlink(std::error_code& ec) const noexcept;
-    uintmax_t file_size(std::error_code& ec) const noexcept;
-    file_time_type last_write_time(std::error_code& ec) const noexcept;
-    file_status status(std::error_code& ec) const noexcept;
-    file_status symlink_status(std::error_code& ec) const noexcept;
-
-#ifndef GHC_OS_WEB
-#ifdef GHC_WITH_EXCEPTIONS
-    uintmax_t hard_link_count() const;
-#endif
-    uintmax_t hard_link_count(std::error_code& ec) const noexcept;
-#endif
-
-#ifdef GHC_HAS_THREEWAY_COMP
-    std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept;
-#endif
-    bool operator<(const directory_entry& rhs) const noexcept;
-    bool operator==(const directory_entry& rhs) const noexcept;
-    bool operator!=(const directory_entry& rhs) const noexcept;
-    bool operator<=(const directory_entry& rhs) const noexcept;
-    bool operator>(const directory_entry& rhs) const noexcept;
-    bool operator>=(const directory_entry& rhs) const noexcept;
-
-private:
-    friend class directory_iterator;
-#ifdef GHC_WITH_EXCEPTIONS
-    file_type status_file_type() const;
-#endif
-    file_type status_file_type(std::error_code& ec) const noexcept;
-    filesystem::path _path;
-    file_status _status;
-    file_status _symlink_status;
-    uintmax_t _file_size = static_cast<uintmax_t>(-1);
-#ifndef GHC_OS_WINDOWS
-    uintmax_t _hard_link_count = static_cast<uintmax_t>(-1);
-#endif
-    time_t _last_write_time = 0;
-};
-
-// [fs.class.directory.iterator] Class directory_iterator
-class GHC_FS_API_CLASS directory_iterator
-{
-public:
-    class GHC_FS_API_CLASS proxy
-    {
-    public:
-        const directory_entry& operator*() const& noexcept { return _dir_entry; }
-        directory_entry operator*() && noexcept { return std::move(_dir_entry); }
-
-    private:
-        explicit proxy(const directory_entry& dir_entry)
-            : _dir_entry(dir_entry)
-        {
-        }
-        friend class directory_iterator;
-        friend class recursive_directory_iterator;
-        directory_entry _dir_entry;
-    };
-    using iterator_category = std::input_iterator_tag;
-    using value_type = directory_entry;
-    using difference_type = std::ptrdiff_t;
-    using pointer = const directory_entry*;
-    using reference = const directory_entry&;
-
-    // [fs.dir.itr.members] member functions
-    directory_iterator() noexcept;
-#ifdef GHC_WITH_EXCEPTIONS
-    explicit directory_iterator(const path& p);
-    directory_iterator(const path& p, directory_options options);
-#endif
-    directory_iterator(const path& p, std::error_code& ec) noexcept;
-    directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept;
-    directory_iterator(const directory_iterator& rhs);
-    directory_iterator(directory_iterator&& rhs) noexcept;
-    ~directory_iterator();
-    directory_iterator& operator=(const directory_iterator& rhs);
-    directory_iterator& operator=(directory_iterator&& rhs) noexcept;
-    const directory_entry& operator*() const;
-    const directory_entry* operator->() const;
-#ifdef GHC_WITH_EXCEPTIONS
-    directory_iterator& operator++();
-#endif
-    directory_iterator& increment(std::error_code& ec) noexcept;
-
-    // other members as required by [input.iterators]
-#ifdef GHC_WITH_EXCEPTIONS
-    proxy operator++(int)
-    {
-        proxy p{**this};
-        ++*this;
-        return p;
-    }
-#endif
-    bool operator==(const directory_iterator& rhs) const;
-    bool operator!=(const directory_iterator& rhs) const;
-
-private:
-    friend class recursive_directory_iterator;
-    class impl;
-    std::shared_ptr<impl> _impl;
-};
-
-// [fs.dir.itr.nonmembers] directory_iterator non-member functions
-GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept;
-GHC_FS_API directory_iterator end(const directory_iterator&) noexcept;
-
-// [fs.class.re.dir.itr] class recursive_directory_iterator
-class GHC_FS_API_CLASS recursive_directory_iterator
-{
-public:
-    using iterator_category = std::input_iterator_tag;
-    using value_type = directory_entry;
-    using difference_type = std::ptrdiff_t;
-    using pointer = const directory_entry*;
-    using reference = const directory_entry&;
-
-    // [fs.rec.dir.itr.members] constructors and destructor
-    recursive_directory_iterator() noexcept;
-#ifdef GHC_WITH_EXCEPTIONS
-    explicit recursive_directory_iterator(const path& p);
-    recursive_directory_iterator(const path& p, directory_options options);
-#endif
-    recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept;
-    recursive_directory_iterator(const path& p, std::error_code& ec) noexcept;
-    recursive_directory_iterator(const recursive_directory_iterator& rhs);
-    recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept;
-    ~recursive_directory_iterator();
-
-    // [fs.rec.dir.itr.members] observers
-    directory_options options() const;
-    int depth() const;
-    bool recursion_pending() const;
-
-    const directory_entry& operator*() const;
-    const directory_entry* operator->() const;
-
-    // [fs.rec.dir.itr.members] modifiers recursive_directory_iterator&
-    recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs);
-    recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept;
-#ifdef GHC_WITH_EXCEPTIONS
-    recursive_directory_iterator& operator++();
-#endif
-    recursive_directory_iterator& increment(std::error_code& ec) noexcept;
-
-#ifdef GHC_WITH_EXCEPTIONS
-    void pop();
-#endif
-    void pop(std::error_code& ec);
-    void disable_recursion_pending();
-
-    // other members as required by [input.iterators]
-#ifdef GHC_WITH_EXCEPTIONS
-    directory_iterator::proxy operator++(int)
-    {
-        directory_iterator::proxy proxy{**this};
-        ++*this;
-        return proxy;
-    }
-#endif
-    bool operator==(const recursive_directory_iterator& rhs) const;
-    bool operator!=(const recursive_directory_iterator& rhs) const;
-
-private:
-    struct recursive_directory_iterator_impl
-    {
-        directory_options _options;
-        bool _recursion_pending;
-        std::stack<directory_iterator> _dir_iter_stack;
-        recursive_directory_iterator_impl(directory_options options, bool recursion_pending)
-            : _options(options)
-            , _recursion_pending(recursion_pending)
-        {
-        }
-    };
-    std::shared_ptr<recursive_directory_iterator_impl> _impl;
-};
-
-// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions
-GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
-GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
-
-// [fs.op.funcs] filesystem operations
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_FS_API path absolute(const path& p);
-GHC_FS_API path canonical(const path& p);
-GHC_FS_API void copy(const path& from, const path& to);
-GHC_FS_API void copy(const path& from, const path& to, copy_options options);
-GHC_FS_API bool copy_file(const path& from, const path& to);
-GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option);
-GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink);
-GHC_FS_API bool create_directories(const path& p);
-GHC_FS_API bool create_directory(const path& p);
-GHC_FS_API bool create_directory(const path& p, const path& attributes);
-GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink);
-GHC_FS_API void create_symlink(const path& to, const path& new_symlink);
-GHC_FS_API path current_path();
-GHC_FS_API void current_path(const path& p);
-GHC_FS_API bool exists(const path& p);
-GHC_FS_API bool equivalent(const path& p1, const path& p2);
-GHC_FS_API uintmax_t file_size(const path& p);
-GHC_FS_API bool is_block_file(const path& p);
-GHC_FS_API bool is_character_file(const path& p);
-GHC_FS_API bool is_directory(const path& p);
-GHC_FS_API bool is_empty(const path& p);
-GHC_FS_API bool is_fifo(const path& p);
-GHC_FS_API bool is_other(const path& p);
-GHC_FS_API bool is_regular_file(const path& p);
-GHC_FS_API bool is_socket(const path& p);
-GHC_FS_API bool is_symlink(const path& p);
-GHC_FS_API file_time_type last_write_time(const path& p);
-GHC_FS_API void last_write_time(const path& p, file_time_type new_time);
-GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace);
-GHC_FS_API path proximate(const path& p, const path& base = current_path());
-GHC_FS_API path read_symlink(const path& p);
-GHC_FS_API path relative(const path& p, const path& base = current_path());
-GHC_FS_API bool remove(const path& p);
-GHC_FS_API uintmax_t remove_all(const path& p);
-GHC_FS_API void rename(const path& from, const path& to);
-GHC_FS_API void resize_file(const path& p, uintmax_t size);
-GHC_FS_API space_info space(const path& p);
-GHC_FS_API file_status status(const path& p);
-GHC_FS_API file_status symlink_status(const path& p);
-GHC_FS_API path temp_directory_path();
-GHC_FS_API path weakly_canonical(const path& p);
-#endif
-GHC_FS_API path absolute(const path& p, std::error_code& ec);
-GHC_FS_API path canonical(const path& p, std::error_code& ec);
-GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept;
-GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept;
-GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept;
-GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept;
-GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept;
-GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept;
-GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
-GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
-GHC_FS_API path current_path(std::error_code& ec);
-GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool exists(file_status s) noexcept;
-GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept;
-GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_block_file(file_status s) noexcept;
-GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_character_file(file_status s) noexcept;
-GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_directory(file_status s) noexcept;
-GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_fifo(file_status s) noexcept;
-GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_other(file_status s) noexcept;
-GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_regular_file(file_status s) noexcept;
-GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_socket(file_status s) noexcept;
-GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool is_symlink(file_status s) noexcept;
-GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept;
-GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept;
-GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept;
-GHC_FS_API path proximate(const path& p, std::error_code& ec);
-GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec);
-GHC_FS_API path read_symlink(const path& p, std::error_code& ec);
-GHC_FS_API path relative(const path& p, std::error_code& ec);
-GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec);
-GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept;
-GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept;
-GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API bool status_known(file_status s) noexcept;
-GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept;
-GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept;
-GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept;
-
-#ifndef GHC_OS_WEB
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link);
-GHC_FS_API uintmax_t hard_link_count(const path& p);
-#endif
-GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept;
-GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;
-#endif
-
-// Non-C++17 add-on std::fstream wrappers with path
-template <class charT, class traits = std::char_traits<charT>>
-class basic_filebuf : public std::basic_filebuf<charT, traits>
-{
-public:
-    basic_filebuf() {}
-    ~basic_filebuf() override {}
-    basic_filebuf(const basic_filebuf&) = delete;
-    const basic_filebuf& operator=(const basic_filebuf&) = delete;
-    basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode)
-    {
-#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
-        return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0;
-#else
-        return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0;
-#endif
-    }
-};
-
-template <class charT, class traits = std::char_traits<charT>>
-class basic_ifstream : public std::basic_ifstream<charT, traits>
-{
-public:
-    basic_ifstream() {}
-#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
-    explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)
-        : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode)
-    {
-    }
-    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.wstring().c_str(), mode); }
-#else
-    explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)
-        : std::basic_ifstream<charT, traits>(p.string().c_str(), mode)
-    {
-    }
-    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.string().c_str(), mode); }
-#endif
-    basic_ifstream(const basic_ifstream&) = delete;
-    const basic_ifstream& operator=(const basic_ifstream&) = delete;
-    ~basic_ifstream() override {}
-};
-
-template <class charT, class traits = std::char_traits<charT>>
-class basic_ofstream : public std::basic_ofstream<charT, traits>
-{
-public:
-    basic_ofstream() {}
-#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
-    explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)
-        : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode)
-    {
-    }
-    void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.wstring().c_str(), mode); }
-#else
-    explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)
-        : std::basic_ofstream<charT, traits>(p.string().c_str(), mode)
-    {
-    }
-    void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.string().c_str(), mode); }
-#endif
-    basic_ofstream(const basic_ofstream&) = delete;
-    const basic_ofstream& operator=(const basic_ofstream&) = delete;
-    ~basic_ofstream() override {}
-};
-
-template <class charT, class traits = std::char_traits<charT>>
-class basic_fstream : public std::basic_fstream<charT, traits>
-{
-public:
-    basic_fstream() {}
-#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
-    explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
-        : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode)
-    {
-    }
-    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.wstring().c_str(), mode); }
-#else
-    explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
-        : std::basic_fstream<charT, traits>(p.string().c_str(), mode)
-    {
-    }
-    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.string().c_str(), mode); }
-#endif
-    basic_fstream(const basic_fstream&) = delete;
-    const basic_fstream& operator=(const basic_fstream&) = delete;
-    ~basic_fstream() override {}
-};
-
-typedef basic_filebuf<char> filebuf;
-typedef basic_filebuf<wchar_t> wfilebuf;
-typedef basic_ifstream<char> ifstream;
-typedef basic_ifstream<wchar_t> wifstream;
-typedef basic_ofstream<char> ofstream;
-typedef basic_ofstream<wchar_t> wofstream;
-typedef basic_fstream<char> fstream;
-typedef basic_fstream<wchar_t> wfstream;
-
-class GHC_FS_API_CLASS u8arguments
-{
-public:
-    u8arguments(int& argc, char**& argv);
-    ~u8arguments()
-    {
-        _refargc = _argc;
-        _refargv = _argv;
-    }
-
-    bool valid() const { return _isvalid; }
-
-private:
-    int _argc;
-    char** _argv;
-    int& _refargc;
-    char**& _refargv;
-    bool _isvalid;
-#ifdef GHC_OS_WINDOWS
-    std::vector<std::string> _args;
-    std::vector<char*> _argp;
-#endif
-};
-
-//-------------------------------------------------------------------------------------------------
-//  Implementation
-//-------------------------------------------------------------------------------------------------
-
-namespace detail {
-enum utf8_states_t { S_STRT = 0, S_RJCT = 8 };
-GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode);
-GHC_FS_API bool is_surrogate(uint32_t c);
-GHC_FS_API bool is_high_surrogate(uint32_t c);
-GHC_FS_API bool is_low_surrogate(uint32_t c);
-GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint);
-enum class portable_error {
-    none = 0,
-    exists,
-    not_found,
-    not_supported,
-    not_implemented,
-    invalid_argument,
-    is_a_directory,
-};
-GHC_FS_API std::error_code make_error_code(portable_error err);
-#ifdef GHC_OS_WINDOWS
-GHC_FS_API std::error_code make_system_error(uint32_t err = 0);
-#else
-GHC_FS_API std::error_code make_system_error(int err = 0);
-#endif
-}  // namespace detail
-
-namespace detail {
-
-#ifdef GHC_EXPAND_IMPL
-
-GHC_INLINE std::error_code make_error_code(portable_error err)
-{
-#ifdef GHC_OS_WINDOWS
-    switch (err) {
-        case portable_error::none:
-            return std::error_code();
-        case portable_error::exists:
-            return std::error_code(ERROR_ALREADY_EXISTS, std::system_category());
-        case portable_error::not_found:
-            return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category());
-        case portable_error::not_supported:
-            return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
-        case portable_error::not_implemented:
-            return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category());
-        case portable_error::invalid_argument:
-            return std::error_code(ERROR_INVALID_PARAMETER, std::system_category());
-        case portable_error::is_a_directory:
-#ifdef ERROR_DIRECTORY_NOT_SUPPORTED
-            return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category());
-#else
-            return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
-#endif
-    }
-#else
-    switch (err) {
-        case portable_error::none:
-            return std::error_code();
-        case portable_error::exists:
-            return std::error_code(EEXIST, std::system_category());
-        case portable_error::not_found:
-            return std::error_code(ENOENT, std::system_category());
-        case portable_error::not_supported:
-            return std::error_code(ENOTSUP, std::system_category());
-        case portable_error::not_implemented:
-            return std::error_code(ENOSYS, std::system_category());
-        case portable_error::invalid_argument:
-            return std::error_code(EINVAL, std::system_category());
-        case portable_error::is_a_directory:
-            return std::error_code(EISDIR, std::system_category());
-    }
-#endif
-    return std::error_code();
-}
-
-#ifdef GHC_OS_WINDOWS
-GHC_INLINE std::error_code make_system_error(uint32_t err)
-{
-    return std::error_code(err ? static_cast<int>(err) : static_cast<int>(::GetLastError()), std::system_category());
-}
-#else
-GHC_INLINE std::error_code make_system_error(int err)
-{
-    return std::error_code(err ? err : errno, std::system_category());
-}
-#endif
-
-#endif  // GHC_EXPAND_IMPL
-
-template <typename Enum>
-using EnableBitmask = typename std::enable_if<std::is_same<Enum, perms>::value || std::is_same<Enum, perm_options>::value || std::is_same<Enum, copy_options>::value || std::is_same<Enum, directory_options>::value, Enum>::type;
-}  // namespace detail
-
-template <typename Enum>
-constexpr detail::EnableBitmask<Enum> operator&(Enum X, Enum Y)
-{
-    using underlying = typename std::underlying_type<Enum>::type;
-    return static_cast<Enum>(static_cast<underlying>(X) & static_cast<underlying>(Y));
-}
-
-template <typename Enum>
-constexpr detail::EnableBitmask<Enum> operator|(Enum X, Enum Y)
-{
-    using underlying = typename std::underlying_type<Enum>::type;
-    return static_cast<Enum>(static_cast<underlying>(X) | static_cast<underlying>(Y));
-}
-
-template <typename Enum>
-constexpr detail::EnableBitmask<Enum> operator^(Enum X, Enum Y)
-{
-    using underlying = typename std::underlying_type<Enum>::type;
-    return static_cast<Enum>(static_cast<underlying>(X) ^ static_cast<underlying>(Y));
-}
-
-template <typename Enum>
-constexpr detail::EnableBitmask<Enum> operator~(Enum X)
-{
-    using underlying = typename std::underlying_type<Enum>::type;
-    return static_cast<Enum>(~static_cast<underlying>(X));
-}
-
-template <typename Enum>
-detail::EnableBitmask<Enum>& operator&=(Enum& X, Enum Y)
-{
-    X = X & Y;
-    return X;
-}
-
-template <typename Enum>
-detail::EnableBitmask<Enum>& operator|=(Enum& X, Enum Y)
-{
-    X = X | Y;
-    return X;
-}
-
-template <typename Enum>
-detail::EnableBitmask<Enum>& operator^=(Enum& X, Enum Y)
-{
-    X = X ^ Y;
-    return X;
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-namespace detail {
-
-GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi)
-{
-    return (static_cast<uint32_t>(c - lo) < (hi - lo + 1));
-}
-
-GHC_INLINE bool is_surrogate(uint32_t c)
-{
-    return in_range(c, 0xd800, 0xdfff);
-}
-
-GHC_INLINE bool is_high_surrogate(uint32_t c)
-{
-    return (c & 0xfffffc00) == 0xd800;
-}
-
-GHC_INLINE bool is_low_surrogate(uint32_t c)
-{
-    return (c & 0xfffffc00) == 0xdc00;
-}
-
-GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode)
-{
-    if (unicode <= 0x7f) {
-        str.push_back(static_cast<char>(unicode));
-    }
-    else if (unicode >= 0x80 && unicode <= 0x7ff) {
-        str.push_back(static_cast<char>((unicode >> 6) + 192));
-        str.push_back(static_cast<char>((unicode & 0x3f) + 128));
-    }
-    else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) {
-        str.push_back(static_cast<char>((unicode >> 12) + 224));
-        str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
-        str.push_back(static_cast<char>((unicode & 0x3f) + 128));
-    }
-    else if (unicode >= 0x10000 && unicode <= 0x10ffff) {
-        str.push_back(static_cast<char>((unicode >> 18) + 240));
-        str.push_back(static_cast<char>(((unicode & 0x3ffff) >> 12) + 128));
-        str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
-        str.push_back(static_cast<char>((unicode & 0x3f) + 128));
-    }
-    else {
-#ifdef GHC_RAISE_UNICODE_ERRORS
-        throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence));
-#else
-        appendUTF8(str, 0xfffd);
-#endif
-    }
-}
-
-// Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/)
-// and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding;
-// Generating debugging and shrinking my own DFA from scratch was a day of fun!
-GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint)
-{
-    static const uint32_t utf8_state_info[] = {
-        // encoded states
-        0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u,
-        0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u,          0u,          0u,          0u,
-    };
-    uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;
-    codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment);
-    return state == S_RJCT ? static_cast<unsigned>(S_RJCT) : static_cast<unsigned>((utf8_state_info[category + 16] >> (state << 2)) & 0xf);
-}
-
-GHC_INLINE bool validUtf8(const std::string& utf8String)
-{
-    std::string::const_iterator iter = utf8String.begin();
-    unsigned utf8_state = S_STRT;
-    std::uint32_t codepoint = 0;
-    while (iter < utf8String.end()) {
-        if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_RJCT) {
-            return false;
-        }
-    }
-    if (utf8_state) {
-        return false;
-    }
-    return true;
-}
-
-}  // namespace detail
-
-#endif
-
-namespace detail {
-
-template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr>
-inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
-{
-    return StringType(utf8String.begin(), utf8String.end(), alloc);
-}
-
-template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr>
-inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
-{
-    StringType result(alloc);
-    result.reserve(utf8String.length());
-    auto iter = utf8String.cbegin();
-    unsigned utf8_state = S_STRT;
-    std::uint32_t codepoint = 0;
-    while (iter < utf8String.cend()) {
-        if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {
-            if (codepoint <= 0xffff) {
-                result += static_cast<typename StringType::value_type>(codepoint);
-            }
-            else {
-                codepoint -= 0x10000;
-                result += static_cast<typename StringType::value_type>((codepoint >> 10) + 0xd800);
-                result += static_cast<typename StringType::value_type>((codepoint & 0x3ff) + 0xdc00);
-            }
-            codepoint = 0;
-        }
-        else if (utf8_state == S_RJCT) {
-#ifdef GHC_RAISE_UNICODE_ERRORS
-            throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
-#else
-            result += static_cast<typename StringType::value_type>(0xfffd);
-            utf8_state = S_STRT;
-            codepoint = 0;
-#endif
-        }
-    }
-    if (utf8_state) {
-#ifdef GHC_RAISE_UNICODE_ERRORS
-        throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
-#else
-        result += static_cast<typename StringType::value_type>(0xfffd);
-#endif
-    }
-    return result;
-}
-
-template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr>
-inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
-{
-    StringType result(alloc);
-    result.reserve(utf8String.length());
-    auto iter = utf8String.cbegin();
-    unsigned utf8_state = S_STRT;
-    std::uint32_t codepoint = 0;
-    while (iter < utf8String.cend()) {
-        if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {
-            result += static_cast<typename StringType::value_type>(codepoint);
-            codepoint = 0;
-        }
-        else if (utf8_state == S_RJCT) {
-#ifdef GHC_RAISE_UNICODE_ERRORS
-            throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
-#else
-            result += static_cast<typename StringType::value_type>(0xfffd);
-            utf8_state = S_STRT;
-            codepoint = 0;
-#endif
-        }
-    }
-    if (utf8_state) {
-#ifdef GHC_RAISE_UNICODE_ERRORS
-        throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));
-#else
-        result += static_cast<typename StringType::value_type>(0xfffd);
-#endif
-    }
-    return result;
-}
-
-template <class StringType, typename charT, std::size_t N>
-inline StringType fromUtf8(const charT (&utf8String)[N])
-{
-#ifdef GHC_WITH_STRING_VIEW
-    return fromUtf8<StringType>(basic_string_view<charT>(utf8String, N - 1));
-#else
-    return fromUtf8<StringType>(std::basic_string<charT>(utf8String, N - 1));
-#endif
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1>
-inline std::string toUtf8(const strT& unicodeString)
-{
-    return std::string(unicodeString.begin(), unicodeString.end());
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 2), int>::type size = 2>
-inline std::string toUtf8(const strT& unicodeString)
-{
-    std::string result;
-    for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) {
-        char32_t c = *iter;
-        if (is_surrogate(c)) {
-            ++iter;
-            if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) {
-                appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00);
-            }
-            else {
-#ifdef GHC_RAISE_UNICODE_ERRORS
-                throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence));
-#else
-                appendUTF8(result, 0xfffd);
-                if (iter == unicodeString.end()) {
-                    break;
-                }
-#endif
-            }
-        }
-        else {
-            appendUTF8(result, c);
-        }
-    }
-    return result;
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 4), int>::type size = 4>
-inline std::string toUtf8(const strT& unicodeString)
-{
-    std::string result;
-    for (auto c : unicodeString) {
-        appendUTF8(result, static_cast<uint32_t>(c));
-    }
-    return result;
-}
-
-template <typename charT>
-inline std::string toUtf8(const charT* unicodeString)
-{
-#ifdef GHC_WITH_STRING_VIEW
-    return toUtf8(basic_string_view<charT, std::char_traits<charT>>(unicodeString));
-#else
-    return toUtf8(std::basic_string<charT, std::char_traits<charT>>(unicodeString));
-#endif
-}
-
-#ifdef GHC_USE_WCHAR_T
-template <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 1), bool>::type = false>
-inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
-{
-    auto temp = toUtf8(wString);
-    return StringType(temp.begin(), temp.end(), alloc);
-}
-
-template <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 2), bool>::type = false>
-inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
-{
-    return StringType(wString.begin(), wString.end(), alloc);
-}
-
-template <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 4), bool>::type = false>
-inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
-{
-    auto temp = toUtf8(wString);
-    return fromUtf8<StringType>(temp, alloc);
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), bool>::type = false>
-inline std::wstring toWChar(const strT& unicodeString)
-{
-    return fromUtf8<std::wstring>(unicodeString);
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 2), bool>::type = false>
-inline std::wstring toWChar(const strT& unicodeString)
-{
-    return std::wstring(unicodeString.begin(), unicodeString.end());
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 4), bool>::type = false>
-inline std::wstring toWChar(const strT& unicodeString)
-{
-    auto temp = toUtf8(unicodeString);
-    return fromUtf8<std::wstring>(temp);
-}
-
-template <typename charT>
-inline std::wstring toWChar(const charT* unicodeString)
-{
-#ifdef GHC_WITH_STRING_VIEW
-    return toWChar(basic_string_view<charT, std::char_traits<charT>>(unicodeString));
-#else
-    return toWChar(std::basic_string<charT, std::char_traits<charT>>(unicodeString));
-#endif
-}
-#endif // GHC_USE_WCHAR_T
-
-}  // namespace detail
-
-#ifdef GHC_EXPAND_IMPL
-
-namespace detail {
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>
-GHC_INLINE bool startsWith(const strT& what, const strT& with)
-{
-    return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin());
-}
-
-template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>
-GHC_INLINE bool endsWith(const strT& what, const strT& with)
-{
-    return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0;
-}
-
-}  // namespace detail
-
-GHC_INLINE void path::check_long_path()
-{
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) {
-        postprocess_path_with_format(native_format);
-    }
-#endif
-}
-
-GHC_INLINE void path::postprocess_path_with_format(path::format fmt)
-{
-#ifdef GHC_RAISE_UNICODE_ERRORS
-    if (!detail::validUtf8(_path)) {
-        path t;
-        t._path = _path;
-        throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence));
-    }
-#endif
-    switch (fmt) {
-#ifdef GHC_OS_WINDOWS
-        case path::native_format:
-        case path::auto_format:
-        case path::generic_format:
-            for (auto& c : _path) {
-                if (c == generic_separator) {
-                    c = preferred_separator;
-                }
-            }
-#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
-            if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) {
-                _path = GHC_PLATFORM_LITERAL("\\\\?\\") + _path;
-            }
-#endif
-            handle_prefixes();
-            break;
-#else
-        case path::auto_format:
-        case path::native_format:
-        case path::generic_format:
-            // nothing to do
-            break;
-#endif
-    }
-    if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator) {
-        impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast<string_type::difference_type>(_prefixLength) + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; });
-        _path.erase(new_end, _path.end());
-    }
-    else {
-        impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast<string_type::difference_type>(_prefixLength), _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; });
-        _path.erase(new_end, _path.end());
-    }
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-template <class Source, typename>
-inline path::path(const Source& source, format fmt)
-#ifdef GHC_USE_WCHAR_T
-    : _path(detail::toWChar(source))
-#else
-    : _path(detail::toUtf8(source))
-#endif
-{
-    postprocess_path_with_format(fmt);
-}
-
-template <class Source, typename>
-inline path u8path(const Source& source)
-{
-    return path(source);
-}
-template <class InputIterator>
-inline path u8path(InputIterator first, InputIterator last)
-{
-    return path(first, last);
-}
-
-template <class InputIterator>
-inline path::path(InputIterator first, InputIterator last, format fmt)
-    : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt)
-{
-    // delegated
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-namespace detail {
-
-GHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const path::value_type* str2)
-{
-#ifdef GHC_OS_WINDOWS
-#ifdef __GNUC__
-    while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) {
-        if (*str1++ == 0)
-            return true;
-    }
-    return false;
-#else // __GNUC__
-#ifdef GHC_USE_WCHAR_T
-    return 0 == ::_wcsicmp(str1, str2);
-#else // GHC_USE_WCHAR_T
-    return 0 == ::_stricmp(str1, str2);
-#endif // GHC_USE_WCHAR_T
-#endif // __GNUC__
-#else // GHC_OS_WINDOWS
-    return 0 == ::strcasecmp(str1, str2);
-#endif // GHC_OS_WINDOWS
-}
-
-GHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2)
-{
-    while (len1 > 0 && len2 > 0 && ::tolower(static_cast<unsigned char>(*str1)) == ::tolower(static_cast<unsigned char>(*str2))) {
-        --len1;
-        --len2;
-        ++str1;
-        ++str2;
-    }
-    if (len1 && len2) {
-        return *str1 < *str2 ? -1 : 1;
-    }
-    if (len1 == 0 && len2 == 0) {
-        return 0;
-    }
-    return len1 == 0 ? -1 : 1;
-}
-
-GHC_INLINE const char* strerror_adapter(char* gnu, char*)
-{
-    return gnu;
-}
-
-GHC_INLINE const char* strerror_adapter(int posix, char* buffer)
-{
-    if (posix) {
-        return "Error in strerror_r!";
-    }
-    return buffer;
-}
-
-template <typename ErrorNumber>
-GHC_INLINE std::string systemErrorText(ErrorNumber code = 0)
-{
-#if defined(GHC_OS_WINDOWS)
-    LPVOID msgBuf;
-    DWORD dw = code ? static_cast<DWORD>(code) : ::GetLastError();
-    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL);
-    std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf));
-    LocalFree(msgBuf);
-    return msg;
-#else
-    char buffer[512];
-    return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer);
-#endif
-}
-
-#ifdef GHC_OS_WINDOWS
-using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD);
-using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
-
-GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec)
-{
-    std::error_code tec;
-    auto fs = status(target_name, tec);
-    if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) {
-        ec = detail::make_error_code(detail::portable_error::not_supported);
-        return;
-    }
-#if defined(__GNUC__) && __GNUC__ >= 8
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif
-    static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
-#if defined(__GNUC__) && __GNUC__ >= 8
-#pragma GCC diagnostic pop
-#endif
-    if (api_call) {
-        if (api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), to_directory ? 1 : 0) == 0) {
-            auto result = ::GetLastError();
-            if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), to_directory ? 3 : 2) != 0) {
-                return;
-            }
-            ec = detail::make_system_error(result);
-        }
-    }
-    else {
-        ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
-    }
-}
-
-GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)
-{
-#if defined(__GNUC__) && __GNUC__ >= 8
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif
-    static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
-#if defined(__GNUC__) && __GNUC__ >= 8
-#pragma GCC diagnostic pop
-#endif
-    if (api_call) {
-        if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) {
-            ec = detail::make_system_error();
-        }
-    }
-    else {
-        ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
-    }
-}
-
-GHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec)
-{
-    ULONG size = ::GetFullPathNameW(p, 0, 0, 0);
-    if (size) {
-        std::vector<wchar_t> buf(size, 0);
-        ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr);
-        if (s2 && s2 < size) {
-            return path(std::wstring(buf.data(), s2));
-        }
-    }
-    ec = detail::make_system_error();
-    return path();
-}
-
-#else
-GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec)
-{
-    if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) {
-        ec = detail::make_system_error();
-    }
-}
-
-#ifndef GHC_OS_WEB
-GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)
-{
-    if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) {
-        ec = detail::make_system_error();
-    }
-}
-#endif
-#endif
-
-template <typename T>
-GHC_INLINE file_status file_status_from_st_mode(T mode)
-{
-#ifdef GHC_OS_WINDOWS
-    file_type ft = file_type::unknown;
-    if ((mode & _S_IFDIR) == _S_IFDIR) {
-        ft = file_type::directory;
-    }
-    else if ((mode & _S_IFREG) == _S_IFREG) {
-        ft = file_type::regular;
-    }
-    else if ((mode & _S_IFCHR) == _S_IFCHR) {
-        ft = file_type::character;
-    }
-    perms prms = static_cast<perms>(mode & 0xfff);
-    return file_status(ft, prms);
-#else
-    file_type ft = file_type::unknown;
-    if (S_ISDIR(mode)) {
-        ft = file_type::directory;
-    }
-    else if (S_ISREG(mode)) {
-        ft = file_type::regular;
-    }
-    else if (S_ISCHR(mode)) {
-        ft = file_type::character;
-    }
-    else if (S_ISBLK(mode)) {
-        ft = file_type::block;
-    }
-    else if (S_ISFIFO(mode)) {
-        ft = file_type::fifo;
-    }
-    else if (S_ISLNK(mode)) {
-        ft = file_type::symlink;
-    }
-    else if (S_ISSOCK(mode)) {
-        ft = file_type::socket;
-    }
-    perms prms = static_cast<perms>(mode & 0xfff);
-    return file_status(ft, prms);
-#endif
-}
-
-#ifdef GHC_OS_WINDOWS
-#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
-typedef struct _REPARSE_DATA_BUFFER
-{
-    ULONG ReparseTag;
-    USHORT ReparseDataLength;
-    USHORT Reserved;
-    union
-    {
-        struct
-        {
-            USHORT SubstituteNameOffset;
-            USHORT SubstituteNameLength;
-            USHORT PrintNameOffset;
-            USHORT PrintNameLength;
-            ULONG Flags;
-            WCHAR PathBuffer[1];
-        } SymbolicLinkReparseBuffer;
-        struct
-        {
-            USHORT SubstituteNameOffset;
-            USHORT SubstituteNameLength;
-            USHORT PrintNameOffset;
-            USHORT PrintNameLength;
-            WCHAR PathBuffer[1];
-        } MountPointReparseBuffer;
-        struct
-        {
-            UCHAR DataBuffer[1];
-        } GenericReparseBuffer;
-    } DUMMYUNIONNAME;
-} REPARSE_DATA_BUFFER;
-#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
-#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024)
-#endif
-#endif
-
-GHC_INLINE std::shared_ptr<REPARSE_DATA_BUFFER> getReparseData(const path& p, std::error_code& ec)
-{
-    std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
-    if (file.get() == INVALID_HANDLE_VALUE) {
-        ec = detail::make_system_error();
-        return nullptr;
-    }
-
-    std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free);
-    ULONG bufferUsed;
-    if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {
-        return reparseData;
-    }
-    else {
-        ec = detail::make_system_error();
-    }
-    return nullptr;
-}
-#endif
-
-GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)
-{
-#ifdef GHC_OS_WINDOWS
-    path result;
-    auto reparseData = detail::getReparseData(p, ec);
-    if (!ec) {
-        if (reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag)) {
-            switch (reparseData->ReparseTag) {
-                case IO_REPARSE_TAG_SYMLINK: {
-                    auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR));
-                    auto substituteName =
-                        std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
-                    if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L"\\??\\"))) {
-                        result = printName;
-                    }
-                    else {
-                        result = substituteName;
-                    }
-                    if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) {
-                        result = p.parent_path() / result;
-                    }
-                    break;
-                }
-                case IO_REPARSE_TAG_MOUNT_POINT:
-                    result = detail::getFullPathName(GHC_NATIVEWP(p), ec);
-                    //result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-    return result;
-#else
-    size_t bufferSize = 256;
-    while (true) {
-        std::vector<char> buffer(bufferSize, static_cast<char>(0));
-        auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size());
-        if (rc < 0) {
-            ec = detail::make_system_error();
-            return path();
-        }
-        else if (rc < static_cast<int>(bufferSize)) {
-            return path(std::string(buffer.data(), static_cast<std::string::size_type>(rc)));
-        }
-        bufferSize *= 2;
-    }
-    return path();
-#endif
-}
-
-#ifdef GHC_OS_WINDOWS
-GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft)
-{
-    ULARGE_INTEGER ull;
-    ull.LowPart = ft.dwLowDateTime;
-    ull.HighPart = ft.dwHighDateTime;
-    return static_cast<time_t>(ull.QuadPart / 10000000ULL - 11644473600ULL);
-}
-
-GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft)
-{
-    LONGLONG ll;
-    ll = Int32x32To64(t, 10000000) + 116444736000000000;
-    ft.dwLowDateTime = static_cast<DWORD>(ll);
-    ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);
-}
-
-template <typename INFO>
-GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info)
-{
-    return static_cast<uintmax_t>(-1);
-}
-
-template <>
-GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_HANDLE_FILE_INFORMATION* info)
-{
-    return info->nNumberOfLinks;
-}
-
-template <typename INFO>
-GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*)
-{
-    return 0;
-}
-
-template <>
-GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info)
-{
-    return info->dwReserved0;
-}
-
-template <typename INFO>
-GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr)
-{
-    file_type ft = file_type::unknown;
-    if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
-        if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
-            ft = file_type::symlink;
-        }
-    }
-    else {
-        if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
-            auto reparseData = detail::getReparseData(p, ec);
-            if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
-                ft = file_type::symlink;
-            }
-        }
-    }
-    if (ft == file_type::unknown) {
-        if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
-            ft = file_type::directory;
-        }
-        else {
-            ft = file_type::regular;
-        }
-    }
-    perms prms = perms::owner_read | perms::group_read | perms::others_read;
-    if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
-        prms = prms | perms::owner_write | perms::group_write | perms::others_write;
-    }
-    if (has_executable_extension(p)) {
-        prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec;
-    }
-    if (sz) {
-        *sz = static_cast<uintmax_t>(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow;
-    }
-    if (lwt) {
-        *lwt = detail::timeFromFILETIME(info->ftLastWriteTime);
-    }
-    return file_status(ft, prms);
-}
-
-#endif
-
-GHC_INLINE bool is_not_found_error(std::error_code& ec)
-{
-#ifdef GHC_OS_WINDOWS
-    return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME;
-#else
-    return ec.value() == ENOENT || ec.value() == ENOTDIR;
-#endif
-}
-
-GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept
-{
-#ifdef GHC_OS_WINDOWS
-    file_status fs;
-    WIN32_FILE_ATTRIBUTE_DATA attr;
-    if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {
-        ec = detail::make_system_error();
-    }
-    else {
-        ec.clear();
-        fs = detail::status_from_INFO(p, &attr, ec, sz, lwt);
-        if (nhl) {
-            *nhl = 0;
-        }
-    }
-    if (detail::is_not_found_error(ec)) {
-        return file_status(file_type::not_found);
-    }
-    return ec ? file_status(file_type::none) : fs;
-#else
-    (void)sz;
-    (void)nhl;
-    (void)lwt;
-    struct ::stat fs;
-    auto result = ::lstat(p.c_str(), &fs);
-    if (result == 0) {
-        ec.clear();
-        file_status f_s = detail::file_status_from_st_mode(fs.st_mode);
-        return f_s;
-    }
-    ec = detail::make_system_error();
-    if (detail::is_not_found_error(ec)) {
-        return file_status(file_type::not_found, perms::unknown);
-    }
-    return file_status(file_type::none);
-#endif
-}
-
-GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    if (recurse_count > 16) {
-        ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/);
-        return file_status(file_type::unknown);
-    }
-    WIN32_FILE_ATTRIBUTE_DATA attr;
-    if (!::GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {
-        ec = detail::make_system_error();
-    }
-    else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-        auto reparseData = detail::getReparseData(p, ec);
-        if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
-            path target = resolveSymlink(p, ec);
-            file_status result;
-            if (!ec && !target.empty()) {
-                if (sls) {
-                    *sls = status_from_INFO(p, &attr, ec);
-                }
-                return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1);
-            }
-            return file_status(file_type::unknown);
-        }
-    }
-    if (ec) {
-        if (detail::is_not_found_error(ec)) {
-            return file_status(file_type::not_found);
-        }
-        return file_status(file_type::none);
-    }
-    if (nhl) {
-        *nhl = 0;
-    }
-    return detail::status_from_INFO(p, &attr, ec, sz, lwt);
-#else
-    (void)recurse_count;
-    struct ::stat st;
-    auto result = ::lstat(p.c_str(), &st);
-    if (result == 0) {
-        ec.clear();
-        file_status fs = detail::file_status_from_st_mode(st.st_mode);
-        if (sls) {
-            *sls = fs;
-        }
-        if (fs.type() == file_type::symlink) {
-            result = ::stat(p.c_str(), &st);
-            if (result == 0) {
-                fs = detail::file_status_from_st_mode(st.st_mode);
-            }
-            else {
-                ec = detail::make_system_error();
-                if (detail::is_not_found_error(ec)) {
-                    return file_status(file_type::not_found, perms::unknown);
-                }
-                return file_status(file_type::none);
-            }
-        }
-        if (sz) {
-            *sz = static_cast<uintmax_t>(st.st_size);
-        }
-        if (nhl) {
-            *nhl = st.st_nlink;
-        }
-        if (lwt) {
-            *lwt = st.st_mtime;
-        }
-        return fs;
-    }
-    else {
-        ec = detail::make_system_error();
-        if (detail::is_not_found_error(ec)) {
-            return file_status(file_type::not_found, perms::unknown);
-        }
-        return file_status(file_type::none);
-    }
-#endif
-}
-
-}  // namespace detail
-
-GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv)
-    : _argc(argc)
-    , _argv(argv)
-    , _refargc(argc)
-    , _refargv(argv)
-    , _isvalid(false)
-{
-#ifdef GHC_OS_WINDOWS
-    LPWSTR* p;
-    p = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
-    _args.reserve(static_cast<size_t>(argc));
-    _argp.reserve(static_cast<size_t>(argc));
-    for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
-        _args.push_back(detail::toUtf8(std::wstring(p[i])));
-        _argp.push_back((char*)_args[i].data());
-    }
-    argv = _argp.data();
-    ::LocalFree(p);
-    _isvalid = true;
-#else
-    std::setlocale(LC_ALL, "");
-#if defined(__ANDROID__) && __ANDROID_API__ < 26
-    _isvalid = true;
-#else
-    if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) {
-        _isvalid = true;
-    }
-#endif
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.construct] constructors and destructor
-
-GHC_INLINE path::path() noexcept {}
-
-GHC_INLINE path::path(const path& p)
-    : _path(p._path)
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    , _prefixLength(p._prefixLength)
-#endif
-{
-}
-
-GHC_INLINE path::path(path&& p) noexcept
-    : _path(std::move(p._path))
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    , _prefixLength(p._prefixLength)
-#endif
-{
-}
-
-GHC_INLINE path::path(string_type&& source, format fmt)
-    : _path(std::move(source))
-{
-    postprocess_path_with_format(fmt);
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-#ifdef GHC_WITH_EXCEPTIONS
-template <class Source, typename>
-inline path::path(const Source& source, const std::locale& loc, format fmt)
-    : path(source, fmt)
-{
-    std::string locName = loc.name();
-    if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) {
-        throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported));
-    }
-}
-
-template <class InputIterator>
-inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt)
-    : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt)
-{
-    std::string locName = loc.name();
-    if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) {
-        throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported));
-    }
-}
-#endif
-
-#ifdef GHC_EXPAND_IMPL
-
-GHC_INLINE path::~path() {}
-
-//-----------------------------------------------------------------------------
-// [fs.path.assign] assignments
-
-GHC_INLINE path& path::operator=(const path& p)
-{
-    _path = p._path;
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    _prefixLength = p._prefixLength;
-#endif
-    return *this;
-}
-
-GHC_INLINE path& path::operator=(path&& p) noexcept
-{
-    _path = std::move(p._path);
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    _prefixLength = p._prefixLength;
-#endif
-    return *this;
-}
-
-GHC_INLINE path& path::operator=(path::string_type&& source)
-{
-    return assign(source);
-}
-
-GHC_INLINE path& path::assign(path::string_type&& source)
-{
-    _path = std::move(source);
-    postprocess_path_with_format(native_format);
-    return *this;
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-template <class Source>
-inline path& path::operator=(const Source& source)
-{
-    return assign(source);
-}
-
-template <class Source>
-inline path& path::assign(const Source& source)
-{
-#ifdef GHC_USE_WCHAR_T
-    _path.assign(detail::toWChar(source));
-#else
-    _path.assign(detail::toUtf8(source));
-#endif
-    postprocess_path_with_format(native_format);
-    return *this;
-}
-
-template <>
-inline path& path::assign<path>(const path& source)
-{
-    _path = source._path;
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    _prefixLength = source._prefixLength;
-#endif
-    return *this;
-}
-
-template <class InputIterator>
-inline path& path::assign(InputIterator first, InputIterator last)
-{
-    _path.assign(first, last);
-    postprocess_path_with_format(native_format);
-    return *this;
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-//-----------------------------------------------------------------------------
-// [fs.path.append] appends
-
-GHC_INLINE path& path::operator/=(const path& p)
-{
-    if (p.empty()) {
-        // was: if ((!has_root_directory() && is_absolute()) || has_filename())
-        if (!_path.empty() && _path[_path.length() - 1] != preferred_separator && _path[_path.length() - 1] != ':') {
-            _path += preferred_separator;
-        }
-        return *this;
-    }
-    if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) {
-        assign(p);
-        return *this;
-    }
-    if (p.has_root_directory()) {
-        assign(root_name());
-    }
-    else if ((!has_root_directory() && is_absolute()) || has_filename()) {
-        _path += preferred_separator;
-    }
-    auto iter = p.begin();
-    bool first = true;
-    if (p.has_root_name()) {
-        ++iter;
-    }
-    while (iter != p.end()) {
-        if (!first && !(!_path.empty() && _path[_path.length() - 1] == preferred_separator)) {
-            _path += preferred_separator;
-        }
-        first = false;
-        _path += (*iter++).native();
-    }
-    check_long_path();
-    return *this;
-}
-
-GHC_INLINE void path::append_name(const value_type* name)
-{
-    if (_path.empty()) {
-        this->operator/=(path(name));
-    }
-    else {
-        if (_path.back() != path::preferred_separator) {
-            _path.push_back(path::preferred_separator);
-        }
-        _path += name;
-        check_long_path();
-    }
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-template <class Source>
-inline path& path::operator/=(const Source& source)
-{
-    return append(source);
-}
-
-template <class Source>
-inline path& path::append(const Source& source)
-{
-    return this->operator/=(path(source));
-}
-
-template <>
-inline path& path::append<path>(const path& p)
-{
-    return this->operator/=(p);
-}
-
-template <class InputIterator>
-inline path& path::append(InputIterator first, InputIterator last)
-{
-    std::basic_string<typename std::iterator_traits<InputIterator>::value_type> part(first, last);
-    return append(part);
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-//-----------------------------------------------------------------------------
-// [fs.path.concat] concatenation
-
-GHC_INLINE path& path::operator+=(const path& x)
-{
-    return concat(x._path);
-}
-
-GHC_INLINE path& path::operator+=(const string_type& x)
-{
-    return concat(x);
-}
-
-#ifdef GHC_WITH_STRING_VIEW
-GHC_INLINE path& path::operator+=(basic_string_view<value_type> x)
-{
-    return concat(x);
-}
-#endif
-
-GHC_INLINE path& path::operator+=(const value_type* x)
-{
-#ifdef GHC_WITH_STRING_VIEW
-    basic_string_view<value_type> part(x);
-#else
-    string_type part(x);
-#endif
-    return concat(part);
-}
-
-GHC_INLINE path& path::operator+=(value_type x)
-{
-#ifdef GHC_OS_WINDOWS
-    if (x == generic_separator) {
-        x = preferred_separator;
-    }
-#endif
-    if (_path.empty() || _path.back() != preferred_separator) {
-        _path += x;
-    }
-    check_long_path();
-    return *this;
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-template <class Source>
-inline path::path_from_string<Source>& path::operator+=(const Source& x)
-{
-    return concat(x);
-}
-
-template <class EcharT>
-inline path::path_type_EcharT<EcharT>& path::operator+=(EcharT x)
-{
-#ifdef GHC_WITH_STRING_VIEW
-    basic_string_view<EcharT> part(&x, 1);
-#else
-    std::basic_string<EcharT> part(1, x);
-#endif
-    concat(part);
-    return *this;
-}
-
-template <class Source>
-inline path& path::concat(const Source& x)
-{
-    path p(x);
-    _path += p._path;
-    postprocess_path_with_format(native_format);
-    return *this;
-}
-template <class InputIterator>
-inline path& path::concat(InputIterator first, InputIterator last)
-{
-    _path.append(first, last);
-    postprocess_path_with_format(native_format);
-    return *this;
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-//-----------------------------------------------------------------------------
-// [fs.path.modifiers] modifiers
-GHC_INLINE void path::clear() noexcept
-{
-    _path.clear();
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    _prefixLength = 0;
-#endif
-}
-
-GHC_INLINE path& path::make_preferred()
-{
-    // as this filesystem implementation only uses generic_format
-    // internally, this must be a no-op
-    return *this;
-}
-
-GHC_INLINE path& path::remove_filename()
-{
-    if (has_filename()) {
-        _path.erase(_path.size() - filename()._path.size());
-    }
-    return *this;
-}
-
-GHC_INLINE path& path::replace_filename(const path& replacement)
-{
-    remove_filename();
-    return append(replacement);
-}
-
-GHC_INLINE path& path::replace_extension(const path& replacement)
-{
-    if (has_extension()) {
-        _path.erase(_path.size() - extension()._path.size());
-    }
-    if (!replacement.empty() && replacement._path[0] != '.') {
-        _path += '.';
-    }
-    return concat(replacement);
-}
-
-GHC_INLINE void path::swap(path& rhs) noexcept
-{
-    _path.swap(rhs._path);
-#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    std::swap(_prefixLength, rhs._prefixLength);
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.native.obs] native format observers
-GHC_INLINE const path::string_type& path::native() const noexcept
-{
-    return _path;
-}
-
-GHC_INLINE const path::value_type* path::c_str() const noexcept
-{
-    return native().c_str();
-}
-
-GHC_INLINE path::operator path::string_type() const
-{
-    return native();
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-template <class EcharT, class traits, class Allocator>
-inline std::basic_string<EcharT, traits, Allocator> path::string(const Allocator& a) const
-{
-#ifdef GHC_USE_WCHAR_T
-    return detail::fromWChar<std::basic_string<EcharT, traits, Allocator>>(_path, a);
-#else
-    return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);
-#endif
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-GHC_INLINE std::string path::string() const
-{
-#ifdef GHC_USE_WCHAR_T
-    return detail::toUtf8(native());
-#else
-    return native();
-#endif
-}
-
-GHC_INLINE std::wstring path::wstring() const
-{
-#ifdef GHC_USE_WCHAR_T
-    return native();
-#else
-    return detail::fromUtf8<std::wstring>(native());
-#endif
-}
-
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-GHC_INLINE std::u8string path::u8string() const
-{
-#ifdef GHC_USE_WCHAR_T
-    return std::u8string(reinterpret_cast<const char8_t*>(detail::toUtf8(native()).c_str()));
-#else
-    return std::u8string(reinterpret_cast<const char8_t*>(c_str()));
-#endif
-}
-#else
-GHC_INLINE std::string path::u8string() const
-{
-#ifdef GHC_USE_WCHAR_T
-    return detail::toUtf8(native());
-#else
-    return native();
-#endif
-}
-#endif
-
-GHC_INLINE std::u16string path::u16string() const
-{
-    // TODO: optimize
-    return detail::fromUtf8<std::u16string>(string());
-}
-
-GHC_INLINE std::u32string path::u32string() const
-{
-    // TODO: optimize
-    return detail::fromUtf8<std::u32string>(string());
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-//-----------------------------------------------------------------------------
-// [fs.path.generic.obs] generic format observers
-template <class EcharT, class traits, class Allocator>
-inline std::basic_string<EcharT, traits, Allocator> path::generic_string(const Allocator& a) const
-{
-#ifdef GHC_OS_WINDOWS
-#ifdef GHC_USE_WCHAR_T
-    auto result = detail::fromWChar<std::basic_string<EcharT, traits, Allocator>, path::string_type>(_path, a);
-#else
-    auto result = detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);
-#endif
-    for (auto& c : result) {
-        if (c == preferred_separator) {
-            c = generic_separator;
-        }
-    }
-    return result;
-#else
-    return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);
-#endif
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-GHC_INLINE std::string path::generic_string() const
-{
-#ifdef GHC_OS_WINDOWS
-    return generic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();
-#else
-    return _path;
-#endif
-}
-
-GHC_INLINE std::wstring path::generic_wstring() const
-{
-#ifdef GHC_OS_WINDOWS
-    return generic_string<std::wstring::value_type, std::wstring::traits_type, std::wstring::allocator_type>();
-#else
-    return detail::fromUtf8<std::wstring>(_path);
-#endif
-}  // namespace filesystem
-
-#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
-GHC_INLINE std::u8string path::generic_u8string() const
-{
-#ifdef GHC_OS_WINDOWS
-    return generic_string<std::u8string::value_type, std::u8string::traits_type, std::u8string::allocator_type>();
-#else
-    return std::u8string(reinterpret_cast<const char8_t*>(_path.c_str()));
-#endif
-}
-#else
-GHC_INLINE std::string path::generic_u8string() const
-{
-#ifdef GHC_OS_WINDOWS
-    return generic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();
-#else
-    return _path;
-#endif
-}
-#endif
-
-GHC_INLINE std::u16string path::generic_u16string() const
-{
-#ifdef GHC_OS_WINDOWS
-    return generic_string<std::u16string::value_type, std::u16string::traits_type, std::u16string::allocator_type>();
-#else
-    return detail::fromUtf8<std::u16string>(_path);
-#endif
-}
-
-GHC_INLINE std::u32string path::generic_u32string() const
-{
-#ifdef GHC_OS_WINDOWS
-    return generic_string<std::u32string::value_type, std::u32string::traits_type, std::u32string::allocator_type>();
-#else
-    return detail::fromUtf8<std::u32string>(_path);
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.compare] compare
-GHC_INLINE int path::compare(const path& p) const noexcept
-{
-#ifdef LWG_2936_BEHAVIOUR
-    auto rnl1 = root_name_length();
-    auto rnl2 = p.root_name_length();
-#ifdef GHC_OS_WINDOWS
-    auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);
-#else
-    auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2)));
-#endif
-    if (rnc) {
-        return rnc;
-    }
-    bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory();
-    if (hrd1 != hrd2) {
-        return hrd1 ? 1 : -1;
-    }
-    if (hrd1) {
-        ++rnl1;
-        ++rnl2;
-    }
-    auto iter1 = _path.begin() + static_cast<int>(rnl1);
-    auto iter2 = p._path.begin() + static_cast<int>(rnl2);
-    while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) {
-        ++iter1;
-        ++iter2;
-    }
-    if (iter1 == _path.end()) {
-        return iter2 == p._path.end() ? 0 : -1;
-    }
-    if (iter2 == p._path.end()) {
-        return 1;
-    }
-    if (*iter1 == preferred_separator) {
-        return -1;
-    }
-    if (*iter2 == preferred_separator) {
-        return 1;
-    }
-    return *iter1 < *iter2 ? -1 : 1;
-#else  // LWG_2936_BEHAVIOUR
-#ifdef GHC_OS_WINDOWS
-    auto rnl1 = root_name_length();
-    auto rnl2 = p.root_name_length();
-    auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);
-    if (rnc) {
-        return rnc;
-    }
-    return _path.compare(rnl1, std::string::npos, p._path, rnl2, std::string::npos);
-#else
-    return _path.compare(p._path);
-#endif
-#endif
-}
-
-GHC_INLINE int path::compare(const string_type& s) const
-{
-    return compare(path(s));
-}
-
-#ifdef GHC_WITH_STRING_VIEW
-GHC_INLINE int path::compare(basic_string_view<value_type> s) const
-{
-    return compare(path(s));
-}
-#endif
-
-GHC_INLINE int path::compare(const value_type* s) const
-{
-    return compare(path(s));
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.decompose] decomposition
-#ifdef GHC_OS_WINDOWS
-GHC_INLINE void path::handle_prefixes()
-{
-#if defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
-    _prefixLength = 0;
-    if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast<unsigned char>(_path[4])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[4])) <= 'Z' && _path[5] == ':') {
-        if (detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\"))) || detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\??\\")))) {
-            _prefixLength = 4;
-        }
-    }
-#endif  // GHC_WIN_AUTO_PREFIX_LONG_PATH
-}
-#endif
-
-GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept
-{
-#ifdef GHC_OS_WINDOWS
-    if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') {
-        return 2;
-    }
-#endif
-    if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator && std::isprint(_path[_prefixLength + 2])) {
-        impl_string_type::size_type pos = _path.find(preferred_separator, _prefixLength + 3);
-        if (pos == impl_string_type::npos) {
-            return _path.length();
-        }
-        else {
-            return pos;
-        }
-    }
-    return 0;
-}
-
-GHC_INLINE path path::root_name() const
-{
-    return path(_path.substr(_prefixLength, root_name_length()), native_format);
-}
-
-GHC_INLINE path path::root_directory() const
-{
-    if (has_root_directory()) {
-        static const path _root_dir(std::string(1, preferred_separator), native_format);
-        return _root_dir;
-    }
-    return path();
-}
-
-GHC_INLINE path path::root_path() const
-{
-    return path(root_name().string() + root_directory().string(), native_format);
-}
-
-GHC_INLINE path path::relative_path() const
-{
-    auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
-    return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format);
-}
-
-GHC_INLINE path path::parent_path() const
-{
-    auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
-    if (rootPathLen < _path.length()) {
-        if (empty()) {
-            return path();
-        }
-        else {
-            auto piter = end();
-            auto iter = piter.decrement(_path.end());
-            if (iter > _path.begin() + static_cast<long>(rootPathLen) && *iter != preferred_separator) {
-                --iter;
-            }
-            return path(_path.begin(), iter, native_format);
-        }
-    }
-    else {
-        return *this;
-    }
-}
-
-GHC_INLINE path path::filename() const
-{
-    return !has_relative_path() ? path() : path(*--end());
-}
-
-GHC_INLINE path path::stem() const
-{
-    impl_string_type fn = filename().native();
-    if (fn != "." && fn != "..") {
-        impl_string_type::size_type pos = fn.rfind('.');
-        if (pos != impl_string_type::npos && pos > 0) {
-            return path{fn.substr(0, pos), native_format};
-        }
-    }
-    return path{fn, native_format};
-}
-
-GHC_INLINE path path::extension() const
-{
-    if (has_relative_path()) {
-        auto iter = end();
-        const auto& fn = *--iter;
-        impl_string_type::size_type pos = fn._path.rfind('.');
-        if (pos != std::string::npos && pos > 0) {
-            return path(fn._path.substr(pos), native_format);
-        }
-    }
-    return path();
-}
-
-#ifdef GHC_OS_WINDOWS
-namespace detail {
-GHC_INLINE bool has_executable_extension(const path& p)
-{
-    if (p.has_relative_path()) {
-        auto iter = p.end();
-        const auto& fn = *--iter;
-        auto pos = fn._path.find_last_of('.');
-        if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) {
-            return false;
-        }
-        const path::value_type* ext = fn._path.c_str() + pos + 1;
-        if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) {
-            return true;
-        }
-    }
-    return false;
-}
-}  // namespace detail
-#endif
-
-//-----------------------------------------------------------------------------
-// [fs.path.query] query
-GHC_INLINE bool path::empty() const noexcept
-{
-    return _path.empty();
-}
-
-GHC_INLINE bool path::has_root_name() const
-{
-    return root_name_length() > 0;
-}
-
-GHC_INLINE bool path::has_root_directory() const
-{
-    auto rootLen = _prefixLength + root_name_length();
-    return (_path.length() > rootLen && _path[rootLen] == preferred_separator);
-}
-
-GHC_INLINE bool path::has_root_path() const
-{
-    return has_root_name() || has_root_directory();
-}
-
-GHC_INLINE bool path::has_relative_path() const
-{
-    auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
-    return rootPathLen < _path.length();
-}
-
-GHC_INLINE bool path::has_parent_path() const
-{
-    return !parent_path().empty();
-}
-
-GHC_INLINE bool path::has_filename() const
-{
-    return has_relative_path() && !filename().empty();
-}
-
-GHC_INLINE bool path::has_stem() const
-{
-    return !stem().empty();
-}
-
-GHC_INLINE bool path::has_extension() const
-{
-    return !extension().empty();
-}
-
-GHC_INLINE bool path::is_absolute() const
-{
-#ifdef GHC_OS_WINDOWS
-    return has_root_name() && has_root_directory();
-#else
-    return has_root_directory();
-#endif
-}
-
-GHC_INLINE bool path::is_relative() const
-{
-    return !is_absolute();
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.gen] generation
-GHC_INLINE path path::lexically_normal() const
-{
-    path dest;
-    bool lastDotDot = false;
-    for (string_type s : *this) {
-        if (s == ".") {
-            dest /= "";
-            continue;
-        }
-        else if (s == ".." && !dest.empty()) {
-            auto root = root_path();
-            if (dest == root) {
-                continue;
-            }
-            else if (*(--dest.end()) != "..") {
-                if (dest._path.back() == preferred_separator) {
-                    dest._path.pop_back();
-                }
-                dest.remove_filename();
-                continue;
-            }
-        }
-        if (!(s.empty() && lastDotDot)) {
-            dest /= s;
-        }
-        lastDotDot = s == "..";
-    }
-    if (dest.empty()) {
-        dest = ".";
-    }
-    return dest;
-}
-
-GHC_INLINE path path::lexically_relative(const path& base) const
-{
-    if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) {
-        return path();
-    }
-    const_iterator a = begin(), b = base.begin();
-    while (a != end() && b != base.end() && *a == *b) {
-        ++a;
-        ++b;
-    }
-    if (a == end() && b == base.end()) {
-        return path(".");
-    }
-    int count = 0;
-    for (const auto& element : input_iterator_range<const_iterator>(b, base.end())) {
-        if (element != "." && element != "" && element != "..") {
-            ++count;
-        }
-        else if (element == "..") {
-            --count;
-        }
-    }
-    if (count < 0) {
-        return path();
-    }
-    path result;
-    for (int i = 0; i < count; ++i) {
-        result /= "..";
-    }
-    for (const auto& element : input_iterator_range<const_iterator>(a, end())) {
-        result /= element;
-    }
-    return result;
-}
-
-GHC_INLINE path path::lexically_proximate(const path& base) const
-{
-    path result = lexically_relative(base);
-    return result.empty() ? *this : result;
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.itr] iterators
-GHC_INLINE path::iterator::iterator() {}
-
-GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos)
-    : _first(p._path.begin())
-    , _last(p._path.end())
-    , _prefix(_first + static_cast<string_type::difference_type>(p._prefixLength))
-    , _root(p.has_root_directory() ? _first + static_cast<string_type::difference_type>(p._prefixLength + p.root_name_length()) : _last)
-    , _iter(pos)
-{
-    if(pos != _last) {
-        updateCurrent();
-    }
-}
-
-GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const
-{
-    path::impl_string_type::const_iterator i = pos;
-    bool fromStart = i == _first || i == _prefix;
-    if (i != _last) {
-        if (fromStart && i == _first && _prefix > _first) {
-            i = _prefix;
-        }
-        else if (*i++ == preferred_separator) {
-            // we can only sit on a slash if it is a network name or a root
-            if (i != _last && *i == preferred_separator) {
-                if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) {
-                    // leadind double slashes detected, treat this and the
-                    // following until a slash as one unit
-                    i = std::find(++i, _last, preferred_separator);
-                }
-                else {
-                    // skip redundant slashes
-                    while (i != _last && *i == preferred_separator) {
-                        ++i;
-                    }
-                }
-            }
-        }
-        else {
-            if (fromStart && i != _last && *i == ':') {
-                ++i;
-            }
-            else {
-                i = std::find(i, _last, preferred_separator);
-            }
-        }
-    }
-    return i;
-}
-
-GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const
-{
-    path::impl_string_type::const_iterator i = pos;
-    if (i != _first) {
-        --i;
-        // if this is now the root slash or the trailing slash, we are done,
-        // else check for network name
-        if (i != _root && (pos != _last || *i != preferred_separator)) {
-#ifdef GHC_OS_WINDOWS
-            static const impl_string_type seps = GHC_PLATFORM_LITERAL("\\:");
-            i = std::find_first_of(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), seps.begin(), seps.end()).base();
-            if (i > _first && *i == ':') {
-                i++;
-            }
-#else
-            i = std::find(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), preferred_separator).base();
-#endif
-            // Now we have to check if this is a network name
-            if (i - _first == 2 && *_first == preferred_separator && *(_first + 1) == preferred_separator) {
-                i -= 2;
-            }
-        }
-    }
-    return i;
-}
-
-GHC_INLINE void path::iterator::updateCurrent()
-{
-    if ((_iter == _last) || (_iter != _first && _iter != _last && (*_iter == preferred_separator && _iter != _root) && (_iter + 1 == _last))) {
-        _current.clear();
-    }
-    else {
-        _current.assign(_iter, increment(_iter));
-    }
-}
-
-GHC_INLINE path::iterator& path::iterator::operator++()
-{
-    _iter = increment(_iter);
-    while (_iter != _last &&                // we didn't reach the end
-           _iter != _root &&                // this is not a root position
-           *_iter == preferred_separator &&  // we are on a separator
-           (_iter + 1) != _last             // the slash is not the last char
-    ) {
-        ++_iter;
-    }
-    updateCurrent();
-    return *this;
-}
-
-GHC_INLINE path::iterator path::iterator::operator++(int)
-{
-    path::iterator i{*this};
-    ++(*this);
-    return i;
-}
-
-GHC_INLINE path::iterator& path::iterator::operator--()
-{
-    _iter = decrement(_iter);
-    updateCurrent();
-    return *this;
-}
-
-GHC_INLINE path::iterator path::iterator::operator--(int)
-{
-    auto i = *this;
-    --(*this);
-    return i;
-}
-
-GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const
-{
-    return _iter == other._iter;
-}
-
-GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const
-{
-    return _iter != other._iter;
-}
-
-GHC_INLINE path::iterator::reference path::iterator::operator*() const
-{
-    return _current;
-}
-
-GHC_INLINE path::iterator::pointer path::iterator::operator->() const
-{
-    return &_current;
-}
-
-GHC_INLINE path::iterator path::begin() const
-{
-    return iterator(*this, _path.begin());
-}
-
-GHC_INLINE path::iterator path::end() const
-{
-    return iterator(*this, _path.end());
-}
-
-//-----------------------------------------------------------------------------
-// [fs.path.nonmember] path non-member functions
-GHC_INLINE void swap(path& lhs, path& rhs) noexcept
-{
-    swap(lhs._path, rhs._path);
-}
-
-GHC_INLINE size_t hash_value(const path& p) noexcept
-{
-    return std::hash<std::string>()(p.generic_string());
-}
-
-#ifdef GHC_HAS_THREEWAY_COMP
-GHC_INLINE std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept
-{
-    return lhs.compare(rhs) <=> 0;
-}
-#endif
-
-GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept
-{
-    return lhs.compare(rhs) == 0;
-}
-
-GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept
-{
-    return !(lhs == rhs);
-}
-
-GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept
-{
-    return lhs.compare(rhs) < 0;
-}
-
-GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept
-{
-    return lhs.compare(rhs) <= 0;
-}
-
-GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept
-{
-    return lhs.compare(rhs) > 0;
-}
-
-GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept
-{
-    return lhs.compare(rhs) >= 0;
-}
-
-GHC_INLINE path operator/(const path& lhs, const path& rhs)
-{
-    path result(lhs);
-    result /= rhs;
-    return result;
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-//-----------------------------------------------------------------------------
-// [fs.path.io] path inserter and extractor
-template <class charT, class traits>
-inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p)
-{
-    os << "\"";
-    auto ps = p.string<charT, traits>();
-    for (auto c : ps) {
-        if (c == '"' || c == '\\') {
-            os << '\\';
-        }
-        os << c;
-    }
-    os << "\"";
-    return os;
-}
-
-template <class charT, class traits>
-inline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p)
-{
-    std::basic_string<charT, traits> tmp;
-    charT c;
-    is >> c;
-    if (c == '"') {
-        auto sf = is.flags();
-        is >> std::noskipws;
-        while (is) {
-            auto c2 = is.get();
-            if (is) {
-                if (c2 == '\\') {
-                    c2 = is.get();
-                    if (is) {
-                        tmp += static_cast<charT>(c2);
-                    }
-                }
-                else if (c2 == '"') {
-                    break;
-                }
-                else {
-                    tmp += static_cast<charT>(c2);
-                }
-            }
-        }
-        if ((sf & std::ios_base::skipws) == std::ios_base::skipws) {
-            is >> std::skipws;
-        }
-        p = path(tmp);
-    }
-    else {
-        is >> tmp;
-        p = path(static_cast<charT>(c) + tmp);
-    }
-    return is;
-}
-
-#ifdef GHC_EXPAND_IMPL
-
-//-----------------------------------------------------------------------------
-// [fs.class.filesystem_error] Class filesystem_error
-GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec)
-    : std::system_error(ec, what_arg)
-    , _what_arg(what_arg)
-    , _ec(ec)
-{
-}
-
-GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec)
-    : std::system_error(ec, what_arg)
-    , _what_arg(what_arg)
-    , _ec(ec)
-    , _p1(p1)
-{
-    if (!_p1.empty()) {
-        _what_arg += ": '" + _p1.string() + "'";
-    }
-}
-
-GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec)
-    : std::system_error(ec, what_arg)
-    , _what_arg(what_arg)
-    , _ec(ec)
-    , _p1(p1)
-    , _p2(p2)
-{
-    if (!_p1.empty()) {
-        _what_arg += ": '" + _p1.string() + "'";
-    }
-    if (!_p2.empty()) {
-        _what_arg += ", '" + _p2.string() + "'";
-    }
-}
-
-GHC_INLINE const path& filesystem_error::path1() const noexcept
-{
-    return _p1;
-}
-
-GHC_INLINE const path& filesystem_error::path2() const noexcept
-{
-    return _p2;
-}
-
-GHC_INLINE const char* filesystem_error::what() const noexcept
-{
-    return _what_arg.c_str();
-}
-
-//-----------------------------------------------------------------------------
-// [fs.op.funcs] filesystem operations
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path absolute(const path& p)
-{
-    std::error_code ec;
-    path result = absolute(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE path absolute(const path& p, std::error_code& ec)
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    if (p.empty()) {
-        return absolute(current_path(ec), ec) / "";
-    }
-    ULONG size = ::GetFullPathNameW(GHC_NATIVEWP(p), 0, 0, 0);
-    if (size) {
-        std::vector<wchar_t> buf(size, 0);
-        ULONG s2 = GetFullPathNameW(GHC_NATIVEWP(p), size, buf.data(), nullptr);
-        if (s2 && s2 < size) {
-            path result = path(std::wstring(buf.data(), s2));
-            if (p.filename() == ".") {
-                result /= ".";
-            }
-            return result;
-        }
-    }
-    ec = detail::make_system_error();
-    return path();
-#else
-    path base = current_path(ec);
-    if (!ec) {
-        if (p.empty()) {
-            return base / p;
-        }
-        if (p.has_root_name()) {
-            if (p.has_root_directory()) {
-                return p;
-            }
-            else {
-                return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path();
-            }
-        }
-        else {
-            if (p.has_root_directory()) {
-                return base.root_name() / p;
-            }
-            else {
-                return base / p;
-            }
-        }
-    }
-    ec = detail::make_system_error();
-    return path();
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path canonical(const path& p)
-{
-    std::error_code ec;
-    auto result = canonical(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE path canonical(const path& p, std::error_code& ec)
-{
-    if (p.empty()) {
-        ec = detail::make_error_code(detail::portable_error::not_found);
-        return path();
-    }
-    path work = p.is_absolute() ? p : absolute(p, ec);
-    path result;
-
-    auto fs = status(work, ec);
-    if (ec) {
-        return path();
-    }
-    if (fs.type() == file_type::not_found) {
-        ec = detail::make_error_code(detail::portable_error::not_found);
-        return path();
-    }
-    bool redo;
-    do {
-        auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0);
-        redo = false;
-        result.clear();
-        for (auto pe : work) {
-            if (pe.empty() || pe == ".") {
-                continue;
-            }
-            else if (pe == "..") {
-                result = result.parent_path();
-                continue;
-            }
-            else if ((result / pe).string().length() <= rootPathLen) {
-                result /= pe;
-                continue;
-            }
-            auto sls = symlink_status(result / pe, ec);
-            if (ec) {
-                return path();
-            }
-            if (is_symlink(sls)) {
-                redo = true;
-                auto target = read_symlink(result / pe, ec);
-                if (ec) {
-                    return path();
-                }
-                if (target.is_absolute()) {
-                    result = target;
-                    continue;
-                }
-                else {
-                    result /= target;
-                    continue;
-                }
-            }
-            else {
-                result /= pe;
-            }
-        }
-        work = result;
-    } while (redo);
-    ec.clear();
-    return result;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void copy(const path& from, const path& to)
-{
-    copy(from, to, copy_options::none);
-}
-
-GHC_INLINE void copy(const path& from, const path& to, copy_options options)
-{
-    std::error_code ec;
-    copy(from, to, options, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);
-    }
-}
-#endif
-
-GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept
-{
-    copy(from, to, copy_options::none, ec);
-}
-
-GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept
-{
-    std::error_code tec;
-    file_status fs_from, fs_to;
-    ec.clear();
-    if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) {
-        fs_from = symlink_status(from, ec);
-    }
-    else {
-        fs_from = status(from, ec);
-    }
-    if (!exists(fs_from)) {
-        if (!ec) {
-            ec = detail::make_error_code(detail::portable_error::not_found);
-        }
-        return;
-    }
-    if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) {
-        fs_to = symlink_status(to, tec);
-    }
-    else {
-        fs_to = status(to, tec);
-    }
-    if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) {
-        ec = detail::make_error_code(detail::portable_error::invalid_argument);
-    }
-    else if (is_symlink(fs_from)) {
-        if ((options & copy_options::skip_symlinks) == copy_options::none) {
-            if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) {
-                copy_symlink(from, to, ec);
-            }
-            else {
-                ec = detail::make_error_code(detail::portable_error::invalid_argument);
-            }
-        }
-    }
-    else if (is_regular_file(fs_from)) {
-        if ((options & copy_options::directories_only) == copy_options::none) {
-            if ((options & copy_options::create_symlinks) != copy_options::none) {
-                create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec);
-            }
-#ifndef GHC_OS_WEB
-            else if ((options & copy_options::create_hard_links) != copy_options::none) {
-                create_hard_link(from, to, ec);
-            }
-#endif
-            else if (is_directory(fs_to)) {
-                copy_file(from, to / from.filename(), options, ec);
-            }
-            else {
-                copy_file(from, to, options, ec);
-            }
-        }
-    }
-#ifdef LWG_2682_BEHAVIOUR
-    else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) {
-        ec = detail::make_error_code(detail::portable_error::is_a_directory);
-    }
-#endif
-    else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) {
-        if (!exists(fs_to)) {
-            create_directory(to, from, ec);
-            if (ec) {
-                return;
-            }
-        }
-        for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) {
-            if (!ec) {
-                copy(iter->path(), to / iter->path().filename(), options | static_cast<copy_options>(0x8000), ec);
-            }
-            if (ec) {
-                return;
-            }
-        }
-    }
-    return;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool copy_file(const path& from, const path& to)
-{
-    return copy_file(from, to, copy_options::none);
-}
-
-GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option)
-{
-    std::error_code ec;
-    auto result = copy_file(from, to, option, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept
-{
-    return copy_file(from, to, copy_options::none, ec);
-}
-
-GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept
-{
-    std::error_code tecf, tect;
-    auto sf = status(from, tecf);
-    auto st = status(to, tect);
-    bool overwrite = false;
-    ec.clear();
-    if (!is_regular_file(sf)) {
-        ec = tecf;
-        return false;
-    }
-    if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) {
-        ec = tect ? tect : detail::make_error_code(detail::portable_error::exists);
-        return false;
-    }
-    if (exists(st)) {
-        if ((options & copy_options::update_existing) == copy_options::update_existing) {
-            auto from_time = last_write_time(from, ec);
-            if (ec) {
-                ec = detail::make_system_error();
-                return false;
-            }
-            auto to_time = last_write_time(to, ec);
-            if (ec) {
-                ec = detail::make_system_error();
-                return false;
-            }
-            if (from_time <= to_time) {
-                return false;
-            }
-        }
-        overwrite = true;
-    }
-#ifdef GHC_OS_WINDOWS
-    if (!::CopyFileW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), !overwrite)) {
-        ec = detail::make_system_error();
-        return false;
-    }
-    return true;
-#else
-    std::vector<char> buffer(16384, '\0');
-    int in = -1, out = -1;
-    if ((in = ::open(from.c_str(), O_RDONLY)) < 0) {
-        ec = detail::make_system_error();
-        return false;
-    }
-    int mode = O_CREAT | O_WRONLY | O_TRUNC;
-    if (!overwrite) {
-        mode |= O_EXCL;
-    }
-    if ((out = ::open(to.c_str(), mode, static_cast<int>(sf.permissions() & perms::all))) < 0) {
-        ec = detail::make_system_error();
-        ::close(in);
-        return false;
-    }
-    ssize_t br, bw;
-    while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {
-        ssize_t offset = 0;
-        do {
-            if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) {
-                br -= bw;
-                offset += bw;
-            }
-            else if (bw < 0) {
-                ec = detail::make_system_error();
-                ::close(in);
-                ::close(out);
-                return false;
-            }
-        } while (br);
-    }
-    ::close(in);
-    ::close(out);
-    return true;
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink)
-{
-    std::error_code ec;
-    copy_symlink(existing_symlink, new_symlink, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec);
-    }
-}
-#endif
-
-GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept
-{
-    ec.clear();
-    auto to = read_symlink(existing_symlink, ec);
-    if (!ec) {
-        if (exists(to, ec) && is_directory(to, ec)) {
-            create_directory_symlink(to, new_symlink, ec);
-        }
-        else {
-            create_symlink(to, new_symlink, ec);
-        }
-    }
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool create_directories(const path& p)
-{
-    std::error_code ec;
-    auto result = create_directories(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept
-{
-    path current;
-    ec.clear();
-    bool didCreate = false;
-    for (path::string_type part : p) {
-        current /= part;
-        if (current != p.root_name() && current != p.root_path()) {
-            std::error_code tec;
-            auto fs = status(current, tec);
-            if (tec && fs.type() != file_type::not_found) {
-                ec = tec;
-                return false;
-            }
-            if (!exists(fs)) {
-                create_directory(current, ec);
-                if (ec) {
-                    std::error_code tmp_ec;
-                    if (is_directory(current, tmp_ec)) {
-                        ec.clear();
-                    }
-                    else {
-                        return false;
-                    }
-                }
-                didCreate = true;
-            }
-#ifndef LWG_2935_BEHAVIOUR
-            else if (!is_directory(fs)) {
-                ec = detail::make_error_code(detail::portable_error::exists);
-                return false;
-            }
-#endif
-        }
-    }
-    return didCreate;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool create_directory(const path& p)
-{
-    std::error_code ec;
-    auto result = create_directory(p, path(), ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept
-{
-    return create_directory(p, path(), ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool create_directory(const path& p, const path& attributes)
-{
-    std::error_code ec;
-    auto result = create_directory(p, attributes, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept
-{
-    std::error_code tec;
-    ec.clear();
-    auto fs = status(p, tec);
-#ifdef LWG_2935_BEHAVIOUR
-    if (status_known(fs) && exists(fs)) {
-        return false;
-    }
-#else
-    if (status_known(fs) && exists(fs) && is_directory(fs)) {
-        return false;
-    }
-#endif
-#ifdef GHC_OS_WINDOWS
-    if (!attributes.empty()) {
-        if (!::CreateDirectoryExW(GHC_NATIVEWP(attributes), GHC_NATIVEWP(p), NULL)) {
-            ec = detail::make_system_error();
-            return false;
-        }
-    }
-    else if (!::CreateDirectoryW(GHC_NATIVEWP(p), NULL)) {
-        ec = detail::make_system_error();
-        return false;
-    }
-#else
-    ::mode_t attribs = static_cast<mode_t>(perms::all);
-    if (!attributes.empty()) {
-        struct ::stat fileStat;
-        if (::stat(attributes.c_str(), &fileStat) != 0) {
-            ec = detail::make_system_error();
-            return false;
-        }
-        attribs = fileStat.st_mode;
-    }
-    if (::mkdir(p.c_str(), attribs) != 0) {
-        ec = detail::make_system_error();
-        return false;
-    }
-#endif
-    return true;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink)
-{
-    std::error_code ec;
-    create_directory_symlink(to, new_symlink, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec);
-    }
-}
-#endif
-
-GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept
-{
-    detail::create_symlink(to, new_symlink, true, ec);
-}
-
-#ifndef GHC_OS_WEB
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link)
-{
-    std::error_code ec;
-    create_hard_link(to, new_hard_link, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec);
-    }
-}
-#endif
-
-GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept
-{
-    detail::create_hardlink(to, new_hard_link, ec);
-}
-#endif
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void create_symlink(const path& to, const path& new_symlink)
-{
-    std::error_code ec;
-    create_symlink(to, new_symlink, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec);
-    }
-}
-#endif
-
-GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept
-{
-    detail::create_symlink(to, new_symlink, false, ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path current_path()
-{
-    std::error_code ec;
-    auto result = current_path(ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE path current_path(std::error_code& ec)
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    DWORD pathlen = ::GetCurrentDirectoryW(0, 0);
-    std::unique_ptr<wchar_t[]> buffer(new wchar_t[size_t(pathlen) + 1]);
-    if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) {
-        ec = detail::make_system_error();
-        return path();
-    }
-    return path(std::wstring(buffer.get()), path::native_format);
-#else
-    size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX)));
-    std::unique_ptr<char[]> buffer(new char[pathlen + 1]);
-    if (::getcwd(buffer.get(), pathlen) == nullptr) {
-        ec = detail::make_system_error();
-        return path();
-    }
-    return path(buffer.get());
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void current_path(const path& p)
-{
-    std::error_code ec;
-    current_path(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-}
-#endif
-
-GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    if (!::SetCurrentDirectoryW(GHC_NATIVEWP(p))) {
-        ec = detail::make_system_error();
-    }
-#else
-    if (::chdir(p.string().c_str()) == -1) {
-        ec = detail::make_system_error();
-    }
-#endif
-}
-
-GHC_INLINE bool exists(file_status s) noexcept
-{
-    return status_known(s) && s.type() != file_type::not_found;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool exists(const path& p)
-{
-    return exists(status(p));
-}
-#endif
-
-GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept
-{
-    file_status s = status(p, ec);
-    if (status_known(s)) {
-        ec.clear();
-    }
-    return exists(s);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool equivalent(const path& p1, const path& p2)
-{
-    std::error_code ec;
-    bool result = equivalent(p1, p2, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    std::shared_ptr<void> file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
-    auto e1 = ::GetLastError();
-    std::shared_ptr<void> file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
-    if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) {
-#ifdef LWG_2937_BEHAVIOUR
-        ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
-#else
-        if (file1 == file2) {
-            ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
-        }
-#endif
-        return false;
-    }
-    BY_HANDLE_FILE_INFORMATION inf1, inf2;
-    if (!::GetFileInformationByHandle(file1.get(), &inf1)) {
-        ec = detail::make_system_error();
-        return false;
-    }
-    if (!::GetFileInformationByHandle(file2.get(), &inf2)) {
-        ec = detail::make_system_error();
-        return false;
-    }
-    return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow &&
-           inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber;
-#else
-    struct ::stat s1, s2;
-    auto rc1 = ::stat(p1.c_str(), &s1);
-    auto e1 = errno;
-    auto rc2 = ::stat(p2.c_str(), &s2);
-    if (rc1 || rc2) {
-#ifdef LWG_2937_BEHAVIOUR
-        ec = detail::make_system_error(e1 ? e1 : errno);
-#else
-        if (rc1 && rc2) {
-            ec = detail::make_system_error(e1 ? e1 : errno);
-        }
-#endif
-        return false;
-    }
-    return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE uintmax_t file_size(const path& p)
-{
-    std::error_code ec;
-    auto result = file_size(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    WIN32_FILE_ATTRIBUTE_DATA attr;
-    if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {
-        ec = detail::make_system_error();
-        return static_cast<uintmax_t>(-1);
-    }
-    return static_cast<uintmax_t>(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow;
-#else
-    struct ::stat fileStat;
-    if (::stat(p.c_str(), &fileStat) == -1) {
-        ec = detail::make_system_error();
-        return static_cast<uintmax_t>(-1);
-    }
-    return static_cast<uintmax_t>(fileStat.st_size);
-#endif
-}
-
-#ifndef GHC_OS_WEB
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE uintmax_t hard_link_count(const path& p)
-{
-    std::error_code ec;
-    auto result = hard_link_count(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    uintmax_t result = static_cast<uintmax_t>(-1);
-    std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
-    BY_HANDLE_FILE_INFORMATION inf;
-    if (file.get() == INVALID_HANDLE_VALUE) {
-        ec = detail::make_system_error();
-    }
-    else {
-        if (!::GetFileInformationByHandle(file.get(), &inf)) {
-            ec = detail::make_system_error();
-        }
-        else {
-            result = inf.nNumberOfLinks;
-        }
-    }
-    return result;
-#else
-    uintmax_t result = 0;
-    file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr);
-    if (fs.type() == file_type::not_found) {
-        ec = detail::make_error_code(detail::portable_error::not_found);
-    }
-    return ec ? static_cast<uintmax_t>(-1) : result;
-#endif
-}
-#endif
-
-GHC_INLINE bool is_block_file(file_status s) noexcept
-{
-    return s.type() == file_type::block;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_block_file(const path& p)
-{
-    return is_block_file(status(p));
-}
-#endif
-
-GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept
-{
-    return is_block_file(status(p, ec));
-}
-
-GHC_INLINE bool is_character_file(file_status s) noexcept
-{
-    return s.type() == file_type::character;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_character_file(const path& p)
-{
-    return is_character_file(status(p));
-}
-#endif
-
-GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept
-{
-    return is_character_file(status(p, ec));
-}
-
-GHC_INLINE bool is_directory(file_status s) noexcept
-{
-    return s.type() == file_type::directory;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_directory(const path& p)
-{
-    return is_directory(status(p));
-}
-#endif
-
-GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept
-{
-    return is_directory(status(p, ec));
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_empty(const path& p)
-{
-    if (is_directory(p)) {
-        return directory_iterator(p) == directory_iterator();
-    }
-    else {
-        return file_size(p) == 0;
-    }
-}
-#endif
-
-GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept
-{
-    auto fs = status(p, ec);
-    if (ec) {
-        return false;
-    }
-    if (is_directory(fs)) {
-        directory_iterator iter(p, ec);
-        if (ec) {
-            return false;
-        }
-        return iter == directory_iterator();
-    }
-    else {
-        auto sz = file_size(p, ec);
-        if (ec) {
-            return false;
-        }
-        return sz == 0;
-    }
-}
-
-GHC_INLINE bool is_fifo(file_status s) noexcept
-{
-    return s.type() == file_type::fifo;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_fifo(const path& p)
-{
-    return is_fifo(status(p));
-}
-#endif
-
-GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept
-{
-    return is_fifo(status(p, ec));
-}
-
-GHC_INLINE bool is_other(file_status s) noexcept
-{
-    return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_other(const path& p)
-{
-    return is_other(status(p));
-}
-#endif
-
-GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept
-{
-    return is_other(status(p, ec));
-}
-
-GHC_INLINE bool is_regular_file(file_status s) noexcept
-{
-    return s.type() == file_type::regular;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_regular_file(const path& p)
-{
-    return is_regular_file(status(p));
-}
-#endif
-
-GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept
-{
-    return is_regular_file(status(p, ec));
-}
-
-GHC_INLINE bool is_socket(file_status s) noexcept
-{
-    return s.type() == file_type::socket;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_socket(const path& p)
-{
-    return is_socket(status(p));
-}
-#endif
-
-GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept
-{
-    return is_socket(status(p, ec));
-}
-
-GHC_INLINE bool is_symlink(file_status s) noexcept
-{
-    return s.type() == file_type::symlink;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool is_symlink(const path& p)
-{
-    return is_symlink(symlink_status(p));
-}
-#endif
-
-GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept
-{
-    return is_symlink(symlink_status(p, ec));
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_time_type last_write_time(const path& p)
-{
-    std::error_code ec;
-    auto result = last_write_time(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept
-{
-    time_t result = 0;
-    ec.clear();
-    file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result);
-    return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void last_write_time(const path& p, file_time_type new_time)
-{
-    std::error_code ec;
-    last_write_time(p, new_time, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-}
-#endif
-
-GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept
-{
-    ec.clear();
-    auto d = new_time.time_since_epoch();
-#ifdef GHC_OS_WINDOWS
-    std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle);
-    FILETIME ft;
-    auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000;
-    ft.dwLowDateTime = static_cast<DWORD>(tt);
-    ft.dwHighDateTime = static_cast<DWORD>(tt >> 32);
-    if (!::SetFileTime(file.get(), 0, 0, &ft)) {
-        ec = detail::make_system_error();
-    }
-#elif defined(GHC_OS_MACOS)
-#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
-#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
-    struct ::stat fs;
-    if (::stat(p.c_str(), &fs) == 0) {
-        struct ::timeval tv[2];
-        tv[0].tv_sec = fs.st_atimespec.tv_sec;
-        tv[0].tv_usec = static_cast<int>(fs.st_atimespec.tv_nsec / 1000);
-        tv[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
-        tv[1].tv_usec = static_cast<int>(std::chrono::duration_cast<std::chrono::microseconds>(d).count() % 1000000);
-        if (::utimes(p.c_str(), tv) == 0) {
-            return;
-        }
-    }
-    ec = detail::make_system_error();
-    return;
-#else
-    struct ::timespec times[2];
-    times[0].tv_sec = 0;
-    times[0].tv_nsec = UTIME_OMIT;
-    times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
-    times[1].tv_nsec = 0;  // std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
-    if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
-        ec = detail::make_system_error();
-    }
-    return;
-#endif
-#endif
-#else
-#ifndef UTIME_OMIT
-#define UTIME_OMIT ((1l << 30) - 2l)
-#endif
-    struct ::timespec times[2];
-    times[0].tv_sec = 0;
-    times[0].tv_nsec = UTIME_OMIT;
-    times[1].tv_sec = static_cast<decltype(times[1].tv_sec)>(std::chrono::duration_cast<std::chrono::seconds>(d).count());
-    times[1].tv_nsec = static_cast<decltype(times[1].tv_nsec)>(std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000);
-#if defined(__ANDROID_API__) && __ANDROID_API__ < 12
-    if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
-#else
-    if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
-#endif
-        ec = detail::make_system_error();
-    }
-    return;
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void permissions(const path& p, perms prms, perm_options opts)
-{
-    std::error_code ec;
-    permissions(p, prms, opts, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-}
-#endif
-
-GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept
-{
-    permissions(p, prms, perm_options::replace, ec);
-}
-
-GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept
-{
-    if (static_cast<int>(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) {
-        ec = detail::make_error_code(detail::portable_error::invalid_argument);
-        return;
-    }
-    auto fs = symlink_status(p, ec);
-    if ((opts & perm_options::replace) != perm_options::replace) {
-        if ((opts & perm_options::add) == perm_options::add) {
-            prms = fs.permissions() | prms;
-        }
-        else {
-            prms = fs.permissions() & ~prms;
-        }
-    }
-#ifdef GHC_OS_WINDOWS
-#ifdef __GNUC__
-    auto oldAttr = GetFileAttributesW(GHC_NATIVEWP(p));
-    if (oldAttr != INVALID_FILE_ATTRIBUTES) {
-        DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast<DWORD>(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY;
-        if (oldAttr == newAttr || SetFileAttributesW(GHC_NATIVEWP(p), newAttr)) {
-            return;
-        }
-    }
-    ec = detail::make_system_error();
-#else
-    int mode = 0;
-    if ((prms & perms::owner_read) == perms::owner_read) {
-        mode |= _S_IREAD;
-    }
-    if ((prms & perms::owner_write) == perms::owner_write) {
-        mode |= _S_IWRITE;
-    }
-    if (::_wchmod(p.wstring().c_str(), mode) != 0) {
-        ec = detail::make_system_error();
-    }
-#endif
-#else
-    if ((opts & perm_options::nofollow) != perm_options::nofollow) {
-        if (::chmod(p.c_str(), static_cast<mode_t>(prms)) != 0) {
-            ec = detail::make_system_error();
-        }
-    }
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path proximate(const path& p, std::error_code& ec)
-{
-    auto cp = current_path(ec);
-    if (!ec) {
-        return proximate(p, cp, ec);
-    }
-    return path();
-}
-#endif
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path proximate(const path& p, const path& base)
-{
-    return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
-}
-#endif
-
-GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec)
-{
-    return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec));
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path read_symlink(const path& p)
-{
-    std::error_code ec;
-    auto result = read_symlink(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE path read_symlink(const path& p, std::error_code& ec)
-{
-    file_status fs = symlink_status(p, ec);
-    if (fs.type() != file_type::symlink) {
-        ec = detail::make_error_code(detail::portable_error::invalid_argument);
-        return path();
-    }
-    auto result = detail::resolveSymlink(p, ec);
-    return ec ? path() : result;
-}
-
-GHC_INLINE path relative(const path& p, std::error_code& ec)
-{
-    return relative(p, current_path(ec), ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path relative(const path& p, const path& base)
-{
-    return weakly_canonical(p).lexically_relative(weakly_canonical(base));
-}
-#endif
-
-GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec)
-{
-    return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec));
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool remove(const path& p)
-{
-    std::error_code ec;
-    auto result = remove(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-#ifdef GHC_USE_WCHAR_T
-    auto cstr = p.c_str();
-#else
-    std::wstring np = detail::fromUtf8<std::wstring>(p.u8string());
-    auto cstr = np.c_str();
-#endif
-    DWORD attr = GetFileAttributesW(cstr);
-    if (attr == INVALID_FILE_ATTRIBUTES) {
-        auto error = ::GetLastError();
-        if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) {
-            return false;
-        }
-        ec = detail::make_system_error(error);
-    }
-    else if(attr & FILE_ATTRIBUTE_READONLY) {
-        auto new_attr = attr & ~static_cast<DWORD>(FILE_ATTRIBUTE_READONLY);
-        if(!SetFileAttributesW(cstr, new_attr)) {
-            auto error = ::GetLastError();
-            ec = detail::make_system_error(error);
-        }
-    }
-    if (!ec) {
-        if (attr & FILE_ATTRIBUTE_DIRECTORY) {
-            if (!RemoveDirectoryW(cstr)) {
-                ec = detail::make_system_error();
-            }
-        }
-        else {
-            if (!DeleteFileW(cstr)) {
-                ec = detail::make_system_error();
-            }
-        }
-    }
-#else
-    if (::remove(p.c_str()) == -1) {
-        auto error = errno;
-        if (error == ENOENT) {
-            return false;
-        }
-        ec = detail::make_system_error();
-    }
-#endif
-    return ec ? false : true;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE uintmax_t remove_all(const path& p)
-{
-    std::error_code ec;
-    auto result = remove_all(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept
-{
-    ec.clear();
-    uintmax_t count = 0;
-    if (p == "/") {
-        ec = detail::make_error_code(detail::portable_error::not_supported);
-        return static_cast<uintmax_t>(-1);
-    }
-    std::error_code tec;
-    auto fs = status(p, tec);
-    if (exists(fs) && is_directory(fs)) {
-        for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) {
-            if (ec && !detail::is_not_found_error(ec)) {
-                break;
-            }
-            bool is_symlink_result = iter->is_symlink(ec);
-            if (ec)
-                return static_cast<uintmax_t>(-1);
-            if (!is_symlink_result && iter->is_directory(ec)) {
-                count += remove_all(iter->path(), ec);
-                if (ec) {
-                    return static_cast<uintmax_t>(-1);
-                }
-            }
-            else {
-                if (!ec) {
-                    remove(iter->path(), ec);
-                }
-                if (ec) {
-                    return static_cast<uintmax_t>(-1);
-                }
-                ++count;
-            }
-        }
-    }
-    if (!ec) {
-        if (remove(p, ec)) {
-            ++count;
-        }
-    }
-    if (ec) {
-        return static_cast<uintmax_t>(-1);
-    }
-    return count;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void rename(const path& from, const path& to)
-{
-    std::error_code ec;
-    rename(from, to, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);
-    }
-}
-#endif
-
-GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    if (from != to) {
-        if (!MoveFileExW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), (DWORD)MOVEFILE_REPLACE_EXISTING)) {
-            ec = detail::make_system_error();
-        }
-    }
-#else
-    if (from != to) {
-        if (::rename(from.c_str(), to.c_str()) != 0) {
-            ec = detail::make_system_error();
-        }
-    }
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void resize_file(const path& p, uintmax_t size)
-{
-    std::error_code ec;
-    resize_file(p, size, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-}
-#endif
-
-GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    LARGE_INTEGER lisize;
-    lisize.QuadPart = static_cast<LONGLONG>(size);
-    if (lisize.QuadPart < 0) {
-#ifdef ERROR_FILE_TOO_LARGE
-        ec = detail::make_system_error(ERROR_FILE_TOO_LARGE);
-#else
-        ec = detail::make_system_error(223);
-#endif
-        return;
-    }
-    std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle);
-    if (file.get() == INVALID_HANDLE_VALUE) {
-        ec = detail::make_system_error();
-    }
-    else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) {
-        ec = detail::make_system_error();
-    }
-#else
-    if (::truncate(p.c_str(), static_cast<off_t>(size)) != 0) {
-        ec = detail::make_system_error();
-    }
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE space_info space(const path& p)
-{
-    std::error_code ec;
-    auto result = space(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }};
-    ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }};
-    ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }};
-    if (!GetDiskFreeSpaceExW(GHC_NATIVEWP(p), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) {
-        ec = detail::make_system_error();
-        return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)};
-    }
-    return {static_cast<uintmax_t>(totalNumberOfBytes.QuadPart), static_cast<uintmax_t>(totalNumberOfFreeBytes.QuadPart), static_cast<uintmax_t>(freeBytesAvailableToCaller.QuadPart)};
-#else
-    struct ::statvfs sfs;
-    if (::statvfs(p.c_str(), &sfs) != 0) {
-        ec = detail::make_system_error();
-        return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)};
-    }
-    return {static_cast<uintmax_t>(sfs.f_blocks * sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bfree * sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bavail * sfs.f_frsize)};
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_status status(const path& p)
-{
-    std::error_code ec;
-    auto result = status(p, ec);
-    if (result.type() == file_type::none) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept
-{
-    return detail::status_ex(p, ec);
-}
-
-GHC_INLINE bool status_known(file_status s) noexcept
-{
-    return s.type() != file_type::none;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_status symlink_status(const path& p)
-{
-    std::error_code ec;
-    auto result = symlink_status(p, ec);
-    if (result.type() == file_type::none) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept
-{
-    return detail::symlink_status_ex(p, ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path temp_directory_path()
-{
-    std::error_code ec;
-    path result = temp_directory_path(ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept
-{
-    ec.clear();
-#ifdef GHC_OS_WINDOWS
-    wchar_t buffer[512];
-    auto rc = GetTempPathW(511, buffer);
-    if (!rc || rc > 511) {
-        ec = detail::make_system_error();
-        return path();
-    }
-    return path(std::wstring(buffer));
-#else
-    static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr};
-    const char* temp_path = nullptr;
-    for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) {
-        temp_path = std::getenv(*temp_name);
-        if (temp_path) {
-            return path(temp_path);
-        }
-    }
-    return path("/tmp");
-#endif
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE path weakly_canonical(const path& p)
-{
-    std::error_code ec;
-    auto result = weakly_canonical(p, ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
-    }
-    return result;
-}
-#endif
-
-GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept
-{
-    path result;
-    ec.clear();
-    bool scan = true;
-    for (auto pe : p) {
-        if (scan) {
-            std::error_code tec;
-            if (exists(result / pe, tec)) {
-                result /= pe;
-            }
-            else {
-                if (ec) {
-                    return path();
-                }
-                scan = false;
-                if (!result.empty()) {
-                    result = canonical(result, ec) / pe;
-                    if (ec) {
-                        break;
-                    }
-                }
-                else {
-                    result /= pe;
-                }
-            }
-        }
-        else {
-            result /= pe;
-        }
-    }
-    if (scan) {
-        if (!result.empty()) {
-            result = canonical(result, ec);
-        }
-    }
-    return ec ? path() : result.lexically_normal();
-}
-
-//-----------------------------------------------------------------------------
-// [fs.class.file_status] class file_status
-// [fs.file_status.cons] constructors and destructor
-GHC_INLINE file_status::file_status() noexcept
-    : file_status(file_type::none)
-{
-}
-
-GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept
-    : _type(ft)
-    , _perms(prms)
-{
-}
-
-GHC_INLINE file_status::file_status(const file_status& other) noexcept
-    : _type(other._type)
-    , _perms(other._perms)
-{
-}
-
-GHC_INLINE file_status::file_status(file_status&& other) noexcept
-    : _type(other._type)
-    , _perms(other._perms)
-{
-}
-
-GHC_INLINE file_status::~file_status() {}
-
-// assignments:
-GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept
-{
-    _type = rhs._type;
-    _perms = rhs._perms;
-    return *this;
-}
-
-GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept
-{
-    _type = rhs._type;
-    _perms = rhs._perms;
-    return *this;
-}
-
-// [fs.file_status.mods] modifiers
-GHC_INLINE void file_status::type(file_type ft) noexcept
-{
-    _type = ft;
-}
-
-GHC_INLINE void file_status::permissions(perms prms) noexcept
-{
-    _perms = prms;
-}
-
-// [fs.file_status.obs] observers
-GHC_INLINE file_type file_status::type() const noexcept
-{
-    return _type;
-}
-
-GHC_INLINE perms file_status::permissions() const noexcept
-{
-    return _perms;
-}
-
-//-----------------------------------------------------------------------------
-// [fs.class.directory_entry] class directory_entry
-// [fs.dir.entry.cons] constructors and destructor
-// directory_entry::directory_entry() noexcept = default;
-// directory_entry::directory_entry(const directory_entry&) = default;
-// directory_entry::directory_entry(directory_entry&&) noexcept = default;
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE directory_entry::directory_entry(const filesystem::path& p)
-    : _path(p)
-    , _file_size(static_cast<uintmax_t>(-1))
-#ifndef GHC_OS_WINDOWS
-    , _hard_link_count(static_cast<uintmax_t>(-1))
-#endif
-    , _last_write_time(0)
-{
-    refresh();
-}
-#endif
-
-GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec)
-    : _path(p)
-    , _file_size(static_cast<uintmax_t>(-1))
-#ifndef GHC_OS_WINDOWS
-    , _hard_link_count(static_cast<uintmax_t>(-1))
-#endif
-    , _last_write_time(0)
-{
-    refresh(ec);
-}
-
-GHC_INLINE directory_entry::~directory_entry() {}
-
-// assignments:
-// directory_entry& directory_entry::operator=(const directory_entry&) = default;
-// directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default;
-
-// [fs.dir.entry.mods] directory_entry modifiers
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void directory_entry::assign(const filesystem::path& p)
-{
-    _path = p;
-    refresh();
-}
-#endif
-
-GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec)
-{
-    _path = p;
-    refresh(ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p)
-{
-    _path.replace_filename(p);
-    refresh();
-}
-#endif
-
-GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec)
-{
-    _path.replace_filename(p);
-    refresh(ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void directory_entry::refresh()
-{
-    std::error_code ec;
-    refresh(ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec);
-    }
-}
-#endif
-
-GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept
-{
-#ifdef GHC_OS_WINDOWS
-    _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time);
-#else
-    _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time);
-#endif
-}
-
-// [fs.dir.entry.obs] directory_entry observers
-GHC_INLINE const filesystem::path& directory_entry::path() const noexcept
-{
-    return _path;
-}
-
-GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept
-{
-    return _path;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_type directory_entry::status_file_type() const
-{
-    return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type();
-}
-#endif
-
-GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept
-{
-    if(_status.type() != file_type::none) {
-        ec.clear();
-        return _status.type();
-    }
-    return filesystem::status(path(), ec).type();
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::exists() const
-{
-    return status_file_type() != file_type::not_found;
-}
-#endif
-
-GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) != file_type::not_found;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_block_file() const
-{
-    return status_file_type() == file_type::block;
-}
-#endif
-GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) == file_type::block;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_character_file() const
-{
-    return status_file_type() == file_type::character;
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) == file_type::character;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_directory() const
-{
-    return status_file_type() == file_type::directory;
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) == file_type::directory;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_fifo() const
-{
-    return status_file_type() == file_type::fifo;
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) == file_type::fifo;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_other() const
-{
-    auto ft = status_file_type();
-    return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink();
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept
-{
-    auto ft = status_file_type(ec);
-    bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec);
-    return !ec && other;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_regular_file() const
-{
-    return status_file_type() == file_type::regular;
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) == file_type::regular;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_socket() const
-{
-    return status_file_type() == file_type::socket;
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept
-{
-    return status_file_type(ec) == file_type::socket;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE bool directory_entry::is_symlink() const
-{
-    return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status());
-}
-#endif
-
-GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept
-{
-    if(_symlink_status.type() != file_type::none) {
-        ec.clear();
-        return _symlink_status.type() == file_type::symlink;
-    }
-    return filesystem::is_symlink(symlink_status(ec));
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE uintmax_t directory_entry::file_size() const
-{
-    if (_file_size != static_cast<uintmax_t>(-1)) {
-        return _file_size;
-    }
-    return filesystem::file_size(path());
-}
-#endif
-
-GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept
-{
-    if (_file_size != static_cast<uintmax_t>(-1)) {
-        ec.clear();
-        return _file_size;
-    }
-    return filesystem::file_size(path(), ec);
-}
-
-#ifndef GHC_OS_WEB
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE uintmax_t directory_entry::hard_link_count() const
-{
-#ifndef GHC_OS_WINDOWS
-    if (_hard_link_count != static_cast<uintmax_t>(-1)) {
-        return _hard_link_count;
-    }
-#endif
-    return filesystem::hard_link_count(path());
-}
-#endif
-
-GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept
-{
-#ifndef GHC_OS_WINDOWS
-    if (_hard_link_count != static_cast<uintmax_t>(-1)) {
-        ec.clear();
-        return _hard_link_count;
-    }
-#endif
-    return filesystem::hard_link_count(path(), ec);
-}
-#endif
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_time_type directory_entry::last_write_time() const
-{
-    if (_last_write_time != 0) {
-        return std::chrono::system_clock::from_time_t(_last_write_time);
-    }
-    return filesystem::last_write_time(path());
-}
-#endif
-
-GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept
-{
-    if (_last_write_time != 0) {
-        ec.clear();
-        return std::chrono::system_clock::from_time_t(_last_write_time);
-    }
-    return filesystem::last_write_time(path(), ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_status directory_entry::status() const
-{
-    if (_status.type() != file_type::none && _status.permissions() != perms::unknown) {
-        return _status;
-    }
-    return filesystem::status(path());
-}
-#endif
-
-GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept
-{
-    if (_status.type() != file_type::none && _status.permissions() != perms::unknown) {
-        ec.clear();
-        return _status;
-    }
-    return filesystem::status(path(), ec);
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE file_status directory_entry::symlink_status() const
-{
-    if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) {
-        return _symlink_status;
-    }
-    return filesystem::symlink_status(path());
-}
-#endif
-
-GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept
-{
-    if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) {
-        ec.clear();
-        return _symlink_status;
-    }
-    return filesystem::symlink_status(path(), ec);
-}
-
-#ifdef GHC_HAS_THREEWAY_COMP
-GHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept
-{
-    return _path <=> rhs._path;
-}
-#endif
-
-GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept
-{
-    return _path < rhs._path;
-}
-
-GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept
-{
-    return _path == rhs._path;
-}
-
-GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept
-{
-    return _path != rhs._path;
-}
-
-GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept
-{
-    return _path <= rhs._path;
-}
-
-GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept
-{
-    return _path > rhs._path;
-}
-
-GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept
-{
-    return _path >= rhs._path;
-}
-
-//-----------------------------------------------------------------------------
-// [fs.class.directory_iterator] class directory_iterator
-
-#ifdef GHC_OS_WINDOWS
-class directory_iterator::impl
-{
-public:
-    impl(const path& p, directory_options options)
-        : _base(p)
-        , _options(options)
-        , _dirHandle(INVALID_HANDLE_VALUE)
-    {
-        if (!_base.empty()) {
-            ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW));
-            if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / "*")), &_findData)) != INVALID_HANDLE_VALUE) {
-                if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") {
-                    increment(_ec);
-                }
-                else {
-                    _dir_entry._path = _base / std::wstring(_findData.cFileName);
-                    copyToDirEntry(_ec);
-                }
-            }
-            else {
-                auto error = ::GetLastError();
-                _base = filesystem::path();
-                if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) {
-                    _ec = detail::make_system_error();
-                }
-            }
-        }
-    }
-    impl(const impl& other) = delete;
-    ~impl()
-    {
-        if (_dirHandle != INVALID_HANDLE_VALUE) {
-            FindClose(_dirHandle);
-            _dirHandle = INVALID_HANDLE_VALUE;
-        }
-    }
-    void increment(std::error_code& ec)
-    {
-        if (_dirHandle != INVALID_HANDLE_VALUE) {
-            do {
-                if (FindNextFileW(_dirHandle, &_findData)) {
-                    _dir_entry._path = _base;
-#ifdef GHC_USE_WCHAR_T
-                    _dir_entry._path.append_name(_findData.cFileName);
-#else
-#ifdef GHC_RAISE_UNICODE_ERRORS
-                    try {
-                        _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str());
-                    }
-                    catch (filesystem_error& fe) {
-                        ec = fe.code();
-                        return;
-                    }
-#else
-                    _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str());
-#endif
-#endif
-                    copyToDirEntry(ec);
-                }
-                else {
-                    auto err = ::GetLastError();
-                    if (err != ERROR_NO_MORE_FILES) {
-                        _ec = ec = detail::make_system_error(err);
-                    }
-                    FindClose(_dirHandle);
-                    _dirHandle = INVALID_HANDLE_VALUE;
-                    _dir_entry._path.clear();
-                    break;
-                }
-            } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..");
-        }
-        else {
-            ec = _ec;
-        }
-    }
-    void copyToDirEntry(std::error_code& ec)
-    {
-        if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-            _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time);
-        }
-        else {
-            _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time);
-            _dir_entry._symlink_status = _dir_entry._status;
-        }
-        if (ec) {
-            if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) {
-                ec.clear();
-            }
-            else {
-                _dir_entry._file_size = static_cast<uintmax_t>(-1);
-                _dir_entry._last_write_time = 0;
-            }
-        }
-    }
-    path _base;
-    directory_options _options;
-    WIN32_FIND_DATAW _findData;
-    HANDLE _dirHandle;
-    directory_entry _dir_entry;
-    std::error_code _ec;
-};
-#else
-// POSIX implementation
-class directory_iterator::impl
-{
-public:
-    impl(const path& path, directory_options options)
-        : _base(path)
-        , _options(options)
-        , _dir(nullptr)
-        , _entry(nullptr)
-    {
-        if (!path.empty()) {
-            _dir = ::opendir(path.native().c_str());
-            if (!_dir) {
-                auto error = errno;
-                _base = filesystem::path();
-                if ((error != EACCES && error != EPERM) || (options & directory_options::skip_permission_denied) == directory_options::none) {
-                    _ec = detail::make_system_error();
-                }
-            }
-            else {
-                increment(_ec);
-            }
-        }
-    }
-    impl(const impl& other) = delete;
-    ~impl()
-    {
-        if (_dir) {
-            ::closedir(_dir);
-        }
-    }
-    void increment(std::error_code& ec)
-    {
-        if (_dir) {
-            bool skip;
-            do {
-                skip = false;
-                errno = 0;
-                _entry = ::readdir(_dir);
-                if (_entry) {
-                    _dir_entry._path = _base;
-                    _dir_entry._path.append_name(_entry->d_name);
-                    copyToDirEntry();
-                    if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) {
-                        ec.clear();
-                        skip = true;
-                    }
-                }
-                else {
-                    ::closedir(_dir);
-                    _dir = nullptr;
-                    _dir_entry._path.clear();
-                    if (errno) {
-                        ec = detail::make_system_error();
-                    }
-                    break;
-                }
-            } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
-        }
-    }
-
-    void copyToDirEntry()
-    {
-#ifdef GHC_NO_DIRENT_D_TYPE
-        _dir_entry._symlink_status = file_status();
-        _dir_entry._status = file_status();
-#else
-        _dir_entry._symlink_status.permissions(perms::unknown);
-        switch(_entry->d_type) {
-            case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break;
-            case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break;
-            case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break;
-            case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break;
-            case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break;
-            case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break;
-            case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break;
-            case DT_UNKNOWN: _dir_entry._symlink_status.type(file_type::none); break;
-            default: _dir_entry._symlink_status.type(file_type::unknown); break;
-        }
-        if (_entry->d_type != DT_LNK) {
-            _dir_entry._status = _dir_entry._symlink_status;
-        }
-        else {
-            _dir_entry._status.type(file_type::none);
-            _dir_entry._status.permissions(perms::unknown);
-        }
-#endif
-        _dir_entry._file_size = static_cast<uintmax_t>(-1);
-        _dir_entry._hard_link_count = static_cast<uintmax_t>(-1);
-        _dir_entry._last_write_time = 0;
-    }
-    path _base;
-    directory_options _options;
-    DIR* _dir;
-    struct ::dirent* _entry;
-    directory_entry _dir_entry;
-    std::error_code _ec;
-};
-#endif
-
-// [fs.dir.itr.members] member functions
-GHC_INLINE directory_iterator::directory_iterator() noexcept
-    : _impl(new impl(path(), directory_options::none))
-{
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE directory_iterator::directory_iterator(const path& p)
-    : _impl(new impl(p, directory_options::none))
-{
-    if (_impl->_ec) {
-        throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec);
-    }
-    _impl->_ec.clear();
-}
-
-GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options)
-    : _impl(new impl(p, options))
-{
-    if (_impl->_ec) {
-        throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec);
-    }
-}
-#endif
-
-GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept
-    : _impl(new impl(p, directory_options::none))
-{
-    if (_impl->_ec) {
-        ec = _impl->_ec;
-    }
-}
-
-GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept
-    : _impl(new impl(p, options))
-{
-    if (_impl->_ec) {
-        ec = _impl->_ec;
-    }
-}
-
-GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs)
-    : _impl(rhs._impl)
-{
-}
-
-GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept
-    : _impl(std::move(rhs._impl))
-{
-}
-
-GHC_INLINE directory_iterator::~directory_iterator() {}
-
-GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs)
-{
-    _impl = rhs._impl;
-    return *this;
-}
-
-GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept
-{
-    _impl = std::move(rhs._impl);
-    return *this;
-}
-
-GHC_INLINE const directory_entry& directory_iterator::operator*() const
-{
-    return _impl->_dir_entry;
-}
-
-GHC_INLINE const directory_entry* directory_iterator::operator->() const
-{
-    return &_impl->_dir_entry;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE directory_iterator& directory_iterator::operator++()
-{
-    std::error_code ec;
-    _impl->increment(ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec);
-    }
-    return *this;
-}
-#endif
-
-GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept
-{
-    _impl->increment(ec);
-    return *this;
-}
-
-GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const
-{
-    return _impl->_dir_entry._path == rhs._impl->_dir_entry._path;
-}
-
-GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const
-{
-    return _impl->_dir_entry._path != rhs._impl->_dir_entry._path;
-}
-
-// [fs.dir.itr.nonmembers] directory_iterator non-member functions
-
-GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept
-{
-    return iter;
-}
-
-GHC_INLINE directory_iterator end(const directory_iterator&) noexcept
-{
-    return directory_iterator();
-}
-
-//-----------------------------------------------------------------------------
-// [fs.class.rec.dir.itr] class recursive_directory_iterator
-
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept
-    : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
-{
-    _impl->_dir_iter_stack.push(directory_iterator());
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p)
-    : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
-{
-    _impl->_dir_iter_stack.push(directory_iterator(p));
-}
-
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options)
-    : _impl(new recursive_directory_iterator_impl(options, true))
-{
-    _impl->_dir_iter_stack.push(directory_iterator(p, options));
-}
-#endif
-
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept
-    : _impl(new recursive_directory_iterator_impl(options, true))
-{
-    _impl->_dir_iter_stack.push(directory_iterator(p, options, ec));
-}
-
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept
-    : _impl(new recursive_directory_iterator_impl(directory_options::none, true))
-{
-    _impl->_dir_iter_stack.push(directory_iterator(p, ec));
-}
-
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs)
-    : _impl(rhs._impl)
-{
-}
-
-GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept
-    : _impl(std::move(rhs._impl))
-{
-}
-
-GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {}
-
-// [fs.rec.dir.itr.members] observers
-GHC_INLINE directory_options recursive_directory_iterator::options() const
-{
-    return _impl->_options;
-}
-
-GHC_INLINE int recursive_directory_iterator::depth() const
-{
-    return static_cast<int>(_impl->_dir_iter_stack.size() - 1);
-}
-
-GHC_INLINE bool recursive_directory_iterator::recursion_pending() const
-{
-    return _impl->_recursion_pending;
-}
-
-GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const
-{
-    return *(_impl->_dir_iter_stack.top());
-}
-
-GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const
-{
-    return &(*(_impl->_dir_iter_stack.top()));
-}
-
-// [fs.rec.dir.itr.members] modifiers recursive_directory_iterator&
-GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs)
-{
-    _impl = rhs._impl;
-    return *this;
-}
-
-GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept
-{
-    _impl = std::move(rhs._impl);
-    return *this;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++()
-{
-    std::error_code ec;
-    increment(ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);
-    }
-    return *this;
-}
-#endif
-
-GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept
-{
-    bool isSymLink = (*this)->is_symlink(ec);
-    bool isDir = !ec && (*this)->is_directory(ec);
-    if(isSymLink && detail::is_not_found_error(ec)) {
-        ec.clear();
-    }
-    if(!ec) {
-        if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) {
-            _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec));
-        }
-        else {
-            _impl->_dir_iter_stack.top().increment(ec);
-        }
-        if (!ec) {
-            while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
-                _impl->_dir_iter_stack.pop();
-                _impl->_dir_iter_stack.top().increment(ec);
-            }
-        }
-        else if (!_impl->_dir_iter_stack.empty()) {
-            _impl->_dir_iter_stack.pop();
-        }
-        _impl->_recursion_pending = true;
-    }
-    return *this;
-}
-
-#ifdef GHC_WITH_EXCEPTIONS
-GHC_INLINE void recursive_directory_iterator::pop()
-{
-    std::error_code ec;
-    pop(ec);
-    if (ec) {
-        throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);
-    }
-}
-#endif
-
-GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec)
-{
-    if (depth() == 0) {
-        *this = recursive_directory_iterator();
-    }
-    else {
-        do {
-            _impl->_dir_iter_stack.pop();
-            _impl->_dir_iter_stack.top().increment(ec);
-        } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator());
-    }
-}
-
-GHC_INLINE void recursive_directory_iterator::disable_recursion_pending()
-{
-    _impl->_recursion_pending = false;
-}
-
-// other members as required by [input.iterators]
-GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const
-{
-    return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top();
-}
-
-GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const
-{
-    return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top();
-}
-
-// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions
-GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept
-{
-    return iter;
-}
-
-GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept
-{
-    return recursive_directory_iterator();
-}
-
-#endif  // GHC_EXPAND_IMPL
-
-}  // namespace filesystem
-}  // namespace ghc
-
-// cleanup some macros
-#undef GHC_INLINE
-#undef GHC_EXPAND_IMPL
-
-#endif  // GHC_FILESYSTEM_H
diff --git a/wpiutil/src/main/native/thirdparty/json/cpp/json.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json.cpp
deleted file mode 100644
index f1cfb14..0000000
--- a/wpiutil/src/main/native/thirdparty/json/cpp/json.cpp
+++ /dev/null
@@ -1,1505 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#define WPI_JSON_IMPLEMENTATION
-#include "wpi/json.h"
-
-#include "fmt/format.h"
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-namespace detail {
-
-exception::exception(int id_, std::string_view what_arg)
-    : id(id_), m(std::string{what_arg}) {}
-
-parse_error parse_error::create(int id_, std::size_t byte_, std::string_view what_arg)
-{
-    if (byte_ != 0)
-        return parse_error(id_, byte_, fmt::format("[json.exception.parse_error.{}] parse error at {}: {}", id_, byte_, what_arg));
-    else
-        return parse_error(id_, byte_, fmt::format("[json.exception.parse_error.{}] parse error: {}", id_, what_arg));
-}
-
-invalid_iterator invalid_iterator::create(int id_, std::string_view what_arg)
-{
-    return invalid_iterator(id_, fmt::format("[json.exception.invalid_iterator.{}] {}", id_, what_arg));
-}
-
-invalid_iterator invalid_iterator::create(int id_, std::string_view what_arg, std::string_view type_info)
-{
-    return invalid_iterator(id_, fmt::format("[json.exception.invalid_iterator.{}] {} {}", id_, what_arg, type_info));
-}
-
-type_error type_error::create(int id_, std::string_view what_arg)
-{
-    return type_error(id_, fmt::format("[json.exception.type_error.{}] {}", id_, what_arg));
-}
-
-type_error type_error::create(int id_, std::string_view what_arg, std::string_view type_info)
-{
-    return type_error(id_, fmt::format("[json.exception.type_error.{}] {} {}", id_, what_arg, type_info));
-}
-
-out_of_range out_of_range::create(int id_, std::string_view what_arg)
-{
-    return out_of_range(id_, fmt::format("[json.exception.out_of_range.{}] {}", id_, what_arg));
-}
-
-other_error other_error::create(int id_, std::string_view what_arg)
-{
-    return other_error(id_, fmt::format("[json.exception.other_error.{}] {}", id_, what_arg));
-}
-
-}  // namespace detail
-
-json::json_value::json_value(value_t t)
-{
-    switch (t)
-    {
-        case value_t::object:
-        {
-            object = create<object_t>();
-            break;
-        }
-
-        case value_t::array:
-        {
-            array = create<array_t>();
-            break;
-        }
-
-        case value_t::string:
-        {
-            string = create<std::string>("");
-            break;
-        }
-
-        case value_t::boolean:
-        {
-            boolean = false;
-            break;
-        }
-
-        case value_t::number_integer:
-        {
-            number_integer = 0;
-            break;
-        }
-
-        case value_t::number_unsigned:
-        {
-            number_unsigned = 0u;
-            break;
-        }
-
-        case value_t::number_float:
-        {
-            number_float = 0.0;
-            break;
-        }
-
-        case value_t::null:
-        {
-            object = nullptr;  // silence warning, see #821
-            break;
-        }
-
-        default:
-        {
-            object = nullptr;  // silence warning, see #821
-            if (JSON_UNLIKELY(t == value_t::null))
-            {
-                JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE
-            }
-            break;
-        }
-    }
-}
-
-void json::json_value::destroy(value_t t) noexcept
-{
-    switch (t)
-    {
-        case value_t::object:
-        {
-            std::allocator<object_t> alloc;
-            std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
-            std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
-            break;
-        }
-
-        case value_t::array:
-        {
-            std::allocator<array_t> alloc;
-            std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
-            std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
-            break;
-        }
-
-        case value_t::string:
-        {
-            std::allocator<std::string> alloc;
-            std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
-            std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
-            break;
-        }
-
-        default:
-        {
-            break;
-        }
-    }
-}
-
-json::json(initializer_list_t init,
-           bool type_deduction,
-           value_t manual_type)
-{
-    // check if each element is an array with two elements whose first
-    // element is a string
-    bool is_an_object = std::all_of(init.begin(), init.end(),
-                                    [](const detail::json_ref<json>& element_ref)
-    {
-        return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string());
-    });
-
-    // adjust type if type deduction is not wanted
-    if (not type_deduction)
-    {
-        // if array is wanted, do not create an object though possible
-        if (manual_type == value_t::array)
-        {
-            is_an_object = false;
-        }
-
-        // if object is wanted but impossible, throw an exception
-        if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))
-        {
-            JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
-        }
-    }
-
-    if (is_an_object)
-    {
-        // the initializer list is a list of pairs -> create object
-        m_type = value_t::object;
-        m_value = value_t::object;
-
-        std::for_each(init.begin(), init.end(), [this](const detail::json_ref<json>& element_ref)
-        {
-            auto element = element_ref.moved_or_copied();
-            m_value.object->try_emplace(
-                *((*element.m_value.array)[0].m_value.string),
-                std::move((*element.m_value.array)[1]));
-        });
-    }
-    else
-    {
-        // the initializer list describes an array -> create array
-        m_type = value_t::array;
-        m_value.array = create<array_t>(init.begin(), init.end());
-    }
-
-    assert_invariant();
-}
-
-json::json(size_type cnt, const json& val)
-    : m_type(value_t::array)
-{
-    m_value.array = create<array_t>(cnt, val);
-    assert_invariant();
-}
-
-json::json(const json& other)
-    : m_type(other.m_type)
-{
-    // check of passed value is valid
-    other.assert_invariant();
-
-    switch (m_type)
-    {
-        case value_t::object:
-        {
-            m_value = *other.m_value.object;
-            break;
-        }
-
-        case value_t::array:
-        {
-            m_value = *other.m_value.array;
-            break;
-        }
-
-        case value_t::string:
-        {
-            m_value = *other.m_value.string;
-            break;
-        }
-
-        case value_t::boolean:
-        {
-            m_value = other.m_value.boolean;
-            break;
-        }
-
-        case value_t::number_integer:
-        {
-            m_value = other.m_value.number_integer;
-            break;
-        }
-
-        case value_t::number_unsigned:
-        {
-            m_value = other.m_value.number_unsigned;
-            break;
-        }
-
-        case value_t::number_float:
-        {
-            m_value = other.m_value.number_float;
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    assert_invariant();
-}
-
-json json::meta()
-{
-    json result;
-
-    result["copyright"] = "(C) 2013-2017 Niels Lohmann, (C) 2017-2018 FIRST";
-    result["name"] = "WPI version of JSON for Modern C++";
-    result["url"] = "https://github.com/wpilibsuite/allwpilib";
-    result["version"]["string"] =
-        std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." +
-        std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." +
-        std::to_string(NLOHMANN_JSON_VERSION_PATCH);
-    result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
-    result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
-    result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
-
-#ifdef _WIN32
-    result["platform"] = "win32";
-#elif defined __linux__
-    result["platform"] = "linux";
-#elif defined __APPLE__
-    result["platform"] = "apple";
-#elif defined __unix__
-    result["platform"] = "unix";
-#else
-    result["platform"] = "unknown";
-#endif
-
-#if defined(__ICC) || defined(__INTEL_COMPILER)
-    result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
-#elif defined(__clang__)
-    result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
-#elif defined(__GNUC__) || defined(__GNUG__)
-    result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
-#elif defined(__HP_cc) || defined(__HP_aCC)
-    result["compiler"] = "hp"
-#elif defined(__IBMCPP__)
-    result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
-#elif defined(_MSC_VER)
-    result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
-#elif defined(__PGI)
-    result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
-#elif defined(__SUNPRO_CC)
-    result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
-#else
-    result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
-#endif
-
-#ifdef __cplusplus
-    result["compiler"]["c++"] = std::to_string(__cplusplus);
-#else
-    result["compiler"]["c++"] = "unknown";
-#endif
-    return result;
-}
-
-json::reference json::at(size_type idx)
-{
-    // at only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        JSON_TRY
-        {
-            return m_value.array->at(idx);
-        }
-        JSON_CATCH (std::out_of_range&)
-        {
-            // create better exception explanation
-            JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
-        }
-    }
-    else
-    {
-        JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
-    }
-}
-
-json::const_reference json::at(size_type idx) const
-{
-    // at only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        JSON_TRY
-        {
-            return m_value.array->at(idx);
-        }
-        JSON_CATCH (std::out_of_range&)
-        {
-            // create better exception explanation
-            JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
-        }
-    }
-    else
-    {
-        JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
-    }
-}
-
-json::reference json::at(std::string_view key)
-{
-    // at only works for objects
-    if (JSON_LIKELY(is_object()))
-    {
-        auto it = m_value.object->find(key);
-        if (it == m_value.object->end())
-        {
-            // create better exception explanation
-            JSON_THROW(out_of_range::create(403, fmt::format("key '{}' not found", key)));
-        }
-        return it->second;
-    }
-    else
-    {
-        JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
-    }
-}
-
-json::const_reference json::at(std::string_view key) const
-{
-    // at only works for objects
-    if (JSON_LIKELY(is_object()))
-    {
-        auto it = m_value.object->find(key);
-        if (it == m_value.object->end())
-        {
-            // create better exception explanation
-            JSON_THROW(out_of_range::create(403, fmt::format("key '{}' not found", key)));
-        }
-        return it->second;
-    }
-    else
-    {
-        JSON_THROW(type_error::create(304, "cannot use at() with", type_name()));
-    }
-}
-
-json::reference json::operator[](size_type idx)
-{
-    // implicitly convert null value to an empty array
-    if (is_null())
-    {
-        m_type = value_t::array;
-        m_value.array = create<array_t>();
-        assert_invariant();
-    }
-
-    // operator[] only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        // fill up array with null values if given idx is outside range
-        if (idx >= m_value.array->size())
-        {
-            m_value.array->insert(m_value.array->end(),
-                                  idx - m_value.array->size() + 1,
-                                  json());
-        }
-
-        return m_value.array->operator[](idx);
-    }
-
-    JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
-}
-
-json::const_reference json::operator[](size_type idx) const
-{
-    // const operator[] only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        return m_value.array->operator[](idx);
-    }
-
-    JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
-}
-
-json::reference json::operator[](std::string_view key)
-{
-    // implicitly convert null value to an empty object
-    if (is_null())
-    {
-        m_type = value_t::object;
-        m_value.object = create<object_t>();
-        assert_invariant();
-    }
-
-    // operator[] only works for objects
-    if (JSON_LIKELY(is_object()))
-    {
-        return m_value.object->operator[](key);
-    }
-
-    JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
-}
-
-json::const_reference json::operator[](std::string_view key) const
-{
-    // const operator[] only works for objects
-    if (JSON_LIKELY(is_object()))
-    {
-        assert(m_value.object->find(key) != m_value.object->end());
-        return m_value.object->find(key)->second;
-    }
-
-    JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
-}
-
-json::size_type json::erase(std::string_view key)
-{
-    // this erase only works for objects
-    if (JSON_LIKELY(is_object()))
-    {
-        return m_value.object->erase(key);
-    }
-
-    JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
-}
-
-void json::erase(const size_type idx)
-{
-    // this erase only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        if (JSON_UNLIKELY(idx >= size()))
-        {
-            JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
-        }
-
-        m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
-    }
-    else
-    {
-        JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
-    }
-}
-
-json::iterator json::find(std::string_view key)
-{
-    auto result = end();
-
-    if (is_object())
-    {
-        result.m_it.object_iterator = m_value.object->find(key);
-    }
-
-    return result;
-}
-
-json::const_iterator json::find(std::string_view key) const
-{
-    auto result = cend();
-
-    if (is_object())
-    {
-        result.m_it.object_iterator = m_value.object->find(key);
-    }
-
-    return result;
-}
-
-json::size_type json::count(std::string_view key) const
-{
-    // return 0 for all nonobject types
-    return is_object() ? m_value.object->count(key) : 0;
-}
-
-bool json::empty() const noexcept
-{
-    switch (m_type)
-    {
-        case value_t::null:
-        {
-            // null values are empty
-            return true;
-        }
-
-        case value_t::array:
-        {
-            // delegate call to array_t::empty()
-            return m_value.array->empty();
-        }
-
-        case value_t::object:
-        {
-            // delegate call to object_t::empty()
-            return m_value.object->empty();
-        }
-
-        default:
-        {
-            // all other types are nonempty
-            return false;
-        }
-    }
-}
-
-json::size_type json::size() const noexcept
-{
-    switch (m_type)
-    {
-        case value_t::null:
-        {
-            // null values are empty
-            return 0;
-        }
-
-        case value_t::array:
-        {
-            // delegate call to array_t::size()
-            return m_value.array->size();
-        }
-
-        case value_t::object:
-        {
-            // delegate call to object_t::size()
-            return m_value.object->size();
-        }
-
-        default:
-        {
-            // all other types have size 1
-            return 1;
-        }
-    }
-}
-
-json::size_type json::max_size() const noexcept
-{
-    switch (m_type)
-    {
-        case value_t::array:
-        {
-            // delegate call to array_t::max_size()
-            return m_value.array->max_size();
-        }
-
-        case value_t::object:
-        {
-            // delegate call to std::allocator<object_t>::max_size()
-            return std::allocator_traits<object_t>::max_size(*m_value.object);
-        }
-
-        default:
-        {
-            // all other types have max_size() == size()
-            return size();
-        }
-    }
-}
-
-void json::clear() noexcept
-{
-    switch (m_type)
-    {
-        case value_t::number_integer:
-        {
-            m_value.number_integer = 0;
-            break;
-        }
-
-        case value_t::number_unsigned:
-        {
-            m_value.number_unsigned = 0;
-            break;
-        }
-
-        case value_t::number_float:
-        {
-            m_value.number_float = 0.0;
-            break;
-        }
-
-        case value_t::boolean:
-        {
-            m_value.boolean = false;
-            break;
-        }
-
-        case value_t::string:
-        {
-            m_value.string->clear();
-            break;
-        }
-
-        case value_t::array:
-        {
-            m_value.array->clear();
-            break;
-        }
-
-        case value_t::object:
-        {
-            m_value.object->clear();
-            break;
-        }
-
-        default:
-            break;
-    }
-}
-
-void json::push_back(json&& val)
-{
-    // push_back only works for null objects or arrays
-    if (JSON_UNLIKELY(not(is_null() or is_array())))
-    {
-        JSON_THROW(type_error::create(308, "cannot use push_back() with", type_name()));
-    }
-
-    // transform null object into an array
-    if (is_null())
-    {
-        m_type = value_t::array;
-        m_value = value_t::array;
-        assert_invariant();
-    }
-
-    // add element to array (move semantics)
-    m_value.array->push_back(std::move(val));
-    // invalidate object
-    val.m_type = value_t::null;
-}
-
-void json::push_back(const json& val)
-{
-    // push_back only works for null objects or arrays
-    if (JSON_UNLIKELY(not(is_null() or is_array())))
-    {
-        JSON_THROW(type_error::create(308, "cannot use push_back() with", type_name()));
-    }
-
-    // transform null object into an array
-    if (is_null())
-    {
-        m_type = value_t::array;
-        m_value = value_t::array;
-        assert_invariant();
-    }
-
-    // add element to array
-    m_value.array->push_back(val);
-}
-
-void json::push_back(initializer_list_t init)
-{
-    if (is_object() and init.size() == 2 and (*init.begin())->is_string())
-    {
-        std::string key = init.begin()->moved_or_copied();
-        push_back(std::pair<std::string_view, json>(key, (init.begin() + 1)->moved_or_copied()));
-    }
-    else
-    {
-        push_back(json(init));
-    }
-}
-
-json::iterator json::insert(const_iterator pos, const json& val)
-{
-    // insert only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        // check if iterator pos fits to this JSON value
-        if (JSON_UNLIKELY(pos.m_object != this))
-        {
-            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
-        }
-
-        // insert to array and return iterator
-        iterator result(this);
-        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
-        return result;
-    }
-
-    JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
-}
-
-json::iterator json::insert(const_iterator pos, size_type cnt, const json& val)
-{
-    // insert only works for arrays
-    if (JSON_LIKELY(is_array()))
-    {
-        // check if iterator pos fits to this JSON value
-        if (JSON_UNLIKELY(pos.m_object != this))
-        {
-            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
-        }
-
-        // insert to array and return iterator
-        iterator result(this);
-        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
-        return result;
-    }
-
-    JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
-}
-
-json::iterator json::insert(const_iterator pos, const_iterator first, const_iterator last)
-{
-    // insert only works for arrays
-    if (JSON_UNLIKELY(not is_array()))
-    {
-        JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
-    }
-
-    // check if iterator pos fits to this JSON value
-    if (JSON_UNLIKELY(pos.m_object != this))
-    {
-        JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
-    }
-
-    // check if range iterators belong to the same JSON object
-    if (JSON_UNLIKELY(first.m_object != last.m_object))
-    {
-        JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
-    }
-
-    if (JSON_UNLIKELY(first.m_object == this))
-    {
-        JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
-    }
-
-    // insert to array and return iterator
-    iterator result(this);
-    result.m_it.array_iterator = m_value.array->insert(
-                                     pos.m_it.array_iterator,
-                                     first.m_it.array_iterator,
-                                     last.m_it.array_iterator);
-    return result;
-}
-
-json::iterator json::insert(const_iterator pos, initializer_list_t ilist)
-{
-    // insert only works for arrays
-    if (JSON_UNLIKELY(not is_array()))
-    {
-        JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
-    }
-
-    // check if iterator pos fits to this JSON value
-    if (JSON_UNLIKELY(pos.m_object != this))
-    {
-        JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
-    }
-
-    // insert to array and return iterator
-    iterator result(this);
-    result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end());
-    return result;
-}
-
-void json::insert(const_iterator first, const_iterator last)
-{
-    // insert only works for objects
-    if (JSON_UNLIKELY(not is_object()))
-    {
-        JSON_THROW(type_error::create(309, "cannot use insert() with", type_name()));
-    }
-
-    // check if range iterators belong to the same JSON object
-    if (JSON_UNLIKELY(first.m_object != last.m_object))
-    {
-        JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
-    }
-
-    // passed iterators must belong to objects
-    if (JSON_UNLIKELY(not first.m_object->is_object()))
-    {
-        JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
-    }
-
-    for (auto it = first.m_it.object_iterator, end = last.m_it.object_iterator; it != end; ++it)
-    {
-        m_value.object->insert(std::make_pair(it->first(), it->second));
-    }
-}
-
-void json::update(const_reference j)
-{
-    // implicitly convert null value to an empty object
-    if (is_null())
-    {
-        m_type = value_t::object;
-        m_value.object = create<object_t>();
-        assert_invariant();
-    }
-
-    if (JSON_UNLIKELY(not is_object()))
-    {
-        JSON_THROW(type_error::create(312, "cannot use update() with", type_name()));
-    }
-    if (JSON_UNLIKELY(not j.is_object()))
-    {
-        JSON_THROW(type_error::create(312, "cannot use update() with", j.type_name()));
-    }
-
-    for (auto it = j.cbegin(); it != j.cend(); ++it)
-    {
-        m_value.object->operator[](it.key()) = it.value();
-    }
-}
-
-void json::update(const_iterator first, const_iterator last)
-{
-    // implicitly convert null value to an empty object
-    if (is_null())
-    {
-        m_type = value_t::object;
-        m_value.object = create<object_t>();
-        assert_invariant();
-    }
-
-    if (JSON_UNLIKELY(not is_object()))
-    {
-        JSON_THROW(type_error::create(312, "cannot use update() with", type_name()));
-    }
-
-    // check if range iterators belong to the same JSON object
-    if (JSON_UNLIKELY(first.m_object != last.m_object))
-    {
-        JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
-    }
-
-    // passed iterators must belong to objects
-    if (JSON_UNLIKELY(not first.m_object->is_object()
-                      or not last.m_object->is_object()))
-    {
-        JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
-    }
-
-    for (auto it = first; it != last; ++it)
-    {
-        m_value.object->operator[](it.key()) = it.value();
-    }
-}
-
-bool operator==(json::const_reference lhs, json::const_reference rhs) noexcept
-{
-    const auto lhs_type = lhs.type();
-    const auto rhs_type = rhs.type();
-
-    if (lhs_type == rhs_type)
-    {
-        switch (lhs_type)
-        {
-            case json::value_t::array:
-                return (*lhs.m_value.array == *rhs.m_value.array);
-
-            case json::value_t::object:
-                return (*lhs.m_value.object == *rhs.m_value.object);
-
-            case json::value_t::null:
-                return true;
-
-            case json::value_t::string:
-                return (*lhs.m_value.string == *rhs.m_value.string);
-
-            case json::value_t::boolean:
-                return (lhs.m_value.boolean == rhs.m_value.boolean);
-
-            case json::value_t::number_integer:
-                return (lhs.m_value.number_integer == rhs.m_value.number_integer);
-
-            case json::value_t::number_unsigned:
-                return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned);
-
-            case json::value_t::number_float:
-                return (lhs.m_value.number_float == rhs.m_value.number_float);
-
-            default:
-                return false;
-        }
-    }
-    else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_float)
-    {
-        return (static_cast<double>(lhs.m_value.number_integer) == rhs.m_value.number_float);
-    }
-    else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_integer)
-    {
-        return (lhs.m_value.number_float == static_cast<double>(rhs.m_value.number_integer));
-    }
-    else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_float)
-    {
-        return (static_cast<double>(lhs.m_value.number_unsigned) == rhs.m_value.number_float);
-    }
-    else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_unsigned)
-    {
-        return (lhs.m_value.number_float == static_cast<double>(rhs.m_value.number_unsigned));
-    }
-    else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_integer)
-    {
-        return (static_cast<int64_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer);
-    }
-    else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_unsigned)
-    {
-        return (lhs.m_value.number_integer == static_cast<int64_t>(rhs.m_value.number_unsigned));
-    }
-
-    return false;
-}
-
-bool operator<(json::const_reference lhs, json::const_reference rhs) noexcept
-{
-    const auto lhs_type = lhs.type();
-    const auto rhs_type = rhs.type();
-
-    if (lhs_type == rhs_type)
-    {
-        switch (lhs_type)
-        {
-            case json::value_t::array:
-                return (*lhs.m_value.array) < (*rhs.m_value.array);
-
-            case json::value_t::object:
-                return *lhs.m_value.object < *rhs.m_value.object;
-
-            case json::value_t::null:
-                return false;
-
-            case json::value_t::string:
-                return *lhs.m_value.string < *rhs.m_value.string;
-
-            case json::value_t::boolean:
-                return lhs.m_value.boolean < rhs.m_value.boolean;
-
-            case json::value_t::number_integer:
-                return lhs.m_value.number_integer < rhs.m_value.number_integer;
-
-            case json::value_t::number_unsigned:
-                return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
-
-            case json::value_t::number_float:
-                return lhs.m_value.number_float < rhs.m_value.number_float;
-
-            default:
-                return false;
-        }
-    }
-    else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_float)
-    {
-        return static_cast<double>(lhs.m_value.number_integer) < rhs.m_value.number_float;
-    }
-    else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_integer)
-    {
-        return lhs.m_value.number_float < static_cast<double>(rhs.m_value.number_integer);
-    }
-    else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_float)
-    {
-        return static_cast<double>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
-    }
-    else if (lhs_type == json::value_t::number_float and rhs_type == json::value_t::number_unsigned)
-    {
-        return lhs.m_value.number_float < static_cast<double>(rhs.m_value.number_unsigned);
-    }
-    else if (lhs_type == json::value_t::number_integer and rhs_type == json::value_t::number_unsigned)
-    {
-        return lhs.m_value.number_integer < static_cast<int64_t>(rhs.m_value.number_unsigned);
-    }
-    else if (lhs_type == json::value_t::number_unsigned and rhs_type == json::value_t::number_integer)
-    {
-        return static_cast<int64_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
-    }
-
-    // We only reach this line if we cannot compare values. In that case,
-    // we compare types. Note we have to call the operator explicitly,
-    // because MSVC has problems otherwise.
-    return operator<(lhs_type, rhs_type);
-}
-
-const char* json::type_name() const noexcept
-{
-    {
-        switch (m_type)
-        {
-            case value_t::null:
-                return "null";
-            case value_t::object:
-                return "object";
-            case value_t::array:
-                return "array";
-            case value_t::string:
-                return "string";
-            case value_t::boolean:
-                return "boolean";
-            case value_t::discarded:
-                return "discarded";
-            default:
-                return "number";
-        }
-    }
-}
-
-json json::patch(const json& json_patch) const
-{
-    // make a working copy to apply the patch to
-    json result = *this;
-
-    // the valid JSON Patch operations
-    enum class patch_operations {add, remove, replace, move, copy, test, invalid};
-
-    const auto get_op = [](const std::string & op)
-    {
-        if (op == "add")
-        {
-            return patch_operations::add;
-        }
-        if (op == "remove")
-        {
-            return patch_operations::remove;
-        }
-        if (op == "replace")
-        {
-            return patch_operations::replace;
-        }
-        if (op == "move")
-        {
-            return patch_operations::move;
-        }
-        if (op == "copy")
-        {
-            return patch_operations::copy;
-        }
-        if (op == "test")
-        {
-            return patch_operations::test;
-        }
-
-        return patch_operations::invalid;
-    };
-
-    // wrapper for "add" operation; add value at ptr
-    const auto operation_add = [&result](json_pointer & ptr, json val)
-    {
-        // adding to the root of the target document means replacing it
-        if (ptr.is_root())
-        {
-            result = val;
-        }
-        else
-        {
-            // make sure the top element of the pointer exists
-            json_pointer top_pointer = ptr.top();
-            if (top_pointer != ptr)
-            {
-                result.at(top_pointer);
-            }
-
-            // get reference to parent of JSON pointer ptr
-            const auto last_path = ptr.pop_back();
-            json& parent = result[ptr];
-
-            switch (parent.m_type)
-            {
-                case value_t::null:
-                case value_t::object:
-                {
-                    // use operator[] to add value
-                    parent[last_path] = val;
-                    break;
-                }
-
-                case value_t::array:
-                {
-                    if (last_path == "-")
-                    {
-                        // special case: append to back
-                        parent.push_back(val);
-                    }
-                    else
-                    {
-                        const auto idx = json_pointer::array_index(last_path);
-                        if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
-                        {
-                            // avoid undefined behavior
-                            JSON_THROW(out_of_range::create(401, fmt::format("array index {} is out of range", idx)));
-                        }
-                        else
-                        {
-                            // default case: insert add offset
-                            parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
-                        }
-                    }
-                    break;
-                }
-
-                default:
-                {
-                    // if there exists a parent it cannot be primitive
-                    assert(false);  // LCOV_EXCL_LINE
-                }
-            }
-        }
-    };
-
-    // wrapper for "remove" operation; remove value at ptr
-    const auto operation_remove = [&result](json_pointer & ptr)
-    {
-        // get reference to parent of JSON pointer ptr
-        const auto last_path = ptr.pop_back();
-        json& parent = result.at(ptr);
-
-        // remove child
-        if (parent.is_object())
-        {
-            // perform range check
-            auto it = parent.find(last_path);
-            if (JSON_LIKELY(it != parent.end()))
-            {
-                parent.erase(it);
-            }
-            else
-            {
-                JSON_THROW(out_of_range::create(403, fmt::format("key '{}' not found", last_path)));
-            }
-        }
-        else if (parent.is_array())
-        {
-            // note erase performs range check
-            parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));
-        }
-    };
-
-    // type check: top level value must be an array
-    if (JSON_UNLIKELY(not json_patch.is_array()))
-    {
-        JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
-    }
-
-    // iterate and apply the operations
-    for (const auto& val : json_patch)
-    {
-        // wrapper to get a value for an operation
-        const auto get_value = [&val](const std::string & op,
-                                      const std::string & member,
-                                      bool string_type) -> json &
-        {
-            // find value
-            auto it = val.m_value.object->find(member);
-
-            // context-sensitive error message
-            const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
-
-            // check if desired value is present
-            if (JSON_UNLIKELY(it == val.m_value.object->end()))
-            {
-                JSON_THROW(parse_error::create(105, 0, fmt::format("{} must have member '{}'", error_msg, member)));
-            }
-
-            // check if result is of type string
-            if (JSON_UNLIKELY(string_type and not it->second.is_string()))
-            {
-                JSON_THROW(parse_error::create(105, 0, fmt::format("{} must have string member '{}'", error_msg, member)));
-            }
-
-            // no error: return value
-            return it->second;
-        };
-
-        // type check: every element of the array must be an object
-        if (JSON_UNLIKELY(not val.is_object()))
-        {
-            JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
-        }
-
-        // collect mandatory members
-        const std::string op = get_value("op", "op", true);
-        const std::string path = get_value(op, "path", true);
-        json_pointer ptr(path);
-
-        switch (get_op(op))
-        {
-            case patch_operations::add:
-            {
-                operation_add(ptr, get_value("add", "value", false));
-                break;
-            }
-
-            case patch_operations::remove:
-            {
-                operation_remove(ptr);
-                break;
-            }
-
-            case patch_operations::replace:
-            {
-                // the "path" location must exist - use at()
-                result.at(ptr) = get_value("replace", "value", false);
-                break;
-            }
-
-            case patch_operations::move:
-            {
-                const std::string from_path = get_value("move", "from", true);
-                json_pointer from_ptr(from_path);
-
-                // the "from" location must exist - use at()
-                json v = result.at(from_ptr);
-
-                // The move operation is functionally identical to a
-                // "remove" operation on the "from" location, followed
-                // immediately by an "add" operation at the target
-                // location with the value that was just removed.
-                operation_remove(from_ptr);
-                operation_add(ptr, v);
-                break;
-            }
-
-            case patch_operations::copy:
-            {
-                const std::string from_path = get_value("copy", "from", true);
-                const json_pointer from_ptr(from_path);
-
-                // the "from" location must exist - use at()
-                json v = result.at(from_ptr);
-
-                // The copy is functionally identical to an "add"
-                // operation at the target location using the value
-                // specified in the "from" member.
-                operation_add(ptr, v);
-                break;
-            }
-
-            case patch_operations::test:
-            {
-                bool success = false;
-                JSON_TRY
-                {
-                    // check if "value" matches the one at "path"
-                    // the "path" location must exist - use at()
-                    success = (result.at(ptr) == get_value("test", "value", false));
-                }
-                JSON_CATCH (out_of_range&)
-                {
-                    // ignore out of range errors: success remains false
-                }
-
-                // throw an exception if test fails
-                if (JSON_UNLIKELY(not success))
-                {
-                    JSON_THROW(other_error::create(501, fmt::format("unsuccessful: {}", val.dump())));
-                }
-
-                break;
-            }
-
-            case patch_operations::invalid:
-            {
-                // op must be "add", "remove", "replace", "move", "copy", or
-                // "test"
-                JSON_THROW(parse_error::create(105, 0, fmt::format("operation value '{}' is invalid", op)));
-            }
-        }
-    }
-
-    return result;
-}
-
-json json::diff(const json& source, const json& target,
-                       const std::string& path)
-{
-    // the patch
-    json result(value_t::array);
-
-    // if the values are the same, return empty patch
-    if (source == target)
-    {
-        return result;
-    }
-
-    if (source.type() != target.type())
-    {
-        // different types: replace value
-        result.push_back(
-        {
-            {"op", "replace"}, {"path", path}, {"value", target}
-        });
-    }
-    else
-    {
-        switch (source.type())
-        {
-            case value_t::array:
-            {
-                // first pass: traverse common elements
-                std::size_t i = 0;
-                while (i < source.size() and i < target.size())
-                {
-                    // recursive call to compare array values at index i
-                    auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
-                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());
-                    ++i;
-                }
-
-                // i now reached the end of at least one array
-                // in a second pass, traverse the remaining elements
-
-                // remove my remaining elements
-                const auto end_index = static_cast<difference_type>(result.size());
-                while (i < source.size())
-                {
-                    // add operations in reverse order to avoid invalid
-                    // indices
-                    result.insert(result.begin() + end_index, object(
-                    {
-                        {"op", "remove"},
-                        {"path", path + "/" + std::to_string(i)}
-                    }));
-                    ++i;
-                }
-
-                // add other remaining elements
-                while (i < target.size())
-                {
-                    result.push_back(
-                    {
-                        {"op", "add"},
-                        {"path", path + "/" + std::to_string(i)},
-                        {"value", target[i]}
-                    });
-                    ++i;
-                }
-
-                break;
-            }
-
-            case value_t::object:
-            {
-                // first pass: traverse this object's elements
-                for (auto it = source.cbegin(); it != source.cend(); ++it)
-                {
-                    // escape the key name to be used in a JSON patch
-                    const auto key = json_pointer::escape(std::string{it.key()});
-
-                    if (target.find(it.key()) != target.end())
-                    {
-                        // recursive call to compare object values at key it
-                        auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
-                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
-                    }
-                    else
-                    {
-                        // found a key that is not in o -> remove it
-                        result.push_back(object(
-                        {
-                            {"op", "remove"}, {"path", path + "/" + key}
-                        }));
-                    }
-                }
-
-                // second pass: traverse other object's elements
-                for (auto it = target.cbegin(); it != target.cend(); ++it)
-                {
-                    if (source.find(it.key()) == source.end())
-                    {
-                        // found a key that is not in this -> add it
-                        const auto key = json_pointer::escape(std::string{it.key()});
-                        result.push_back(
-                        {
-                            {"op", "add"}, {"path", path + "/" + key},
-                            {"value", it.value()}
-                        });
-                    }
-                }
-
-                break;
-            }
-
-            default:
-            {
-                // both primitive type: replace value
-                result.push_back(
-                {
-                    {"op", "replace"}, {"path", path}, {"value", target}
-                });
-                break;
-            }
-        }
-    }
-
-    return result;
-}
-
-void json::merge_patch(const json& patch)
-{
-    if (patch.is_object())
-    {
-        if (not is_object())
-        {
-            *this = object();
-        }
-        for (auto it = patch.begin(); it != patch.end(); ++it)
-        {
-            if (it.value().is_null())
-            {
-                erase(it.key());
-            }
-            else
-            {
-                operator[](it.key()).merge_patch(it.value());
-            }
-        }
-    }
-    else
-    {
-        *this = patch;
-    }
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
deleted file mode 100644
index 2081359..0000000
--- a/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
+++ /dev/null
@@ -1,1415 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#define WPI_JSON_IMPLEMENTATION
-#include "wpi/json.h"
-
-#include <cmath>  // ldexp
-
-#include "fmt/format.h"
-#include "wpi/raw_istream.h"
-
-namespace wpi {
-
-/*!
-@brief deserialization of CBOR and MessagePack values
-*/
-class json::binary_reader
-{
-  public:
-    /*!
-    @brief create a binary reader
-
-    @param[in] adapter  input adapter to read from
-    */
-    explicit binary_reader(raw_istream& s) : is(s)
-    {
-    }
-
-    /*!
-    @brief create a JSON value from CBOR input
-
-    @param[in] strict  whether to expect the input to be consumed completed
-    @return JSON value created from CBOR input
-
-    @throw parse_error.110 if input ended unexpectedly or the end of file was
-                           not reached when @a strict was set to true
-    @throw parse_error.112 if unsupported byte was read
-    */
-    json parse_cbor(const bool strict)
-    {
-        const auto res = parse_cbor_internal();
-        if (strict)
-        {
-            get();
-            expect_eof();
-        }
-        return res;
-    }
-
-    /*!
-    @brief create a JSON value from MessagePack input
-
-    @param[in] strict  whether to expect the input to be consumed completed
-    @return JSON value created from MessagePack input
-
-    @throw parse_error.110 if input ended unexpectedly or the end of file was
-                           not reached when @a strict was set to true
-    @throw parse_error.112 if unsupported byte was read
-    */
-    json parse_msgpack(const bool strict)
-    {
-        const auto res = parse_msgpack_internal();
-        if (strict)
-        {
-            get();
-            expect_eof();
-        }
-        return res;
-    }
-
-    /*!
-    @brief create a JSON value from UBJSON input
-
-    @param[in] strict  whether to expect the input to be consumed completed
-    @return JSON value created from UBJSON input
-
-    @throw parse_error.110 if input ended unexpectedly or the end of file was
-                           not reached when @a strict was set to true
-    @throw parse_error.112 if unsupported byte was read
-    */
-    json parse_ubjson(const bool strict)
-    {
-        const auto res = parse_ubjson_internal();
-        if (strict)
-        {
-            get_ignore_noop();
-            expect_eof();
-        }
-        return res;
-    }
-
-    /*!
-    @brief determine system byte order
-
-    @return true if and only if system's byte order is little endian
-
-    @note from http://stackoverflow.com/a/1001328/266378
-    */
-    static bool little_endianess(int num = 1) noexcept
-    {
-        return (*reinterpret_cast<char*>(&num) == 1);
-    }
-
-  private:
-    /*!
-    @param[in] get_char  whether a new character should be retrieved from the
-                         input (true, default) or whether the last read
-                         character should be considered instead
-    */
-    json parse_cbor_internal(const bool get_char = true);
-
-    json parse_msgpack_internal();
-
-    /*!
-    @param[in] get_char  whether a new character should be retrieved from the
-                         input (true, default) or whether the last read
-                         character should be considered instead
-    */
-    json parse_ubjson_internal(const bool get_char = true)
-    {
-        return get_ubjson_value(get_char ? get_ignore_noop() : current);
-    }
-
-    /*!
-    @brief get next character from the input
-
-    This function provides the interface to the used input adapter. It does
-    not throw in case the input reached EOF, but returns a -'ve valued
-    `std::char_traits<char>::eof()` in that case.
-
-    @return character read from the input
-    */
-    int get()
-    {
-        ++chars_read;
-        unsigned char c;
-        is.read(c);
-        if (is.has_error())
-        {
-            current = std::char_traits<char>::eof();
-        }
-        else
-        {
-            current = c;
-        }
-        return current;
-    }
-
-    /*!
-    @return character read from the input after ignoring all 'N' entries
-    */
-    int get_ignore_noop()
-    {
-        do
-        {
-            get();
-        }
-        while (current == 'N');
-
-        return current;
-    }
-
-    /*
-    @brief read a number from the input
-
-    @tparam NumberType the type of the number
-
-    @return number of type @a NumberType
-
-    @note This function needs to respect the system's endianess, because
-          bytes in CBOR and MessagePack are stored in network order (big
-          endian) and therefore need reordering on little endian systems.
-
-    @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes
-    */
-    template<typename NumberType> NumberType get_number()
-    {
-        // step 1: read input into array with system's byte order
-        std::array<uint8_t, sizeof(NumberType)> vec;
-        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
-        {
-            get();
-            unexpect_eof();
-
-            // reverse byte order prior to conversion if necessary
-            if (is_little_endian)
-            {
-                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
-            }
-            else
-            {
-                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
-            }
-        }
-
-        // step 2: convert array into number of type T and return
-        NumberType result;
-        std::memcpy(&result, vec.data(), sizeof(NumberType));
-        return result;
-    }
-
-    /*!
-    @brief create a string by reading characters from the input
-
-    @param[in] len number of bytes to read
-
-    @note We can not reserve @a len bytes for the result, because @a len
-          may be too large. Usually, @ref unexpect_eof() detects the end of
-          the input before we run out of string memory.
-
-    @return string created by reading @a len bytes
-
-    @throw parse_error.110 if input has less than @a len bytes
-    */
-    template<typename NumberType>
-    std::string get_string(const NumberType len)
-    {
-        std::string result;
-        std::generate_n(std::back_inserter(result), len, [this]()
-        {
-            get();
-            unexpect_eof();
-            return static_cast<char>(current);
-        });
-        return result;
-    }
-
-    /*!
-    @brief reads a CBOR string
-
-    This function first reads starting bytes to determine the expected
-    string length and then copies this number of bytes into a string.
-    Additionally, CBOR's strings with indefinite lengths are supported.
-
-    @return string
-
-    @throw parse_error.110 if input ended
-    @throw parse_error.113 if an unexpected byte is read
-    */
-    std::string get_cbor_string();
-
-    template<typename NumberType>
-    json get_cbor_array(const NumberType len)
-    {
-        json result = value_t::array;
-        std::generate_n(std::back_inserter(*result.m_value.array), len, [this]()
-        {
-            return parse_cbor_internal();
-        });
-        return result;
-    }
-
-    template<typename NumberType>
-    json get_cbor_object(const NumberType len)
-    {
-        json result = value_t::object;
-        for (NumberType i = 0; i < len; ++i)
-        {
-            get();
-            auto key = get_cbor_string();
-            (*result.m_value.object)[key] = parse_cbor_internal();
-        }
-        return result;
-    }
-
-    /*!
-    @brief reads a MessagePack string
-
-    This function first reads starting bytes to determine the expected
-    string length and then copies this number of bytes into a string.
-
-    @return string
-
-    @throw parse_error.110 if input ended
-    @throw parse_error.113 if an unexpected byte is read
-    */
-    std::string get_msgpack_string();
-
-    template<typename NumberType>
-    json get_msgpack_array(const NumberType len)
-    {
-        json result = value_t::array;
-        std::generate_n(std::back_inserter(*result.m_value.array), len, [this]()
-        {
-            return parse_msgpack_internal();
-        });
-        return result;
-    }
-
-    template<typename NumberType>
-    json get_msgpack_object(const NumberType len)
-    {
-        json result = value_t::object;
-        for (NumberType i = 0; i < len; ++i)
-        {
-            get();
-            auto key = get_msgpack_string();
-            (*result.m_value.object)[key] = parse_msgpack_internal();
-        }
-        return result;
-    }
-
-    /*!
-    @brief reads a UBJSON string
-
-    This function is either called after reading the 'S' byte explicitly
-    indicating a string, or in case of an object key where the 'S' byte can be
-    left out.
-
-    @param[in] get_char  whether a new character should be retrieved from the
-                         input (true, default) or whether the last read
-                         character should be considered instead
-
-    @return string
-
-    @throw parse_error.110 if input ended
-    @throw parse_error.113 if an unexpected byte is read
-    */
-    std::string get_ubjson_string(const bool get_char = true);
-
-    /*!
-    @brief determine the type and size for a container
-
-    In the optimized UBJSON format, a type and a size can be provided to allow
-    for a more compact representation.
-
-    @return pair of the size and the type
-    */
-    std::pair<std::size_t, int> get_ubjson_size_type();
-
-    json get_ubjson_value(const int prefix);
-
-    json get_ubjson_array();
-
-    json get_ubjson_object();
-
-    /*!
-    @brief throw if end of input is not reached
-    @throw parse_error.110 if input not ended
-    */
-    void expect_eof() const
-    {
-        if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))
-        {
-            JSON_THROW(parse_error::create(110, chars_read, "expected end of input"));
-        }
-    }
-
-    /*!
-    @briefthrow if end of input is reached
-    @throw parse_error.110 if input ended
-    */
-    void unexpect_eof() const
-    {
-        if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
-        {
-            JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
-        }
-    }
-
-  private:
-    /// input adapter
-    raw_istream& is;
-
-    /// the current character
-    int current = std::char_traits<char>::eof();
-
-    /// the number of characters read
-    std::size_t chars_read = 0;
-
-    /// whether we can assume little endianess
-    const bool is_little_endian = little_endianess();
-};
-
-json json::binary_reader::parse_cbor_internal(const bool get_char)
-{
-    switch (get_char ? get() : current)
-    {
-        // EOF
-        case std::char_traits<char>::eof():
-            JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
-
-        // Integer 0x00..0x17 (0..23)
-        case 0x00:
-        case 0x01:
-        case 0x02:
-        case 0x03:
-        case 0x04:
-        case 0x05:
-        case 0x06:
-        case 0x07:
-        case 0x08:
-        case 0x09:
-        case 0x0A:
-        case 0x0B:
-        case 0x0C:
-        case 0x0D:
-        case 0x0E:
-        case 0x0F:
-        case 0x10:
-        case 0x11:
-        case 0x12:
-        case 0x13:
-        case 0x14:
-        case 0x15:
-        case 0x16:
-        case 0x17:
-            return static_cast<uint64_t>(current);
-
-        case 0x18: // Unsigned integer (one-byte uint8_t follows)
-            return get_number<uint8_t>();
-
-        case 0x19: // Unsigned integer (two-byte uint16_t follows)
-            return get_number<uint16_t>();
-
-        case 0x1A: // Unsigned integer (four-byte uint32_t follows)
-            return get_number<uint32_t>();
-
-        case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
-            return get_number<uint64_t>();
-
-        // Negative integer -1-0x00..-1-0x17 (-1..-24)
-        case 0x20:
-        case 0x21:
-        case 0x22:
-        case 0x23:
-        case 0x24:
-        case 0x25:
-        case 0x26:
-        case 0x27:
-        case 0x28:
-        case 0x29:
-        case 0x2A:
-        case 0x2B:
-        case 0x2C:
-        case 0x2D:
-        case 0x2E:
-        case 0x2F:
-        case 0x30:
-        case 0x31:
-        case 0x32:
-        case 0x33:
-        case 0x34:
-        case 0x35:
-        case 0x36:
-        case 0x37:
-            return static_cast<int8_t>(0x20 - 1 - current);
-
-        case 0x38: // Negative integer (one-byte uint8_t follows)
-        {
-            return static_cast<int64_t>(-1) - get_number<uint8_t>();
-        }
-
-        case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
-        {
-            return static_cast<int64_t>(-1) - get_number<uint16_t>();
-        }
-
-        case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
-        {
-            return static_cast<int64_t>(-1) - get_number<uint32_t>();
-        }
-
-        case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
-        {
-            return static_cast<int64_t>(-1) -
-                   static_cast<int64_t>(get_number<uint64_t>());
-        }
-
-        // UTF-8 string (0x00..0x17 bytes follow)
-        case 0x60:
-        case 0x61:
-        case 0x62:
-        case 0x63:
-        case 0x64:
-        case 0x65:
-        case 0x66:
-        case 0x67:
-        case 0x68:
-        case 0x69:
-        case 0x6A:
-        case 0x6B:
-        case 0x6C:
-        case 0x6D:
-        case 0x6E:
-        case 0x6F:
-        case 0x70:
-        case 0x71:
-        case 0x72:
-        case 0x73:
-        case 0x74:
-        case 0x75:
-        case 0x76:
-        case 0x77:
-        case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
-        case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
-        case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
-        case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
-        case 0x7F: // UTF-8 string (indefinite length)
-        {
-            return get_cbor_string();
-        }
-
-        // array (0x00..0x17 data items follow)
-        case 0x80:
-        case 0x81:
-        case 0x82:
-        case 0x83:
-        case 0x84:
-        case 0x85:
-        case 0x86:
-        case 0x87:
-        case 0x88:
-        case 0x89:
-        case 0x8A:
-        case 0x8B:
-        case 0x8C:
-        case 0x8D:
-        case 0x8E:
-        case 0x8F:
-        case 0x90:
-        case 0x91:
-        case 0x92:
-        case 0x93:
-        case 0x94:
-        case 0x95:
-        case 0x96:
-        case 0x97:
-        {
-            return get_cbor_array(current & 0x1F);
-        }
-
-        case 0x98: // array (one-byte uint8_t for n follows)
-        {
-            return get_cbor_array(get_number<uint8_t>());
-        }
-
-        case 0x99: // array (two-byte uint16_t for n follow)
-        {
-            return get_cbor_array(get_number<uint16_t>());
-        }
-
-        case 0x9A: // array (four-byte uint32_t for n follow)
-        {
-            return get_cbor_array(get_number<uint32_t>());
-        }
-
-        case 0x9B: // array (eight-byte uint64_t for n follow)
-        {
-            return get_cbor_array(get_number<uint64_t>());
-        }
-
-        case 0x9F: // array (indefinite length)
-        {
-            json result = value_t::array;
-            while (get() != 0xFF)
-            {
-                result.push_back(parse_cbor_internal(false));
-            }
-            return result;
-        }
-
-        // map (0x00..0x17 pairs of data items follow)
-        case 0xA0:
-        case 0xA1:
-        case 0xA2:
-        case 0xA3:
-        case 0xA4:
-        case 0xA5:
-        case 0xA6:
-        case 0xA7:
-        case 0xA8:
-        case 0xA9:
-        case 0xAA:
-        case 0xAB:
-        case 0xAC:
-        case 0xAD:
-        case 0xAE:
-        case 0xAF:
-        case 0xB0:
-        case 0xB1:
-        case 0xB2:
-        case 0xB3:
-        case 0xB4:
-        case 0xB5:
-        case 0xB6:
-        case 0xB7:
-        {
-            return get_cbor_object(current & 0x1F);
-        }
-
-        case 0xB8: // map (one-byte uint8_t for n follows)
-        {
-            return get_cbor_object(get_number<uint8_t>());
-        }
-
-        case 0xB9: // map (two-byte uint16_t for n follow)
-        {
-            return get_cbor_object(get_number<uint16_t>());
-        }
-
-        case 0xBA: // map (four-byte uint32_t for n follow)
-        {
-            return get_cbor_object(get_number<uint32_t>());
-        }
-
-        case 0xBB: // map (eight-byte uint64_t for n follow)
-        {
-            return get_cbor_object(get_number<uint64_t>());
-        }
-
-        case 0xBF: // map (indefinite length)
-        {
-            json result = value_t::object;
-            while (get() != 0xFF)
-            {
-                auto key = get_cbor_string();
-                result[key] = parse_cbor_internal();
-            }
-            return result;
-        }
-
-        case 0xF4: // false
-        {
-            return false;
-        }
-
-        case 0xF5: // true
-        {
-            return true;
-        }
-
-        case 0xF6: // null
-        {
-            return value_t::null;
-        }
-
-        case 0xF9: // Half-Precision Float (two-byte IEEE 754)
-        {
-            const int byte1 = get();
-            unexpect_eof();
-            const int byte2 = get();
-            unexpect_eof();
-
-            // code from RFC 7049, Appendix D, Figure 3:
-            // As half-precision floating-point numbers were only added
-            // to IEEE 754 in 2008, today's programming platforms often
-            // still only have limited support for them. It is very
-            // easy to include at least decoding support for them even
-            // without such support. An example of a small decoder for
-            // half-precision floating-point numbers in the C language
-            // is shown in Fig. 3.
-            const int half = (byte1 << 8) + byte2;
-            const int exp = (half >> 10) & 0x1F;
-            const int mant = half & 0x3FF;
-            double val;
-            if (exp == 0)
-            {
-                val = std::ldexp(mant, -24);
-            }
-            else if (exp != 31)
-            {
-                val = std::ldexp(mant + 1024, exp - 25);
-            }
-            else
-            {
-                val = (mant == 0) ? std::numeric_limits<double>::infinity()
-                      : std::numeric_limits<double>::quiet_NaN();
-            }
-            return (half & 0x8000) != 0 ? -val : val;
-        }
-
-        case 0xFA: // Single-Precision Float (four-byte IEEE 754)
-        {
-            return get_number<float>();
-        }
-
-        case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
-        {
-            return get_number<double>();
-        }
-
-        default: // anything else (0xFF is handled inside the other types)
-        {
-            JSON_THROW(parse_error::create(112, chars_read, fmt::format("error reading CBOR; last byte: {:#02x}", current)));
-        }
-    }
-}
-
-json json::binary_reader::parse_msgpack_internal()
-{
-    switch (get())
-    {
-        // EOF
-        case std::char_traits<char>::eof():
-            JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
-
-        // positive fixint
-        case 0x00:
-        case 0x01:
-        case 0x02:
-        case 0x03:
-        case 0x04:
-        case 0x05:
-        case 0x06:
-        case 0x07:
-        case 0x08:
-        case 0x09:
-        case 0x0A:
-        case 0x0B:
-        case 0x0C:
-        case 0x0D:
-        case 0x0E:
-        case 0x0F:
-        case 0x10:
-        case 0x11:
-        case 0x12:
-        case 0x13:
-        case 0x14:
-        case 0x15:
-        case 0x16:
-        case 0x17:
-        case 0x18:
-        case 0x19:
-        case 0x1A:
-        case 0x1B:
-        case 0x1C:
-        case 0x1D:
-        case 0x1E:
-        case 0x1F:
-        case 0x20:
-        case 0x21:
-        case 0x22:
-        case 0x23:
-        case 0x24:
-        case 0x25:
-        case 0x26:
-        case 0x27:
-        case 0x28:
-        case 0x29:
-        case 0x2A:
-        case 0x2B:
-        case 0x2C:
-        case 0x2D:
-        case 0x2E:
-        case 0x2F:
-        case 0x30:
-        case 0x31:
-        case 0x32:
-        case 0x33:
-        case 0x34:
-        case 0x35:
-        case 0x36:
-        case 0x37:
-        case 0x38:
-        case 0x39:
-        case 0x3A:
-        case 0x3B:
-        case 0x3C:
-        case 0x3D:
-        case 0x3E:
-        case 0x3F:
-        case 0x40:
-        case 0x41:
-        case 0x42:
-        case 0x43:
-        case 0x44:
-        case 0x45:
-        case 0x46:
-        case 0x47:
-        case 0x48:
-        case 0x49:
-        case 0x4A:
-        case 0x4B:
-        case 0x4C:
-        case 0x4D:
-        case 0x4E:
-        case 0x4F:
-        case 0x50:
-        case 0x51:
-        case 0x52:
-        case 0x53:
-        case 0x54:
-        case 0x55:
-        case 0x56:
-        case 0x57:
-        case 0x58:
-        case 0x59:
-        case 0x5A:
-        case 0x5B:
-        case 0x5C:
-        case 0x5D:
-        case 0x5E:
-        case 0x5F:
-        case 0x60:
-        case 0x61:
-        case 0x62:
-        case 0x63:
-        case 0x64:
-        case 0x65:
-        case 0x66:
-        case 0x67:
-        case 0x68:
-        case 0x69:
-        case 0x6A:
-        case 0x6B:
-        case 0x6C:
-        case 0x6D:
-        case 0x6E:
-        case 0x6F:
-        case 0x70:
-        case 0x71:
-        case 0x72:
-        case 0x73:
-        case 0x74:
-        case 0x75:
-        case 0x76:
-        case 0x77:
-        case 0x78:
-        case 0x79:
-        case 0x7A:
-        case 0x7B:
-        case 0x7C:
-        case 0x7D:
-        case 0x7E:
-        case 0x7F:
-            return static_cast<uint64_t>(current);
-
-        // fixmap
-        case 0x80:
-        case 0x81:
-        case 0x82:
-        case 0x83:
-        case 0x84:
-        case 0x85:
-        case 0x86:
-        case 0x87:
-        case 0x88:
-        case 0x89:
-        case 0x8A:
-        case 0x8B:
-        case 0x8C:
-        case 0x8D:
-        case 0x8E:
-        case 0x8F:
-        {
-            return get_msgpack_object(current & 0x0F);
-        }
-
-        // fixarray
-        case 0x90:
-        case 0x91:
-        case 0x92:
-        case 0x93:
-        case 0x94:
-        case 0x95:
-        case 0x96:
-        case 0x97:
-        case 0x98:
-        case 0x99:
-        case 0x9A:
-        case 0x9B:
-        case 0x9C:
-        case 0x9D:
-        case 0x9E:
-        case 0x9F:
-        {
-            return get_msgpack_array(current & 0x0F);
-        }
-
-        // fixstr
-        case 0xA0:
-        case 0xA1:
-        case 0xA2:
-        case 0xA3:
-        case 0xA4:
-        case 0xA5:
-        case 0xA6:
-        case 0xA7:
-        case 0xA8:
-        case 0xA9:
-        case 0xAA:
-        case 0xAB:
-        case 0xAC:
-        case 0xAD:
-        case 0xAE:
-        case 0xAF:
-        case 0xB0:
-        case 0xB1:
-        case 0xB2:
-        case 0xB3:
-        case 0xB4:
-        case 0xB5:
-        case 0xB6:
-        case 0xB7:
-        case 0xB8:
-        case 0xB9:
-        case 0xBA:
-        case 0xBB:
-        case 0xBC:
-        case 0xBD:
-        case 0xBE:
-        case 0xBF:
-            return get_msgpack_string();
-
-        case 0xC0: // nil
-            return value_t::null;
-
-        case 0xC2: // false
-            return false;
-
-        case 0xC3: // true
-            return true;
-
-        case 0xCA: // float 32
-            return get_number<float>();
-
-        case 0xCB: // float 64
-            return get_number<double>();
-
-        case 0xCC: // uint 8
-            return get_number<uint8_t>();
-
-        case 0xCD: // uint 16
-            return get_number<uint16_t>();
-
-        case 0xCE: // uint 32
-            return get_number<uint32_t>();
-
-        case 0xCF: // uint 64
-            return get_number<uint64_t>();
-
-        case 0xD0: // int 8
-            return get_number<int8_t>();
-
-        case 0xD1: // int 16
-            return get_number<int16_t>();
-
-        case 0xD2: // int 32
-            return get_number<int32_t>();
-
-        case 0xD3: // int 64
-            return get_number<int64_t>();
-
-        case 0xD9: // str 8
-        case 0xDA: // str 16
-        case 0xDB: // str 32
-            return get_msgpack_string();
-
-        case 0xDC: // array 16
-        {
-            return get_msgpack_array(get_number<uint16_t>());
-        }
-
-        case 0xDD: // array 32
-        {
-            return get_msgpack_array(get_number<uint32_t>());
-        }
-
-        case 0xDE: // map 16
-        {
-            return get_msgpack_object(get_number<uint16_t>());
-        }
-
-        case 0xDF: // map 32
-        {
-            return get_msgpack_object(get_number<uint32_t>());
-        }
-
-        // positive fixint
-        case 0xE0:
-        case 0xE1:
-        case 0xE2:
-        case 0xE3:
-        case 0xE4:
-        case 0xE5:
-        case 0xE6:
-        case 0xE7:
-        case 0xE8:
-        case 0xE9:
-        case 0xEA:
-        case 0xEB:
-        case 0xEC:
-        case 0xED:
-        case 0xEE:
-        case 0xEF:
-        case 0xF0:
-        case 0xF1:
-        case 0xF2:
-        case 0xF3:
-        case 0xF4:
-        case 0xF5:
-        case 0xF6:
-        case 0xF7:
-        case 0xF8:
-        case 0xF9:
-        case 0xFA:
-        case 0xFB:
-        case 0xFC:
-        case 0xFD:
-        case 0xFE:
-        case 0xFF:
-            return static_cast<int8_t>(current);
-
-        default: // anything else
-        {
-            JSON_THROW(parse_error::create(112, chars_read,
-                fmt::format("error reading MessagePack; last byte: {:#02x}", current)));
-        }
-    }
-}
-
-std::string json::binary_reader::get_cbor_string()
-{
-    unexpect_eof();
-
-    switch (current)
-    {
-        // UTF-8 string (0x00..0x17 bytes follow)
-        case 0x60:
-        case 0x61:
-        case 0x62:
-        case 0x63:
-        case 0x64:
-        case 0x65:
-        case 0x66:
-        case 0x67:
-        case 0x68:
-        case 0x69:
-        case 0x6A:
-        case 0x6B:
-        case 0x6C:
-        case 0x6D:
-        case 0x6E:
-        case 0x6F:
-        case 0x70:
-        case 0x71:
-        case 0x72:
-        case 0x73:
-        case 0x74:
-        case 0x75:
-        case 0x76:
-        case 0x77:
-        {
-            return get_string(current & 0x1F);
-        }
-
-        case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
-        {
-            return get_string(get_number<uint8_t>());
-        }
-
-        case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
-        {
-            return get_string(get_number<uint16_t>());
-        }
-
-        case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
-        {
-            return get_string(get_number<uint32_t>());
-        }
-
-        case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
-        {
-            return get_string(get_number<uint64_t>());
-        }
-
-        case 0x7F: // UTF-8 string (indefinite length)
-        {
-            std::string result;
-            while (get() != 0xFF)
-            {
-                result.append(get_cbor_string());
-            }
-            return result;
-        }
-
-        default:
-        {
-            JSON_THROW(parse_error::create(113, chars_read,
-                fmt::format("expected a CBOR string; last byte: {:#02x}", current)));
-        }
-    }
-}
-
-std::string json::binary_reader::get_msgpack_string()
-{
-    unexpect_eof();
-
-    switch (current)
-    {
-        // fixstr
-        case 0xA0:
-        case 0xA1:
-        case 0xA2:
-        case 0xA3:
-        case 0xA4:
-        case 0xA5:
-        case 0xA6:
-        case 0xA7:
-        case 0xA8:
-        case 0xA9:
-        case 0xAA:
-        case 0xAB:
-        case 0xAC:
-        case 0xAD:
-        case 0xAE:
-        case 0xAF:
-        case 0xB0:
-        case 0xB1:
-        case 0xB2:
-        case 0xB3:
-        case 0xB4:
-        case 0xB5:
-        case 0xB6:
-        case 0xB7:
-        case 0xB8:
-        case 0xB9:
-        case 0xBA:
-        case 0xBB:
-        case 0xBC:
-        case 0xBD:
-        case 0xBE:
-        case 0xBF:
-        {
-            return get_string(current & 0x1F);
-        }
-
-        case 0xD9: // str 8
-        {
-            return get_string(get_number<uint8_t>());
-        }
-
-        case 0xDA: // str 16
-        {
-            return get_string(get_number<uint16_t>());
-        }
-
-        case 0xDB: // str 32
-        {
-            return get_string(get_number<uint32_t>());
-        }
-
-        default:
-        {
-            JSON_THROW(parse_error::create(113, chars_read,
-                fmt::format("expected a MessagePack string; last byte: {:#02x}", current)));
-        }
-    }
-}
-
-std::string json::binary_reader::get_ubjson_string(const bool get_char)
-{
-    if (get_char)
-    {
-        get();  // TODO: may we ignore N here?
-    }
-
-    unexpect_eof();
-
-    switch (current)
-    {
-        case 'U':
-            return get_string(get_number<uint8_t>());
-        case 'i':
-            return get_string(get_number<int8_t>());
-        case 'I':
-            return get_string(get_number<int16_t>());
-        case 'l':
-            return get_string(get_number<int32_t>());
-        case 'L':
-            return get_string(get_number<int64_t>());
-        default:
-            JSON_THROW(parse_error::create(113, chars_read,
-                fmt::format("expected a UBJSON string; last byte: {:#02x}", current)));
-    }
-}
-
-std::pair<std::size_t, int> json::binary_reader::get_ubjson_size_type()
-{
-    std::size_t sz = std::string::npos;
-    int tc = 0;
-
-    get_ignore_noop();
-
-    if (current == '$')
-    {
-        tc = get();  // must not ignore 'N', because 'N' maybe the type
-        unexpect_eof();
-
-        get_ignore_noop();
-        if (current != '#')
-        {
-            JSON_THROW(parse_error::create(112, chars_read,
-                fmt::format("expected '#' after UBJSON type information; last byte: {:#02x}", current)));
-        }
-        sz = parse_ubjson_internal();
-    }
-    else if (current == '#')
-    {
-        sz = parse_ubjson_internal();
-    }
-
-    return std::make_pair(sz, tc);
-}
-
-json json::binary_reader::get_ubjson_value(const int prefix)
-{
-    switch (prefix)
-    {
-        case std::char_traits<char>::eof():  // EOF
-            JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
-
-        case 'T':  // true
-            return true;
-        case 'F':  // false
-            return false;
-
-        case 'Z':  // null
-            return nullptr;
-
-        case 'U':
-            return get_number<uint8_t>();
-        case 'i':
-            return get_number<int8_t>();
-        case 'I':
-            return get_number<int16_t>();
-        case 'l':
-            return get_number<int32_t>();
-        case 'L':
-            return get_number<int64_t>();
-        case 'd':
-            return get_number<float>();
-        case 'D':
-            return get_number<double>();
-
-        case 'C':  // char
-        {
-            get();
-            unexpect_eof();
-            if (JSON_UNLIKELY(current > 127))
-            {
-                JSON_THROW(parse_error::create(113, chars_read,
-                    fmt::format("byte after 'C' must be in range 0x00..0x7F; last byte: {:#02x}", current)));
-            }
-            return std::string(1, static_cast<char>(current));
-        }
-
-        case 'S':  // string
-            return get_ubjson_string();
-
-        case '[':  // array
-            return get_ubjson_array();
-
-        case '{':  // object
-            return get_ubjson_object();
-
-        default: // anything else
-            JSON_THROW(parse_error::create(112, chars_read,
-                fmt::format("error reading UBJSON; last byte: {:#02x}", current)));
-    }
-}
-
-json json::binary_reader::get_ubjson_array()
-{
-    json result = value_t::array;
-    const auto size_and_type = get_ubjson_size_type();
-
-    if (size_and_type.first != std::string::npos)
-    {
-        if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
-        {
-            JSON_THROW(out_of_range::create(408,
-                fmt::format("excessive array size: {}", size_and_type.first)));
-        }
-
-        if (size_and_type.second != 0)
-        {
-            if (size_and_type.second != 'N')
-            {
-                std::generate_n(std::back_inserter(*result.m_value.array),
-                                size_and_type.first, [this, size_and_type]()
-                {
-                    return get_ubjson_value(size_and_type.second);
-                });
-            }
-        }
-        else
-        {
-            std::generate_n(std::back_inserter(*result.m_value.array),
-                            size_and_type.first, [this]()
-            {
-                return parse_ubjson_internal();
-            });
-        }
-    }
-    else
-    {
-        while (current != ']')
-        {
-            result.push_back(parse_ubjson_internal(false));
-            get_ignore_noop();
-        }
-    }
-
-    return result;
-}
-
-json json::binary_reader::get_ubjson_object()
-{
-    json result = value_t::object;
-    const auto size_and_type = get_ubjson_size_type();
-
-    if (size_and_type.first != std::string::npos)
-    {
-        if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
-        {
-            JSON_THROW(out_of_range::create(408,
-                fmt::format("excessive object size: {}", size_and_type.first)));
-        }
-
-        if (size_and_type.second != 0)
-        {
-            for (size_t i = 0; i < size_and_type.first; ++i)
-            {
-                auto key = get_ubjson_string();
-                (*result.m_value.object)[key] = get_ubjson_value(size_and_type.second);
-            }
-        }
-        else
-        {
-            for (size_t i = 0; i < size_and_type.first; ++i)
-            {
-                auto key = get_ubjson_string();
-                (*result.m_value.object)[key] = parse_ubjson_internal();
-            }
-        }
-    }
-    else
-    {
-        while (current != '}')
-        {
-            auto key = get_ubjson_string(false);
-            result[std::move(key)] = parse_ubjson_internal();
-            get_ignore_noop();
-        }
-    }
-
-    return result;
-}
-
-json json::from_cbor(raw_istream& is, const bool strict)
-{
-    return binary_reader(is).parse_cbor(strict);
-}
-
-json json::from_cbor(std::span<const uint8_t> arr, const bool strict)
-{
-    raw_mem_istream is(arr);
-    return from_cbor(is, strict);
-}
-
-json json::from_msgpack(raw_istream& is, const bool strict)
-{
-    return binary_reader(is).parse_msgpack(strict);
-}
-
-json json::from_msgpack(std::span<const uint8_t> arr, const bool strict)
-{
-    raw_mem_istream is(arr);
-    return from_msgpack(is, strict);
-}
-
-json json::from_ubjson(raw_istream& is, const bool strict)
-{
-    return binary_reader(is).parse_ubjson(strict);
-}
-
-json json::from_ubjson(std::span<const uint8_t> arr, const bool strict)
-{
-    raw_mem_istream is(arr);
-    return from_ubjson(is, strict);
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
deleted file mode 100644
index e25d478..0000000
--- a/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
+++ /dev/null
@@ -1,1091 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#define WPI_JSON_IMPLEMENTATION
-#include "wpi/json.h"
-
-#include "fmt/format.h"
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-/*!
-@brief serialization to CBOR and MessagePack values
-*/
-class json::binary_writer
-{
-    using CharType = unsigned char;
-
-  public:
-    /*!
-    @brief create a binary writer
-
-    @param[in] adapter  output adapter to write to
-    */
-    explicit binary_writer(raw_ostream& s) : o(s)
-    {
-    }
-
-    /*!
-    @brief[in] j  JSON value to serialize
-    */
-    void write_cbor(const json& j);
-
-    /*!
-    @brief[in] j  JSON value to serialize
-    */
-    void write_msgpack(const json& j);
-
-    /*!
-    @param[in] j  JSON value to serialize
-    @param[in] use_count   whether to use '#' prefixes (optimized format)
-    @param[in] use_type    whether to use '$' prefixes (optimized format)
-    @param[in] add_prefix  whether prefixes need to be used for this value
-    */
-    void write_ubjson(const json& j, const bool use_count,
-                      const bool use_type, const bool add_prefix = true);
-
-  private:
-    void write_cbor_string(std::string_view str);
-
-    void write_msgpack_string(std::string_view str);
-
-    /*
-    @brief write a number to output input
-
-    @param[in] n number of type @a NumberType
-    @tparam NumberType the type of the number
-
-    @note This function needs to respect the system's endianess, because bytes
-          in CBOR, MessagePack, and UBJSON are stored in network order (big
-          endian) and therefore need reordering on little endian systems.
-    */
-    template<typename NumberType>
-    void write_number(const NumberType n);
-
-    // UBJSON: write number (floating point)
-    template<typename NumberType, typename std::enable_if<
-                 std::is_floating_point<NumberType>::value, int>::type = 0>
-    void write_number_with_ubjson_prefix(const NumberType n,
-                                         const bool add_prefix)
-    {
-        if (add_prefix)
-        {
-            o << get_ubjson_float_prefix(n);
-        }
-        write_number(n);
-    }
-
-    // UBJSON: write number (unsigned integer)
-    template<typename NumberType, typename std::enable_if<
-                 std::is_unsigned<NumberType>::value, int>::type = 0>
-    void write_number_with_ubjson_prefix(const NumberType n,
-                                         const bool add_prefix);
-
-    // UBJSON: write number (signed integer)
-    template<typename NumberType, typename std::enable_if<
-                 std::is_signed<NumberType>::value and
-                 not std::is_floating_point<NumberType>::value, int>::type = 0>
-    void write_number_with_ubjson_prefix(const NumberType n,
-                                         const bool add_prefix);
-
-    /*!
-    @brief determine the type prefix of container values
-
-    @note This function does not need to be 100% accurate when it comes to
-          integer limits. In case a number exceeds the limits of int64_t,
-          this will be detected by a later call to function
-          write_number_with_ubjson_prefix. Therefore, we return 'L' for any
-          value that does not fit the previous limits.
-    */
-    CharType ubjson_prefix(const json& j) const noexcept;
-
-    static constexpr CharType get_cbor_float_prefix(float)
-    {
-        return static_cast<CharType>(0xFA);  // Single-Precision Float
-    }
-
-    static constexpr CharType get_cbor_float_prefix(double)
-    {
-        return static_cast<CharType>(0xFB);  // Double-Precision Float
-    }
-
-    static constexpr CharType get_msgpack_float_prefix(float)
-    {
-        return static_cast<CharType>(0xCA);  // float 32
-    }
-
-    static constexpr CharType get_msgpack_float_prefix(double)
-    {
-        return static_cast<CharType>(0xCB);  // float 64
-    }
-
-    static constexpr CharType get_ubjson_float_prefix(float)
-    {
-        return 'd';  // float 32
-    }
-
-    static constexpr CharType get_ubjson_float_prefix(double)
-    {
-        return 'D';  // float 64
-    }
-
-  private:
-    static bool little_endianess(int num = 1) noexcept
-    {
-        return (*reinterpret_cast<char*>(&num) == 1);
-    }
-
-    /// whether we can assume little endianess
-    const bool is_little_endian = little_endianess();
-
-    /// the output
-    raw_ostream& o;
-};
-
-void json::binary_writer::write_cbor(const json& j)
-{
-    switch (j.type())
-    {
-        case value_t::null:
-        {
-            o << static_cast<CharType>(0xF6);
-            break;
-        }
-
-        case value_t::boolean:
-        {
-            o << static_cast<CharType>(j.m_value.boolean ? 0xF5 : 0xF4);
-            break;
-        }
-
-        case value_t::number_integer:
-        {
-            if (j.m_value.number_integer >= 0)
-            {
-                // CBOR does not differentiate between positive signed
-                // integers and unsigned integers. Therefore, we used the
-                // code from the value_t::number_unsigned case here.
-                if (j.m_value.number_integer <= 0x17)
-                {
-                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
-                {
-                    o << static_cast<CharType>(0x18);
-                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
-                {
-                    o << static_cast<CharType>(0x19);
-                    write_number(static_cast<uint16_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
-                {
-                    o << static_cast<CharType>(0x1A);
-                    write_number(static_cast<uint32_t>(j.m_value.number_integer));
-                }
-                else
-                {
-                    o << static_cast<CharType>(0x1B);
-                    write_number(static_cast<uint64_t>(j.m_value.number_integer));
-                }
-            }
-            else
-            {
-                // The conversions below encode the sign in the first
-                // byte, and the value is converted to a positive number.
-                const auto positive_number = -1 - j.m_value.number_integer;
-                if (j.m_value.number_integer >= -24)
-                {
-                    write_number(static_cast<uint8_t>(0x20 + positive_number));
-                }
-                else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
-                {
-                    o << static_cast<CharType>(0x38);
-                    write_number(static_cast<uint8_t>(positive_number));
-                }
-                else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
-                {
-                    o << static_cast<CharType>(0x39);
-                    write_number(static_cast<uint16_t>(positive_number));
-                }
-                else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
-                {
-                    o << static_cast<CharType>(0x3A);
-                    write_number(static_cast<uint32_t>(positive_number));
-                }
-                else
-                {
-                    o << static_cast<CharType>(0x3B);
-                    write_number(static_cast<uint64_t>(positive_number));
-                }
-            }
-            break;
-        }
-
-        case value_t::number_unsigned:
-        {
-            if (j.m_value.number_unsigned <= 0x17)
-            {
-                write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
-            {
-                o << static_cast<CharType>(0x18);
-                write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
-            {
-                o << static_cast<CharType>(0x19);
-                write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
-            {
-                o << static_cast<CharType>(0x1A);
-                write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
-            }
-            else
-            {
-                o << static_cast<CharType>(0x1B);
-                write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
-            }
-            break;
-        }
-
-        case value_t::number_float:
-        {
-            o << get_cbor_float_prefix(j.m_value.number_float);
-            write_number(j.m_value.number_float);
-            break;
-        }
-
-        case value_t::string:
-        {
-            write_cbor_string(*j.m_value.string);
-            break;
-        }
-
-        case value_t::array:
-        {
-            // step 1: write control byte and the array size
-            const auto N = j.m_value.array->size();
-            if (N <= 0x17)
-            {
-                write_number(static_cast<uint8_t>(0x80 + N));
-            }
-            else if (N <= (std::numeric_limits<uint8_t>::max)())
-            {
-                o << static_cast<CharType>(0x98);
-                write_number(static_cast<uint8_t>(N));
-            }
-            else if (N <= (std::numeric_limits<uint16_t>::max)())
-            {
-                o << static_cast<CharType>(0x99);
-                write_number(static_cast<uint16_t>(N));
-            }
-            else if (N <= (std::numeric_limits<uint32_t>::max)())
-            {
-                o << static_cast<CharType>(0x9A);
-                write_number(static_cast<uint32_t>(N));
-            }
-            // LCOV_EXCL_START
-            else if (N <= (std::numeric_limits<uint64_t>::max)())
-            {
-                o << static_cast<CharType>(0x9B);
-                write_number(static_cast<uint64_t>(N));
-            }
-            // LCOV_EXCL_STOP
-
-            // step 2: write each element
-            for (const auto& el : *j.m_value.array)
-            {
-                write_cbor(el);
-            }
-            break;
-        }
-
-        case value_t::object:
-        {
-            // step 1: write control byte and the object size
-            const auto N = j.m_value.object->size();
-            if (N <= 0x17)
-            {
-                write_number(static_cast<uint8_t>(0xA0 + N));
-            }
-            else if (N <= (std::numeric_limits<uint8_t>::max)())
-            {
-                o << static_cast<CharType>(0xB8);
-                write_number(static_cast<uint8_t>(N));
-            }
-            else if (N <= (std::numeric_limits<uint16_t>::max)())
-            {
-                o << static_cast<CharType>(0xB9);
-                write_number(static_cast<uint16_t>(N));
-            }
-            else if (N <= (std::numeric_limits<uint32_t>::max)())
-            {
-                o << static_cast<CharType>(0xBA);
-                write_number(static_cast<uint32_t>(N));
-            }
-            // LCOV_EXCL_START
-            else /*if (N <= (std::numeric_limits<uint64_t>::max)())*/
-            {
-                o << static_cast<CharType>(0xBB);
-                write_number(static_cast<uint64_t>(N));
-            }
-            // LCOV_EXCL_STOP
-
-            // step 2: write each element
-            for (const auto& el : *j.m_value.object)
-            {
-                write_cbor_string(el.first());
-                write_cbor(el.second);
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-}
-
-void json::binary_writer::write_msgpack(const json& j)
-{
-    switch (j.type())
-    {
-        case value_t::null: // nil
-        {
-            o << static_cast<CharType>(0xC0);
-            break;
-        }
-
-        case value_t::boolean: // true and false
-        {
-            o << static_cast<CharType>(j.m_value.boolean ? 0xC3 : 0xC2);
-            break;
-        }
-
-        case value_t::number_integer:
-        {
-            if (j.m_value.number_integer >= 0)
-            {
-                // MessagePack does not differentiate between positive
-                // signed integers and unsigned integers. Therefore, we used
-                // the code from the value_t::number_unsigned case here.
-                if (j.m_value.number_unsigned < 128)
-                {
-                    // positive fixnum
-                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
-                {
-                    // uint 8
-                    o << static_cast<CharType>(0xCC);
-                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
-                {
-                    // uint 16
-                    o << static_cast<CharType>(0xCD);
-                    write_number(static_cast<uint16_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
-                {
-                    // uint 32
-                    o << static_cast<CharType>(0xCE);
-                    write_number(static_cast<uint32_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
-                {
-                    // uint 64
-                    o << static_cast<CharType>(0xCF);
-                    write_number(static_cast<uint64_t>(j.m_value.number_integer));
-                }
-            }
-            else
-            {
-                if (j.m_value.number_integer >= -32)
-                {
-                    // negative fixnum
-                    write_number(static_cast<int8_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and
-                         j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
-                {
-                    // int 8
-                    o << static_cast<CharType>(0xD0);
-                    write_number(static_cast<int8_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
-                         j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
-                {
-                    // int 16
-                    o << static_cast<CharType>(0xD1);
-                    write_number(static_cast<int16_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
-                         j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
-                {
-                    // int 32
-                    o << static_cast<CharType>(0xD2);
-                    write_number(static_cast<int32_t>(j.m_value.number_integer));
-                }
-                else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
-                         j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
-                {
-                    // int 64
-                    o << static_cast<CharType>(0xD3);
-                    write_number(static_cast<int64_t>(j.m_value.number_integer));
-                }
-            }
-            break;
-        }
-
-        case value_t::number_unsigned:
-        {
-            if (j.m_value.number_unsigned < 128)
-            {
-                // positive fixnum
-                write_number(static_cast<uint8_t>(j.m_value.number_integer));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
-            {
-                // uint 8
-                o << static_cast<CharType>(0xCC);
-                write_number(static_cast<uint8_t>(j.m_value.number_integer));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
-            {
-                // uint 16
-                o << static_cast<CharType>(0xCD);
-                write_number(static_cast<uint16_t>(j.m_value.number_integer));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
-            {
-                // uint 32
-                o << static_cast<CharType>(0xCE);
-                write_number(static_cast<uint32_t>(j.m_value.number_integer));
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
-            {
-                // uint 64
-                o << static_cast<CharType>(0xCF);
-                write_number(static_cast<uint64_t>(j.m_value.number_integer));
-            }
-            break;
-        }
-
-        case value_t::number_float:
-        {
-            o << get_msgpack_float_prefix(j.m_value.number_float);
-            write_number(j.m_value.number_float);
-            break;
-        }
-
-        case value_t::string:
-        {
-            write_msgpack_string(*j.m_value.string);
-            break;
-        }
-
-        case value_t::array:
-        {
-            // step 1: write control byte and the array size
-            const auto N = j.m_value.array->size();
-            if (N <= 15)
-            {
-                // fixarray
-                write_number(static_cast<uint8_t>(0x90 | N));
-            }
-            else if (N <= (std::numeric_limits<uint16_t>::max)())
-            {
-                // array 16
-                o << static_cast<CharType>(0xDC);
-                write_number(static_cast<uint16_t>(N));
-            }
-            else if (N <= (std::numeric_limits<uint32_t>::max)())
-            {
-                // array 32
-                o << static_cast<CharType>(0xDD);
-                write_number(static_cast<uint32_t>(N));
-            }
-
-            // step 2: write each element
-            for (const auto& el : *j.m_value.array)
-            {
-                write_msgpack(el);
-            }
-            break;
-        }
-
-        case value_t::object:
-        {
-            // step 1: write control byte and the object size
-            const auto N = j.m_value.object->size();
-            if (N <= 15)
-            {
-                // fixmap
-                write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));
-            }
-            else if (N <= (std::numeric_limits<uint16_t>::max)())
-            {
-                // map 16
-                o << static_cast<CharType>(0xDE);
-                write_number(static_cast<uint16_t>(N));
-            }
-            else if (N <= (std::numeric_limits<uint32_t>::max)())
-            {
-                // map 32
-                o << static_cast<CharType>(0xDF);
-                write_number(static_cast<uint32_t>(N));
-            }
-
-            // step 2: write each element
-            for (const auto& el : *j.m_value.object)
-            {
-                write_msgpack_string(el.first());
-                write_msgpack(el.second);
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-}
-
-void json::binary_writer::write_ubjson(const json& j, const bool use_count,
-                  const bool use_type, const bool add_prefix)
-{
-    switch (j.type())
-    {
-        case value_t::null:
-        {
-            if (add_prefix)
-            {
-                o << static_cast<CharType>('Z');
-            }
-            break;
-        }
-
-        case value_t::boolean:
-        {
-            if (add_prefix)
-                o << static_cast<CharType>(j.m_value.boolean ? 'T' : 'F');
-            break;
-        }
-
-        case value_t::number_integer:
-        {
-            write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
-            break;
-        }
-
-        case value_t::number_unsigned:
-        {
-            write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
-            break;
-        }
-
-        case value_t::number_float:
-        {
-            write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
-            break;
-        }
-
-        case value_t::string:
-        {
-            if (add_prefix)
-            {
-                o << static_cast<CharType>('S');
-            }
-            write_number_with_ubjson_prefix(j.m_value.string->size(), true);
-            o << *j.m_value.string;
-            break;
-        }
-
-        case value_t::array:
-        {
-            if (add_prefix)
-            {
-                o << static_cast<CharType>('[');
-            }
-
-            bool prefix_required = true;
-            if (use_type and not j.m_value.array->empty())
-            {
-                assert(use_count);
-                const CharType first_prefix = ubjson_prefix(j.front());
-                const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
-                                                     [this, first_prefix](const json & v)
-                {
-                    return ubjson_prefix(v) == first_prefix;
-                });
-
-                if (same_prefix)
-                {
-                    prefix_required = false;
-                    o << static_cast<CharType>('$');
-                    o << first_prefix;
-                }
-            }
-
-            if (use_count)
-            {
-                o << static_cast<CharType>('#');
-                write_number_with_ubjson_prefix(j.m_value.array->size(), true);
-            }
-
-            for (const auto& el : *j.m_value.array)
-            {
-                write_ubjson(el, use_count, use_type, prefix_required);
-            }
-
-            if (not use_count)
-            {
-                o << static_cast<CharType>(']');
-            }
-
-            break;
-        }
-
-        case value_t::object:
-        {
-            if (add_prefix)
-            {
-                o << static_cast<CharType>('{');
-            }
-
-            bool prefix_required = true;
-            if (use_type and not j.m_value.object->empty())
-            {
-                assert(use_count);
-                const CharType first_prefix = ubjson_prefix(j.front());
-                const bool same_prefix = std::all_of(j.begin(), j.end(),
-                                                     [this, first_prefix](const json & v)
-                {
-                    return ubjson_prefix(v) == first_prefix;
-                });
-
-                if (same_prefix)
-                {
-                    prefix_required = false;
-                    o << static_cast<CharType>('$');
-                    o << first_prefix;
-                }
-            }
-
-            if (use_count)
-            {
-                o << static_cast<CharType>('#');
-                write_number_with_ubjson_prefix(j.m_value.object->size(), true);
-            }
-
-            for (const auto& el : *j.m_value.object)
-            {
-                write_number_with_ubjson_prefix(el.first().size(), true);
-                o << el.first();
-                write_ubjson(el.second, use_count, use_type, prefix_required);
-            }
-
-            if (not use_count)
-            {
-                o << static_cast<CharType>('}');
-            }
-
-            break;
-        }
-
-        default:
-            break;
-    }
-}
-
-void json::binary_writer::write_cbor_string(std::string_view str)
-{
-    // step 1: write control byte and the string length
-    const auto N = str.size();
-    if (N <= 0x17)
-    {
-        write_number(static_cast<uint8_t>(0x60 + N));
-    }
-    else if (N <= (std::numeric_limits<uint8_t>::max)())
-    {
-        o << static_cast<CharType>(0x78);
-        write_number(static_cast<uint8_t>(N));
-    }
-    else if (N <= (std::numeric_limits<uint16_t>::max)())
-    {
-        o << static_cast<CharType>(0x79);
-        write_number(static_cast<uint16_t>(N));
-    }
-    else if (N <= (std::numeric_limits<uint32_t>::max)())
-    {
-        o << static_cast<CharType>(0x7A);
-        write_number(static_cast<uint32_t>(N));
-    }
-    // LCOV_EXCL_START
-    else if (N <= (std::numeric_limits<uint64_t>::max)())
-    {
-        o << static_cast<CharType>(0x7B);
-        write_number(static_cast<uint64_t>(N));
-    }
-    // LCOV_EXCL_STOP
-
-    // step 2: write the string
-    o << str;
-}
-
-void json::binary_writer::write_msgpack_string(std::string_view str)
-{
-    // step 1: write control byte and the string length
-    const auto N = str.size();
-    if (N <= 31)
-    {
-        // fixstr
-        write_number(static_cast<uint8_t>(0xA0 | N));
-    }
-    else if (N <= (std::numeric_limits<uint8_t>::max)())
-    {
-        // str 8
-        o << static_cast<CharType>(0xD9);
-        write_number(static_cast<uint8_t>(N));
-    }
-    else if (N <= (std::numeric_limits<uint16_t>::max)())
-    {
-        // str 16
-        o << static_cast<CharType>(0xDA);
-        write_number(static_cast<uint16_t>(N));
-    }
-    else if (N <= (std::numeric_limits<uint32_t>::max)())
-    {
-        // str 32
-        o << static_cast<CharType>(0xDB);
-        write_number(static_cast<uint32_t>(N));
-    }
-
-    // step 2: write the string
-    o << str;
-}
-
-template<typename NumberType>
-void json::binary_writer::write_number(const NumberType n)
-{
-    // step 1: write number to array of length NumberType
-    std::array<uint8_t, sizeof(NumberType)> vec;
-    std::memcpy(vec.data(), &n, sizeof(NumberType));
-
-    // step 2: write array to output (with possible reordering)
-    if (is_little_endian)
-    {
-        // reverse byte order prior to conversion if necessary
-        std::reverse(vec.begin(), vec.end());
-    }
-
-    o << std::span{vec.data(), sizeof(NumberType)};
-}
-
-template<typename NumberType, typename std::enable_if<
-             std::is_unsigned<NumberType>::value, int>::type>
-void json::binary_writer::write_number_with_ubjson_prefix(const NumberType n,
-                                     const bool add_prefix)
-{
-    if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('i');  // int8
-        }
-        write_number(static_cast<uint8_t>(n));
-    }
-    else if (n <= (std::numeric_limits<uint8_t>::max)())
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('U');  // uint8
-        }
-        write_number(static_cast<uint8_t>(n));
-    }
-    else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('I');  // int16
-        }
-        write_number(static_cast<int16_t>(n));
-    }
-    else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('l');  // int32
-        }
-        write_number(static_cast<int32_t>(n));
-    }
-    else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('L');  // int64
-        }
-        write_number(static_cast<int64_t>(n));
-    }
-    else
-    {
-        JSON_THROW(out_of_range::create(407, fmt::format("number overflow serializing {}", n)));
-    }
-}
-
-template<typename NumberType, typename std::enable_if<
-             std::is_signed<NumberType>::value and
-             not std::is_floating_point<NumberType>::value, int>::type>
-void json::binary_writer::write_number_with_ubjson_prefix(const NumberType n,
-                                     const bool add_prefix)
-{
-    if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('i');  // int8
-        }
-        write_number(static_cast<int8_t>(n));
-    }
-    else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('U');  // uint8
-        }
-        write_number(static_cast<uint8_t>(n));
-    }
-    else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('I');  // int16
-        }
-        write_number(static_cast<int16_t>(n));
-    }
-    else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('l');  // int32
-        }
-        write_number(static_cast<int32_t>(n));
-    }
-    else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
-    {
-        if (add_prefix)
-        {
-            o << static_cast<CharType>('L');  // int64
-        }
-        write_number(static_cast<int64_t>(n));
-    }
-    // LCOV_EXCL_START
-    else
-    {
-        JSON_THROW(out_of_range::create(407, fmt::format("number overflow serializing {}", n)));
-    }
-    // LCOV_EXCL_STOP
-}
-
-json::binary_writer::CharType json::binary_writer::ubjson_prefix(const json& j) const noexcept
-{
-    switch (j.type())
-    {
-        case value_t::null:
-            return 'Z';
-
-        case value_t::boolean:
-            return j.m_value.boolean ? 'T' : 'F';
-
-        case value_t::number_integer:
-        {
-            if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
-            {
-                return 'i';
-            }
-            else if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
-            {
-                return 'U';
-            }
-            else if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
-            {
-                return 'I';
-            }
-            else if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
-            {
-                return 'l';
-            }
-            else  // no check and assume int64_t (see note above)
-            {
-                return 'L';
-            }
-        }
-
-        case value_t::number_unsigned:
-        {
-            if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
-            {
-                return 'i';
-            }
-            else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
-            {
-                return 'U';
-            }
-            else if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
-            {
-                return 'I';
-            }
-            else if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
-            {
-                return 'l';
-            }
-            else  // no check and assume int64_t (see note above)
-            {
-                return 'L';
-            }
-        }
-
-        case value_t::number_float:
-            return get_ubjson_float_prefix(j.m_value.number_float);
-
-        case value_t::string:
-            return 'S';
-
-        case value_t::array:
-            return '[';
-
-        case value_t::object:
-            return '{';
-
-        default:  // discarded values
-            return 'N';
-    }
-}
-
-std::vector<uint8_t> json::to_cbor(const json& j)
-{
-    std::vector<uint8_t> result;
-    raw_uvector_ostream os(result);
-    to_cbor(os, j);
-    return result;
-}
-
-std::span<uint8_t> json::to_cbor(const json& j, std::vector<uint8_t>& buf)
-{
-    buf.clear();
-    raw_uvector_ostream os(buf);
-    to_cbor(os, j);
-    return os.array();
-}
-
-std::span<uint8_t> json::to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf)
-{
-    buf.clear();
-    raw_usvector_ostream os(buf);
-    to_cbor(os, j);
-    return os.array();
-}
-
-void json::to_cbor(raw_ostream& os, const json& j)
-{
-    binary_writer(os).write_cbor(j);
-}
-
-std::vector<uint8_t> json::to_msgpack(const json& j)
-{
-    std::vector<uint8_t> result;
-    raw_uvector_ostream os(result);
-    to_msgpack(os, j);
-    return result;
-}
-
-std::span<uint8_t> json::to_msgpack(const json& j, std::vector<uint8_t>& buf)
-{
-    buf.clear();
-    raw_uvector_ostream os(buf);
-    to_msgpack(os, j);
-    return os.array();
-}
-
-std::span<uint8_t> json::to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf)
-{
-    buf.clear();
-    raw_usvector_ostream os(buf);
-    to_msgpack(os, j);
-    return os.array();
-}
-
-void json::to_msgpack(raw_ostream& os, const json& j)
-{
-    binary_writer(os).write_msgpack(j);
-}
-
-std::vector<uint8_t> json::to_ubjson(const json& j,
-                                     const bool use_size,
-                                     const bool use_type)
-{
-    std::vector<uint8_t> result;
-    raw_uvector_ostream os(result);
-    to_ubjson(os, j, use_size, use_type);
-    return result;
-}
-
-std::span<uint8_t> json::to_ubjson(const json& j, std::vector<uint8_t>& buf,
-                              const bool use_size, const bool use_type)
-{
-    buf.clear();
-    raw_uvector_ostream os(buf);
-    to_ubjson(os, j, use_size, use_type);
-    return os.array();
-}
-
-std::span<uint8_t> json::to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
-                              const bool use_size, const bool use_type)
-{
-    buf.clear();
-    raw_usvector_ostream os(buf);
-    to_ubjson(os, j, use_size, use_type);
-    return os.array();
-}
-
-void json::to_ubjson(raw_ostream& os, const json& j,
-                     const bool use_size, const bool use_type)
-{
-    binary_writer(os).write_ubjson(j, use_size, use_type);
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
deleted file mode 100644
index 3c29489..0000000
--- a/wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
+++ /dev/null
@@ -1,1968 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#define WPI_JSON_IMPLEMENTATION
-#include "wpi/json.h"
-
-#include <clocale>
-#include <cmath>
-#include <cstdlib>
-
-#include "fmt/format.h"
-#include "wpi/SmallString.h"
-#include "wpi/raw_istream.h"
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-/*!
-@brief lexical analysis
-
-This class organizes the lexical analysis during JSON deserialization.
-*/
-class json::lexer
-{
-  public:
-    /// token types for the parser
-    enum class token_type
-    {
-        uninitialized,    ///< indicating the scanner is uninitialized
-        literal_true,     ///< the `true` literal
-        literal_false,    ///< the `false` literal
-        literal_null,     ///< the `null` literal
-        value_string,     ///< a string -- use get_string() for actual value
-        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value
-        value_integer,    ///< a signed integer -- use get_number_integer() for actual value
-        value_float,      ///< an floating point number -- use get_number_float() for actual value
-        begin_array,      ///< the character for array begin `[`
-        begin_object,     ///< the character for object begin `{`
-        end_array,        ///< the character for array end `]`
-        end_object,       ///< the character for object end `}`
-        name_separator,   ///< the name separator `:`
-        value_separator,  ///< the value separator `,`
-        parse_error,      ///< indicating a parse error
-        end_of_input,     ///< indicating the end of the input buffer
-        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)
-    };
-
-    /// return name of values of type token_type (only used for errors)
-    static const char* token_type_name(const token_type t) noexcept;
-
-    explicit lexer(raw_istream& s);
-
-    // delete because of pointer members
-    lexer(const lexer&) = delete;
-    lexer& operator=(lexer&) = delete;
-
-  private:
-    /////////////////////
-    // locales
-    /////////////////////
-
-    /// return the locale-dependent decimal point
-    static char get_decimal_point() noexcept
-    {
-        const auto loc = localeconv();
-        assert(loc != nullptr);
-        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
-    }
-
-    /////////////////////
-    // scan functions
-    /////////////////////
-
-    /*!
-    @brief get codepoint from 4 hex characters following `\u`
-
-    For input "\u c1 c2 c3 c4" the codepoint is:
-      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
-    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
-
-    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
-    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
-    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
-    between the ASCII value of the character and the desired integer value.
-
-    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
-            non-hex character)
-    */
-    int get_codepoint();
-
-    /*!
-    @brief check if the next byte(s) are inside a given range
-
-    Adds the current byte and, for each passed range, reads a new byte and
-    checks if it is inside the range. If a violation was detected, set up an
-    error message and return false. Otherwise, return true.
-
-    @param[in] ranges  list of integers; interpreted as list of pairs of
-                       inclusive lower and upper bound, respectively
-
-    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
-         1, 2, or 3 pairs. This precondition is enforced by an assertion.
-
-    @return true if and only if no range violation was detected
-    */
-    bool next_byte_in_range(std::initializer_list<int> ranges)
-    {
-        assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);
-        add(current);
-
-        for (auto range = ranges.begin(); range != ranges.end(); ++range)
-        {
-            get();
-            if (JSON_LIKELY(*range <= current and current <= *(++range)))
-            {
-                add(current);
-            }
-            else
-            {
-                error_message = "invalid string: ill-formed UTF-8 byte";
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /*!
-    @brief scan a string literal
-
-    This function scans a string according to Sect. 7 of RFC 7159. While
-    scanning, bytes are escaped and copied into buffer token_buffer. Then the
-    function returns successfully, token_buffer is *not* null-terminated (as it
-    may contain \0 bytes), and token_buffer.size() is the number of bytes in the
-    string.
-
-    @return token_type::value_string if string could be successfully scanned,
-            token_type::parse_error otherwise
-
-    @note In case of errors, variable error_message contains a textual
-          description.
-    */
-    token_type scan_string();
-
-    static void strtof(float& f, const char* str, char** endptr) noexcept
-    {
-        f = std::strtof(str, endptr);
-    }
-
-    static void strtof(double& f, const char* str, char** endptr) noexcept
-    {
-        f = std::strtod(str, endptr);
-    }
-
-    static void strtof(long double& f, const char* str, char** endptr) noexcept
-    {
-        f = std::strtold(str, endptr);
-    }
-
-    /*!
-    @brief scan a number literal
-
-    This function scans a string according to Sect. 6 of RFC 7159.
-
-    The function is realized with a deterministic finite state machine derived
-    from the grammar described in RFC 7159. Starting in state "init", the
-    input is read and used to determined the next state. Only state "done"
-    accepts the number. State "error" is a trap state to model errors. In the
-    table below, "anything" means any character but the ones listed before.
-
-    state    | 0        | 1-9      | e E      | +       | -       | .        | anything
-    ---------|----------|----------|----------|---------|---------|----------|-----------
-    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]
-    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]
-    zero     | done     | done     | exponent | done    | done    | decimal1 | done
-    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done
-    decimal1 | decimal2 | [error]  | [error]  | [error] | [error] | [error]  | [error]
-    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done
-    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]
-    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]
-    any2     | any2     | any2     | done     | done    | done    | done     | done
-
-    The state machine is realized with one label per state (prefixed with
-    "scan_number_") and `goto` statements between them. The state machine
-    contains cycles, but any cycle can be left when EOF is read. Therefore,
-    the function is guaranteed to terminate.
-
-    During scanning, the read bytes are stored in token_buffer. This string is
-    then converted to a signed integer, an unsigned integer, or a
-    floating-point number.
-
-    @return token_type::value_unsigned, token_type::value_integer, or
-            token_type::value_float if number could be successfully scanned,
-            token_type::parse_error otherwise
-
-    @note The scanner is independent of the current locale. Internally, the
-          locale's decimal point is used instead of `.` to work with the
-          locale-dependent converters.
-    */
-    token_type scan_number();
-
-    /*!
-    @param[in] literal_text  the literal text to expect
-    @param[in] length        the length of the passed literal text
-    @param[in] return_type   the token type to return on success
-    */
-    token_type scan_literal(const char* literal_text, const std::size_t length,
-                            token_type return_type);
-
-    /////////////////////
-    // input management
-    /////////////////////
-
-    /// reset token_buffer; current character is beginning of token
-    void reset() noexcept
-    {
-        token_buffer.clear();
-        token_string.clear();
-        token_string.push_back(std::char_traits<char>::to_char_type(current));
-    }
-
-    /*
-    @brief get next character from the input
-
-    This function provides the interface to the used input adapter. It does
-    not throw in case the input reached EOF, but returns a
-    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters
-    for use in error messages.
-
-    @return character read from the input
-    */
-    std::char_traits<char>::int_type get()
-    {
-        ++chars_read;
-        if (JSON_UNLIKELY(!unget_chars.empty()))
-        {
-            current = unget_chars.back();
-            unget_chars.pop_back();
-            token_string.push_back(current);
-            return current;
-        }
-        char c;
-        is.read(c);
-        if (JSON_UNLIKELY(is.has_error()))
-        {
-            current = std::char_traits<char>::eof();
-        }
-        else
-        {
-            current = std::char_traits<char>::to_int_type(c);
-            token_string.push_back(c);
-        }
-        return current;
-    }
-
-    /// unget current character (return it again on next get)
-    void unget()
-    {
-        --chars_read;
-        if (JSON_LIKELY(current != std::char_traits<char>::eof()))
-        {
-            unget_chars.emplace_back(current);
-            assert(token_string.size() != 0);
-            token_string.pop_back();
-            if (!token_string.empty())
-            {
-                current = token_string.back();
-            }
-        }
-    }
-
-    /// put back character (returned on next get)
-    void putback(std::char_traits<char>::int_type c)
-    {
-        --chars_read;
-        unget_chars.emplace_back(c);
-    }
-
-    /// add a character to token_buffer
-    void add(int c)
-    {
-        token_buffer.push_back(std::char_traits<char>::to_char_type(c));
-    }
-
-  public:
-    /////////////////////
-    // value getters
-    /////////////////////
-
-    /// return integer value
-    int64_t get_number_integer() const noexcept
-    {
-        return value_integer;
-    }
-
-    /// return unsigned integer value
-    uint64_t get_number_unsigned() const noexcept
-    {
-        return value_unsigned;
-    }
-
-    /// return floating-point value
-    double get_number_float() const noexcept
-    {
-        return value_float;
-    }
-
-    /// return current string value
-    std::string_view get_string()
-    {
-        return token_buffer;
-    }
-
-    /////////////////////
-    // diagnostics
-    /////////////////////
-
-    /// return position of last read token
-    std::size_t get_position() const noexcept
-    {
-        return chars_read;
-    }
-
-    /// return the last read token (for errors only).  Will never contain EOF
-    /// (an arbitrary value that is not a valid char value, often -1), because
-    /// 255 may legitimately occur.  May contain NUL, which should be escaped.
-    std::string get_token_string() const;
-
-    /// return syntax error message
-    const char* get_error_message() const noexcept
-    {
-        return error_message;
-    }
-
-    /////////////////////
-    // actual scanner
-    /////////////////////
-
-    token_type scan();
-
-  private:
-    /// input adapter
-    raw_istream& is;
-
-    /// the current character
-    std::char_traits<char>::int_type current = std::char_traits<char>::eof();
-
-    /// unget characters
-    SmallVector<std::char_traits<char>::int_type, 4> unget_chars;
-
-    /// the number of characters read
-    std::size_t chars_read = 0;
-
-    /// raw input token string (for error messages)
-    SmallString<128> token_string {};
-
-    /// buffer for variable-length tokens (numbers, strings)
-    SmallString<128> token_buffer {};
-
-    /// a description of occurred lexer errors
-    const char* error_message = "";
-
-    // number values
-    int64_t value_integer = 0;
-    uint64_t value_unsigned = 0;
-    double value_float = 0;
-
-    /// the decimal point
-    const char decimal_point_char = '.';
-};
-
-////////////
-// parser //
-////////////
-
-/*!
-@brief syntax analysis
-
-This class implements a recursive decent parser.
-*/
-class json::parser
-{
-    using lexer_t = json::lexer;
-    using token_type = typename lexer_t::token_type;
-
-  public:
-    /// a parser reading from an input adapter
-    explicit parser(raw_istream& s,
-                    const parser_callback_t cb = nullptr,
-                    const bool allow_exceptions_ = true)
-        : callback(cb), m_lexer(s), allow_exceptions(allow_exceptions_)
-    {}
-
-    /*!
-    @brief public parser interface
-
-    @param[in] strict      whether to expect the last token to be EOF
-    @param[in,out] result  parsed JSON value
-
-    @throw parse_error.101 in case of an unexpected token
-    @throw parse_error.102 if to_unicode fails or surrogate error
-    @throw parse_error.103 if to_unicode fails
-    */
-    void parse(const bool strict, json& result);
-
-    /*!
-    @brief public accept interface
-
-    @param[in] strict  whether to expect the last token to be EOF
-    @return whether the input is a proper JSON text
-    */
-    bool accept(const bool strict = true)
-    {
-        // read first token
-        get_token();
-
-        if (not accept_internal())
-        {
-            return false;
-        }
-
-        // strict => last token must be EOF
-        return not strict or (get_token() == token_type::end_of_input);
-    }
-
-  private:
-    /*!
-    @brief the actual parser
-    @throw parse_error.101 in case of an unexpected token
-    @throw parse_error.102 if to_unicode fails or surrogate error
-    @throw parse_error.103 if to_unicode fails
-    */
-    void parse_internal(bool keep, json& result);
-
-    /*!
-    @brief the actual acceptor
-
-    @invariant 1. The last token is not yet processed. Therefore, the caller
-                  of this function must make sure a token has been read.
-               2. When this function returns, the last token is processed.
-                  That is, the last read character was already considered.
-
-    This invariant makes sure that no token needs to be "unput".
-    */
-    bool accept_internal();
-
-    /// get next token from lexer
-    token_type get_token()
-    {
-        return (last_token = m_lexer.scan());
-    }
-
-    /*!
-    @throw parse_error.101 if expected token did not occur
-    */
-    bool expect(token_type t)
-    {
-        if (JSON_UNLIKELY(t != last_token))
-        {
-            errored = true;
-            expected = t;
-            if (allow_exceptions)
-            {
-                throw_exception();
-            }
-            else
-            {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    [[noreturn]] void throw_exception() const;
-
-  private:
-    /// current level of recursion
-    int depth = 0;
-    /// callback function
-    const parser_callback_t callback = nullptr;
-    /// the type of the last read token
-    token_type last_token = token_type::uninitialized;
-    /// the lexer
-    lexer_t m_lexer;
-    /// whether a syntax error occurred
-    bool errored = false;
-    /// possible reason for the syntax error
-    token_type expected = token_type::uninitialized;
-    /// whether to throw exceptions in case of errors
-    const bool allow_exceptions = true;
-};
-
-const char* json::lexer::token_type_name(const token_type t) noexcept
-{
-    switch (t)
-    {
-        case token_type::uninitialized:
-            return "<uninitialized>";
-        case token_type::literal_true:
-            return "true literal";
-        case token_type::literal_false:
-            return "false literal";
-        case token_type::literal_null:
-            return "null literal";
-        case token_type::value_string:
-            return "string literal";
-        case lexer::token_type::value_unsigned:
-        case lexer::token_type::value_integer:
-        case lexer::token_type::value_float:
-            return "number literal";
-        case token_type::begin_array:
-            return "'['";
-        case token_type::begin_object:
-            return "'{'";
-        case token_type::end_array:
-            return "']'";
-        case token_type::end_object:
-            return "'}'";
-        case token_type::name_separator:
-            return "':'";
-        case token_type::value_separator:
-            return "','";
-        case token_type::parse_error:
-            return "<parse error>";
-        case token_type::end_of_input:
-            return "end of input";
-        case token_type::literal_or_value:
-            return "'[', '{', or a literal";
-        default: // catch non-enum values
-            return "unknown token"; // LCOV_EXCL_LINE
-    }
-}
-
-json::lexer::lexer(raw_istream& s)
-    : is(s), decimal_point_char(get_decimal_point())
-{
-    // skip byte order mark
-    std::char_traits<char>::int_type c;
-    if ((c = get()) == 0xEF)
-    {
-        if ((c = get()) == 0xBB)
-        {
-            if ((c = get()) == 0xBF)
-            {
-                chars_read = 0;
-                return; // Ignore BOM
-            }
-            else if (c != std::char_traits<char>::eof())
-            {
-                unget();
-            }
-            putback('\xBB');
-        }
-        else if (c != std::char_traits<char>::eof())
-        {
-            unget();
-        }
-        putback('\xEF');
-    }
-    unget(); // no byte order mark; process as usual
-}
-
-int json::lexer::get_codepoint()
-{
-    // this function only makes sense after reading `\u`
-    assert(current == 'u');
-    int codepoint = 0;
-
-    const auto factors = { 12, 8, 4, 0 };
-    for (const auto factor : factors)
-    {
-        get();
-
-        if (current >= '0' and current <= '9')
-        {
-            codepoint += ((current - 0x30) << factor);
-        }
-        else if (current >= 'A' and current <= 'F')
-        {
-            codepoint += ((current - 0x37) << factor);
-        }
-        else if (current >= 'a' and current <= 'f')
-        {
-            codepoint += ((current - 0x57) << factor);
-        }
-        else
-        {
-            return -1;
-        }
-    }
-
-    assert(0x0000 <= codepoint and codepoint <= 0xFFFF);
-    return codepoint;
-}
-
-json::lexer::token_type json::lexer::scan_string()
-{
-    // reset token_buffer (ignore opening quote)
-    reset();
-
-    // we entered the function by reading an open quote
-    assert(current == '\"');
-
-    while (true)
-    {
-        // get next character
-        switch (get())
-        {
-            // end of file while parsing string
-            case std::char_traits<char>::eof():
-            {
-                error_message = "invalid string: missing closing quote";
-                return token_type::parse_error;
-            }
-
-            // closing quote
-            case '\"':
-            {
-                return token_type::value_string;
-            }
-
-            // escapes
-            case '\\':
-            {
-                switch (get())
-                {
-                    // quotation mark
-                    case '\"':
-                        add('\"');
-                        break;
-                    // reverse solidus
-                    case '\\':
-                        add('\\');
-                        break;
-                    // solidus
-                    case '/':
-                        add('/');
-                        break;
-                    // backspace
-                    case 'b':
-                        add('\b');
-                        break;
-                    // form feed
-                    case 'f':
-                        add('\f');
-                        break;
-                    // line feed
-                    case 'n':
-                        add('\n');
-                        break;
-                    // carriage return
-                    case 'r':
-                        add('\r');
-                        break;
-                    // tab
-                    case 't':
-                        add('\t');
-                        break;
-
-                    // unicode escapes
-                    case 'u':
-                    {
-                        const int codepoint1 = get_codepoint();
-                        int codepoint = codepoint1; // start with codepoint1
-
-                        if (JSON_UNLIKELY(codepoint1 == -1))
-                        {
-                            error_message = "invalid string: '\\u' must be followed by 4 hex digits";
-                            return token_type::parse_error;
-                        }
-
-                        // check if code point is a high surrogate
-                        if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
-                        {
-                            // expect next \uxxxx entry
-                            if (JSON_LIKELY(get() == '\\' and get() == 'u'))
-                            {
-                                const int codepoint2 = get_codepoint();
-
-                                if (JSON_UNLIKELY(codepoint2 == -1))
-                                {
-                                    error_message = "invalid string: '\\u' must be followed by 4 hex digits";
-                                    return token_type::parse_error;
-                                }
-
-                                // check if codepoint2 is a low surrogate
-                                if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
-                                {
-                                    // overwrite codepoint
-                                    codepoint =
-                                        // high surrogate occupies the most significant 22 bits
-                                        (codepoint1 << 10)
-                                        // low surrogate occupies the least significant 15 bits
-                                        + codepoint2
-                                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
-                                        // in the result so we have to subtract with:
-                                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
-                                        - 0x35FDC00;
-                                }
-                                else
-                                {
-                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
-                                    return token_type::parse_error;
-                                }
-                            }
-                            else
-                            {
-                                error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
-                                return token_type::parse_error;
-                            }
-                        }
-                        else
-                        {
-                            if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
-                            {
-                                error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
-                                return token_type::parse_error;
-                            }
-                        }
-
-                        // result of the above calculation yields a proper codepoint
-                        assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
-
-                        // translate codepoint into bytes
-                        if (codepoint < 0x80)
-                        {
-                            // 1-byte characters: 0xxxxxxx (ASCII)
-                            add(codepoint);
-                        }
-                        else if (codepoint <= 0x7FF)
-                        {
-                            // 2-byte characters: 110xxxxx 10xxxxxx
-                            add(0xC0 | (codepoint >> 6));
-                            add(0x80 | (codepoint & 0x3F));
-                        }
-                        else if (codepoint <= 0xFFFF)
-                        {
-                            // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
-                            add(0xE0 | (codepoint >> 12));
-                            add(0x80 | ((codepoint >> 6) & 0x3F));
-                            add(0x80 | (codepoint & 0x3F));
-                        }
-                        else
-                        {
-                            // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-                            add(0xF0 | (codepoint >> 18));
-                            add(0x80 | ((codepoint >> 12) & 0x3F));
-                            add(0x80 | ((codepoint >> 6) & 0x3F));
-                            add(0x80 | (codepoint & 0x3F));
-                        }
-
-                        break;
-                    }
-
-                    // other characters after escape
-                    default:
-                        error_message = "invalid string: forbidden character after backslash";
-                        return token_type::parse_error;
-                }
-
-                break;
-            }
-
-            // invalid control characters
-            case 0x00:
-            case 0x01:
-            case 0x02:
-            case 0x03:
-            case 0x04:
-            case 0x05:
-            case 0x06:
-            case 0x07:
-            case 0x08:
-            case 0x09:
-            case 0x0A:
-            case 0x0B:
-            case 0x0C:
-            case 0x0D:
-            case 0x0E:
-            case 0x0F:
-            case 0x10:
-            case 0x11:
-            case 0x12:
-            case 0x13:
-            case 0x14:
-            case 0x15:
-            case 0x16:
-            case 0x17:
-            case 0x18:
-            case 0x19:
-            case 0x1A:
-            case 0x1B:
-            case 0x1C:
-            case 0x1D:
-            case 0x1E:
-            case 0x1F:
-            {
-                error_message = "invalid string: control character must be escaped";
-                return token_type::parse_error;
-            }
-
-            // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
-            case 0x20:
-            case 0x21:
-            case 0x23:
-            case 0x24:
-            case 0x25:
-            case 0x26:
-            case 0x27:
-            case 0x28:
-            case 0x29:
-            case 0x2A:
-            case 0x2B:
-            case 0x2C:
-            case 0x2D:
-            case 0x2E:
-            case 0x2F:
-            case 0x30:
-            case 0x31:
-            case 0x32:
-            case 0x33:
-            case 0x34:
-            case 0x35:
-            case 0x36:
-            case 0x37:
-            case 0x38:
-            case 0x39:
-            case 0x3A:
-            case 0x3B:
-            case 0x3C:
-            case 0x3D:
-            case 0x3E:
-            case 0x3F:
-            case 0x40:
-            case 0x41:
-            case 0x42:
-            case 0x43:
-            case 0x44:
-            case 0x45:
-            case 0x46:
-            case 0x47:
-            case 0x48:
-            case 0x49:
-            case 0x4A:
-            case 0x4B:
-            case 0x4C:
-            case 0x4D:
-            case 0x4E:
-            case 0x4F:
-            case 0x50:
-            case 0x51:
-            case 0x52:
-            case 0x53:
-            case 0x54:
-            case 0x55:
-            case 0x56:
-            case 0x57:
-            case 0x58:
-            case 0x59:
-            case 0x5A:
-            case 0x5B:
-            case 0x5D:
-            case 0x5E:
-            case 0x5F:
-            case 0x60:
-            case 0x61:
-            case 0x62:
-            case 0x63:
-            case 0x64:
-            case 0x65:
-            case 0x66:
-            case 0x67:
-            case 0x68:
-            case 0x69:
-            case 0x6A:
-            case 0x6B:
-            case 0x6C:
-            case 0x6D:
-            case 0x6E:
-            case 0x6F:
-            case 0x70:
-            case 0x71:
-            case 0x72:
-            case 0x73:
-            case 0x74:
-            case 0x75:
-            case 0x76:
-            case 0x77:
-            case 0x78:
-            case 0x79:
-            case 0x7A:
-            case 0x7B:
-            case 0x7C:
-            case 0x7D:
-            case 0x7E:
-            case 0x7F:
-            {
-                add(current);
-                break;
-            }
-
-            // U+0080..U+07FF: bytes C2..DF 80..BF
-            case 0xC2:
-            case 0xC3:
-            case 0xC4:
-            case 0xC5:
-            case 0xC6:
-            case 0xC7:
-            case 0xC8:
-            case 0xC9:
-            case 0xCA:
-            case 0xCB:
-            case 0xCC:
-            case 0xCD:
-            case 0xCE:
-            case 0xCF:
-            case 0xD0:
-            case 0xD1:
-            case 0xD2:
-            case 0xD3:
-            case 0xD4:
-            case 0xD5:
-            case 0xD6:
-            case 0xD7:
-            case 0xD8:
-            case 0xD9:
-            case 0xDA:
-            case 0xDB:
-            case 0xDC:
-            case 0xDD:
-            case 0xDE:
-            case 0xDF:
-            {
-                if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
-            case 0xE0:
-            {
-                if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
-            // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
-            case 0xE1:
-            case 0xE2:
-            case 0xE3:
-            case 0xE4:
-            case 0xE5:
-            case 0xE6:
-            case 0xE7:
-            case 0xE8:
-            case 0xE9:
-            case 0xEA:
-            case 0xEB:
-            case 0xEC:
-            case 0xEE:
-            case 0xEF:
-            {
-                if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // U+D000..U+D7FF: bytes ED 80..9F 80..BF
-            case 0xED:
-            {
-                if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
-            case 0xF0:
-            {
-                if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
-            case 0xF1:
-            case 0xF2:
-            case 0xF3:
-            {
-                if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
-            case 0xF4:
-            {
-                if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
-                {
-                    return token_type::parse_error;
-                }
-                break;
-            }
-
-            // remaining bytes (80..C1 and F5..FF) are ill-formed
-            default:
-            {
-                error_message = "invalid string: ill-formed UTF-8 byte";
-                return token_type::parse_error;
-            }
-        }
-    }
-}
-
-json::lexer::token_type json::lexer::scan_number()
-{
-    // reset token_buffer to store the number's bytes
-    reset();
-
-    // the type of the parsed number; initially set to unsigned; will be
-    // changed if minus sign, decimal point or exponent is read
-    token_type number_type = token_type::value_unsigned;
-
-    // state (init): we just found out we need to scan a number
-    switch (current)
-    {
-        case '-':
-        {
-            add(current);
-            goto scan_number_minus;
-        }
-
-        case '0':
-        {
-            add(current);
-            goto scan_number_zero;
-        }
-
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_any1;
-        }
-
-        default:
-        {
-            // all other characters are rejected outside scan_number()
-            assert(false); // LCOV_EXCL_LINE
-        }
-    }
-
-scan_number_minus:
-    // state: we just parsed a leading minus sign
-    number_type = token_type::value_integer;
-    switch (get())
-    {
-        case '0':
-        {
-            add(current);
-            goto scan_number_zero;
-        }
-
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_any1;
-        }
-
-        default:
-        {
-            error_message = "invalid number; expected digit after '-'";
-            return token_type::parse_error;
-        }
-    }
-
-scan_number_zero:
-    // state: we just parse a zero (maybe with a leading minus sign)
-    switch (get())
-    {
-        case '.':
-        {
-            add(decimal_point_char);
-            goto scan_number_decimal1;
-        }
-
-        case 'e':
-        case 'E':
-        {
-            add(current);
-            goto scan_number_exponent;
-        }
-
-        default:
-            goto scan_number_done;
-    }
-
-scan_number_any1:
-    // state: we just parsed a number 0-9 (maybe with a leading minus sign)
-    switch (get())
-    {
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_any1;
-        }
-
-        case '.':
-        {
-            add(decimal_point_char);
-            goto scan_number_decimal1;
-        }
-
-        case 'e':
-        case 'E':
-        {
-            add(current);
-            goto scan_number_exponent;
-        }
-
-        default:
-            goto scan_number_done;
-    }
-
-scan_number_decimal1:
-    // state: we just parsed a decimal point
-    number_type = token_type::value_float;
-    switch (get())
-    {
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_decimal2;
-        }
-
-        default:
-        {
-            error_message = "invalid number; expected digit after '.'";
-            return token_type::parse_error;
-        }
-    }
-
-scan_number_decimal2:
-    // we just parsed at least one number after a decimal point
-    switch (get())
-    {
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_decimal2;
-        }
-
-        case 'e':
-        case 'E':
-        {
-            add(current);
-            goto scan_number_exponent;
-        }
-
-        default:
-            goto scan_number_done;
-    }
-
-scan_number_exponent:
-    // we just parsed an exponent
-    number_type = token_type::value_float;
-    switch (get())
-    {
-        case '+':
-        case '-':
-        {
-            add(current);
-            goto scan_number_sign;
-        }
-
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_any2;
-        }
-
-        default:
-        {
-            error_message =
-                "invalid number; expected '+', '-', or digit after exponent";
-            return token_type::parse_error;
-        }
-    }
-
-scan_number_sign:
-    // we just parsed an exponent sign
-    switch (get())
-    {
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_any2;
-        }
-
-        default:
-        {
-            error_message = "invalid number; expected digit after exponent sign";
-            return token_type::parse_error;
-        }
-    }
-
-scan_number_any2:
-    // we just parsed a number after the exponent or exponent sign
-    switch (get())
-    {
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-        {
-            add(current);
-            goto scan_number_any2;
-        }
-
-        default:
-            goto scan_number_done;
-    }
-
-scan_number_done:
-    // unget the character after the number (we only read it to know that
-    // we are done scanning a number)
-    unget();
-
-    char* endptr = nullptr;
-    errno = 0;
-
-    // try to parse integers first and fall back to floats
-    if (number_type == token_type::value_unsigned)
-    {
-        const auto x = std::strtoull(token_buffer.c_str(), &endptr, 10);
-
-        // we checked the number format before
-        assert(endptr == token_buffer.data() + token_buffer.size());
-
-        if (errno == 0)
-        {
-            value_unsigned = static_cast<uint64_t>(x);
-            if (value_unsigned == x)
-            {
-                return token_type::value_unsigned;
-            }
-        }
-    }
-    else if (number_type == token_type::value_integer)
-    {
-        const auto x = std::strtoll(token_buffer.c_str(), &endptr, 10);
-
-        // we checked the number format before
-        assert(endptr == token_buffer.data() + token_buffer.size());
-
-        if (errno == 0)
-        {
-            value_integer = static_cast<int64_t>(x);
-            if (value_integer == x)
-            {
-                return token_type::value_integer;
-            }
-        }
-    }
-
-    // this code is reached if we parse a floating-point number or if an
-    // integer conversion above failed
-    strtof(value_float, token_buffer.c_str(), &endptr);
-
-    // we checked the number format before
-    assert(endptr == token_buffer.data() + token_buffer.size());
-
-    return token_type::value_float;
-}
-
-json::lexer::token_type json::lexer::scan_literal(const char* literal_text, const std::size_t length,
-                        token_type return_type)
-{
-    assert(current == literal_text[0]);
-    for (std::size_t i = 1; i < length; ++i)
-    {
-        if (JSON_UNLIKELY(get() != literal_text[i]))
-        {
-            error_message = "invalid literal";
-            return token_type::parse_error;
-        }
-    }
-    return return_type;
-}
-
-std::string json::lexer::get_token_string() const
-{
-    // escape control characters
-    std::string result;
-    raw_string_ostream ss(result);
-    for (const unsigned char c : token_string)
-    {
-        if (c <= '\x1F')
-        {
-            // escape control characters
-            ss << fmt::format("<U+{:04X}>", c);
-        }
-        else
-        {
-            // add character as is
-            ss << c;
-        }
-    }
-
-    ss.flush();
-    return result;
-}
-
-json::lexer::token_type json::lexer::scan()
-{
-    // read next character and ignore whitespace
-    do
-    {
-        get();
-    }
-    while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
-
-    switch (current)
-    {
-        // structural characters
-        case '[':
-            return token_type::begin_array;
-        case ']':
-            return token_type::end_array;
-        case '{':
-            return token_type::begin_object;
-        case '}':
-            return token_type::end_object;
-        case ':':
-            return token_type::name_separator;
-        case ',':
-            return token_type::value_separator;
-
-        // literals
-        case 't':
-            return scan_literal("true", 4, token_type::literal_true);
-        case 'f':
-            return scan_literal("false", 5, token_type::literal_false);
-        case 'n':
-            return scan_literal("null", 4, token_type::literal_null);
-
-        // string
-        case '\"':
-            return scan_string();
-
-        // number
-        case '-':
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-            return scan_number();
-
-        // end of input (the null byte is needed when parsing from
-        // string literals)
-        case '\0':
-        case std::char_traits<char>::eof():
-            return token_type::end_of_input;
-
-        // error
-        default:
-            error_message = "invalid literal";
-            return token_type::parse_error;
-    }
-}
-
-void json::parser::parse(const bool strict, json& result)
-{
-    // read first token
-    get_token();
-
-    parse_internal(true, result);
-    result.assert_invariant();
-
-    // in strict mode, input must be completely read
-    if (strict)
-    {
-        get_token();
-        expect(token_type::end_of_input);
-    }
-
-    // in case of an error, return discarded value
-    if (errored)
-    {
-        result = value_t::discarded;
-        return;
-    }
-
-    // set top-level value to null if it was discarded by the callback
-    // function
-    if (result.is_discarded())
-    {
-        result = nullptr;
-    }
-}
-
-void json::parser::parse_internal(bool keep, json& result)
-{
-    // never parse after a parse error was detected
-    assert(not errored);
-
-    // start with a discarded value
-    if (not result.is_discarded())
-    {
-        result.m_value.destroy(result.m_type);
-        result.m_type = value_t::discarded;
-    }
-
-    switch (last_token)
-    {
-        case token_type::begin_object:
-        {
-            if (keep)
-            {
-                if (callback)
-                {
-                    keep = callback(depth++, parse_event_t::object_start, result);
-                }
-
-                if (not callback or keep)
-                {
-                    // explicitly set result to object to cope with {}
-                    result.m_type = value_t::object;
-                    result.m_value = value_t::object;
-                }
-            }
-
-            // read next token
-            get_token();
-
-            // closing } -> we are done
-            if (last_token == token_type::end_object)
-            {
-                if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
-                {
-                    result.m_value.destroy(result.m_type);
-                    result.m_type = value_t::discarded;
-                }
-                break;
-            }
-
-            // parse values
-            SmallString<128> key;
-            json value;
-            while (true)
-            {
-                // store key
-                if (not expect(token_type::value_string))
-                {
-                    return;
-                }
-                key = m_lexer.get_string();
-
-                bool keep_tag = false;
-                if (keep)
-                {
-                    if (callback)
-                    {
-                        json k(key);
-                        keep_tag = callback(depth, parse_event_t::key, k);
-                    }
-                    else
-                    {
-                        keep_tag = true;
-                    }
-                }
-
-                // parse separator (:)
-                get_token();
-                if (not expect(token_type::name_separator))
-                {
-                    return;
-                }
-
-                // parse and add value
-                get_token();
-                value.m_value.destroy(value.m_type);
-                value.m_type = value_t::discarded;
-                parse_internal(keep, value);
-
-                if (JSON_UNLIKELY(errored))
-                {
-                    return;
-                }
-
-                if (keep and keep_tag and not value.is_discarded())
-                {
-                    result.m_value.object->try_emplace(std::string_view(key.data(), key.size()), std::move(value));
-                }
-
-                // comma -> next value
-                get_token();
-                if (last_token == token_type::value_separator)
-                {
-                    get_token();
-                    continue;
-                }
-
-                // closing }
-                if (not expect(token_type::end_object))
-                {
-                    return;
-                }
-                break;
-            }
-
-            if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
-            {
-                result.m_value.destroy(result.m_type);
-                result.m_type = value_t::discarded;
-            }
-            break;
-        }
-
-        case token_type::begin_array:
-        {
-            if (keep)
-            {
-                if (callback)
-                {
-                    keep = callback(depth++, parse_event_t::array_start, result);
-                }
-
-                if (not callback or keep)
-                {
-                    // explicitly set result to array to cope with []
-                    result.m_type = value_t::array;
-                    result.m_value = value_t::array;
-                }
-            }
-
-            // read next token
-            get_token();
-
-            // closing ] -> we are done
-            if (last_token == token_type::end_array)
-            {
-                if (callback and not callback(--depth, parse_event_t::array_end, result))
-                {
-                    result.m_value.destroy(result.m_type);
-                    result.m_type = value_t::discarded;
-                }
-                break;
-            }
-
-            // parse values
-            json value;
-            while (true)
-            {
-                // parse value
-                value.m_value.destroy(value.m_type);
-                value.m_type = value_t::discarded;
-                parse_internal(keep, value);
-
-                if (JSON_UNLIKELY(errored))
-                {
-                    return;
-                }
-
-                if (keep and not value.is_discarded())
-                {
-                    result.m_value.array->push_back(std::move(value));
-                }
-
-                // comma -> next value
-                get_token();
-                if (last_token == token_type::value_separator)
-                {
-                    get_token();
-                    continue;
-                }
-
-                // closing ]
-                if (not expect(token_type::end_array))
-                {
-                    return;
-                }
-                break;
-            }
-
-            if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
-            {
-                result.m_value.destroy(result.m_type);
-                result.m_type = value_t::discarded;
-            }
-            break;
-        }
-
-        case token_type::literal_null:
-        {
-            result.m_type = value_t::null;
-            break;
-        }
-
-        case token_type::value_string:
-        {
-            result.m_type = value_t::string;
-            result.m_value = m_lexer.get_string();
-            break;
-        }
-
-        case token_type::literal_true:
-        {
-            result.m_type = value_t::boolean;
-            result.m_value = true;
-            break;
-        }
-
-        case token_type::literal_false:
-        {
-            result.m_type = value_t::boolean;
-            result.m_value = false;
-            break;
-        }
-
-        case token_type::value_unsigned:
-        {
-            result.m_type = value_t::number_unsigned;
-            result.m_value = m_lexer.get_number_unsigned();
-            break;
-        }
-
-        case token_type::value_integer:
-        {
-            result.m_type = value_t::number_integer;
-            result.m_value = m_lexer.get_number_integer();
-            break;
-        }
-
-        case token_type::value_float:
-        {
-            result.m_type = value_t::number_float;
-            result.m_value = m_lexer.get_number_float();
-
-            // throw in case of infinity or NAN
-            if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float)))
-            {
-                if (allow_exceptions)
-                {
-                    JSON_THROW(out_of_range::create(406,
-                        fmt::format("number overflow parsing '{}'", m_lexer.get_token_string())));
-                }
-                expect(token_type::uninitialized);
-            }
-            break;
-        }
-
-        case token_type::parse_error:
-        {
-            // using "uninitialized" to avoid "expected" message
-            if (not expect(token_type::uninitialized))
-            {
-                return;
-            }
-            break; // LCOV_EXCL_LINE
-        }
-
-        default:
-        {
-            // the last token was unexpected; we expected a value
-            if (not expect(token_type::literal_or_value))
-            {
-                return;
-            }
-            break; // LCOV_EXCL_LINE
-        }
-    }
-
-    if (keep and callback and not callback(depth, parse_event_t::value, result))
-    {
-        result.m_value.destroy(result.m_type);
-        result.m_type = value_t::discarded;
-    }
-}
-
-bool json::parser::accept_internal()
-{
-    switch (last_token)
-    {
-        case token_type::begin_object:
-        {
-            // read next token
-            get_token();
-
-            // closing } -> we are done
-            if (last_token == token_type::end_object)
-            {
-                return true;
-            }
-
-            // parse values
-            while (true)
-            {
-                // parse key
-                if (last_token != token_type::value_string)
-                {
-                    return false;
-                }
-
-                // parse separator (:)
-                get_token();
-                if (last_token != token_type::name_separator)
-                {
-                    return false;
-                }
-
-                // parse value
-                get_token();
-                if (not accept_internal())
-                {
-                    return false;
-                }
-
-                // comma -> next value
-                get_token();
-                if (last_token == token_type::value_separator)
-                {
-                    get_token();
-                    continue;
-                }
-
-                // closing }
-                return (last_token == token_type::end_object);
-            }
-        }
-
-        case token_type::begin_array:
-        {
-            // read next token
-            get_token();
-
-            // closing ] -> we are done
-            if (last_token == token_type::end_array)
-            {
-                return true;
-            }
-
-            // parse values
-            while (true)
-            {
-                // parse value
-                if (not accept_internal())
-                {
-                    return false;
-                }
-
-                // comma -> next value
-                get_token();
-                if (last_token == token_type::value_separator)
-                {
-                    get_token();
-                    continue;
-                }
-
-                // closing ]
-                return (last_token == token_type::end_array);
-            }
-        }
-
-        case token_type::value_float:
-        {
-            // reject infinity or NAN
-            return std::isfinite(m_lexer.get_number_float());
-        }
-
-        case token_type::literal_false:
-        case token_type::literal_null:
-        case token_type::literal_true:
-        case token_type::value_integer:
-        case token_type::value_string:
-        case token_type::value_unsigned:
-            return true;
-
-        default: // the last token was unexpected
-            return false;
-    }
-}
-
-void json::parser::throw_exception() const
-{
-    std::string error_msg = "syntax error - ";
-    if (last_token == token_type::parse_error)
-    {
-        error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
-                     m_lexer.get_token_string() + "'";
-    }
-    else
-    {
-        error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token));
-    }
-
-    if (expected != token_type::uninitialized)
-    {
-        error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
-    }
-
-    JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg));
-}
-
-json json::parse(std::string_view s,
-                        const parser_callback_t cb,
-                        const bool allow_exceptions)
-{
-    raw_mem_istream is(std::span<const char>(s.data(), s.size()));
-    return parse(is, cb, allow_exceptions);
-}
-
-json json::parse(std::span<const uint8_t> arr,
-                        const parser_callback_t cb,
-                        const bool allow_exceptions)
-{
-    raw_mem_istream is(arr);
-    return parse(is, cb, allow_exceptions);
-}
-
-json json::parse(raw_istream& i,
-                        const parser_callback_t cb,
-                        const bool allow_exceptions)
-{
-    json result;
-    parser(i, cb, allow_exceptions).parse(true, result);
-    return result;
-}
-
-bool json::accept(std::string_view s)
-{
-    raw_mem_istream is(std::span<const char>(s.data(), s.size()));
-    return parser(is).accept(true);
-}
-
-bool json::accept(std::span<const uint8_t> arr)
-{
-    raw_mem_istream is(arr);
-    return parser(is).accept(true);
-}
-
-bool json::accept(raw_istream& i)
-{
-    return parser(i).accept(true);
-}
-
-raw_istream& operator>>(raw_istream& i, json& j)
-{
-    json::parser(i).parse(false, j);
-    return i;
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp
deleted file mode 100644
index 51548b3..0000000
--- a/wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp
+++ /dev/null
@@ -1,540 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#define WPI_JSON_IMPLEMENTATION
-#include "wpi/json.h"
-
-#include <numeric> // accumulate
-
-#include "fmt/format.h"
-#include "wpi/SmallString.h"
-#include "wpi/StringExtras.h"
-
-namespace wpi {
-
-std::string json_pointer::to_string() const noexcept
-{
-    return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
-                           std::string{},
-                           [](const std::string & a, const std::string & b)
-    {
-        return a + "/" + escape(b);
-    });
-}
-
-int json_pointer::array_index(std::string_view s)
-{
-    SmallString<128> str{s};
-    std::size_t processed_chars = 0;
-    const int res = std::stoi(str.c_str(), &processed_chars);
-
-    // check if the string was completely read
-    if (JSON_UNLIKELY(processed_chars != str.size()))
-    {
-        JSON_THROW(detail::out_of_range::create(404, fmt::format("unresolved reference token '{}'", s)));
-    }
-
-    return res;
-}
-
-json& json_pointer::get_and_create(json& j) const
-{
-    using size_type = typename json::size_type;
-    auto result = &j;
-
-    // in case no reference tokens exist, return a reference to the JSON value
-    // j which will be overwritten by a primitive value
-    for (const auto& reference_token : reference_tokens)
-    {
-        switch (result->m_type)
-        {
-            case detail::value_t::null:
-            {
-                if (reference_token == "0")
-                {
-                    // start a new array if reference token is 0
-                    result = &result->operator[](0);
-                }
-                else
-                {
-                    // start a new object otherwise
-                    result = &result->operator[](reference_token);
-                }
-                break;
-            }
-
-            case detail::value_t::object:
-            {
-                // create an entry in the object
-                result = &result->operator[](reference_token);
-                break;
-            }
-
-            case detail::value_t::array:
-            {
-                // create an entry in the array
-                JSON_TRY
-                {
-                    result = &result->operator[](static_cast<size_type>(array_index(reference_token)));
-                }
-                JSON_CATCH(std::invalid_argument&)
-                {
-                    JSON_THROW(detail::parse_error::create(109, 0, fmt::format("array index '{}' is not a number", reference_token)));
-                }
-                break;
-            }
-
-            /*
-            The following code is only reached if there exists a reference
-            token _and_ the current value is primitive. In this case, we have
-            an error situation, because primitive values may only occur as
-            single value; that is, with an empty list of reference tokens.
-            */
-            default:
-                JSON_THROW(detail::type_error::create(313, "invalid value to unflatten"));
-        }
-    }
-
-    return *result;
-}
-
-json& json_pointer::get_unchecked(json* ptr) const
-{
-    using size_type = typename json::size_type;
-    for (const auto& reference_token : reference_tokens)
-    {
-        // convert null values to arrays or objects before continuing
-        if (ptr->m_type == detail::value_t::null)
-        {
-            // check if reference token is a number
-            const bool nums =
-                std::all_of(reference_token.begin(), reference_token.end(),
-                            [](const char x)
-            {
-                return (x >= '0' and x <= '9');
-            });
-
-            // change value to array for numbers or "-" or to object otherwise
-            *ptr = (nums or reference_token == "-")
-                   ? detail::value_t::array
-                   : detail::value_t::object;
-        }
-
-        switch (ptr->m_type)
-        {
-            case detail::value_t::object:
-            {
-                // use unchecked object access
-                ptr = &ptr->operator[](reference_token);
-                break;
-            }
-
-            case detail::value_t::array:
-            {
-                // error condition (cf. RFC 6901, Sect. 4)
-                if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
-                {
-                    JSON_THROW(detail::parse_error::create(106, 0,
-                        fmt::format("array index '{}' must not begin with '0'", reference_token)));
-                }
-
-                if (reference_token == "-")
-                {
-                    // explicitly treat "-" as index beyond the end
-                    ptr = &ptr->operator[](ptr->m_value.array->size());
-                }
-                else
-                {
-                    // convert array index to number; unchecked access
-                    JSON_TRY
-                    {
-                        ptr = &ptr->operator[](
-                            static_cast<size_type>(array_index(reference_token)));
-                    }
-                    JSON_CATCH(std::invalid_argument&)
-                    {
-                        JSON_THROW(detail::parse_error::create(109, 0,
-                            fmt::format("array index '{}' is not a number", reference_token)));
-                    }
-                }
-                break;
-            }
-
-            default:
-                JSON_THROW(detail::out_of_range::create(404,
-                    fmt::format("unresolved reference token '{}'", reference_token)));
-        }
-    }
-
-    return *ptr;
-}
-
-json& json_pointer::get_checked(json* ptr) const
-{
-    using size_type = typename json::size_type;
-    for (const auto& reference_token : reference_tokens)
-    {
-        switch (ptr->m_type)
-        {
-            case detail::value_t::object:
-            {
-                // note: at performs range check
-                ptr = &ptr->at(reference_token);
-                break;
-            }
-
-            case detail::value_t::array:
-            {
-                if (JSON_UNLIKELY(reference_token == "-"))
-                {
-                    // "-" always fails the range check
-                    JSON_THROW(detail::out_of_range::create(402,
-                        fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
-                }
-
-                // error condition (cf. RFC 6901, Sect. 4)
-                if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
-                {
-                    JSON_THROW(detail::parse_error::create(106, 0,
-                        fmt::format("array index '{}' must not begin with '0'", reference_token)));
-                }
-
-                // note: at performs range check
-                JSON_TRY
-                {
-                    ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
-                }
-                JSON_CATCH(std::invalid_argument&)
-                {
-                    JSON_THROW(detail::parse_error::create(109, 0,
-                        fmt::format("array index '{}' is not a number", reference_token)));
-                }
-                break;
-            }
-
-            default:
-                JSON_THROW(detail::out_of_range::create(404,
-                    fmt::format("unresolved reference token '{}'", reference_token)));
-        }
-    }
-
-    return *ptr;
-}
-
-const json& json_pointer::get_unchecked(const json* ptr) const
-{
-    using size_type = typename json::size_type;
-    for (const auto& reference_token : reference_tokens)
-    {
-        switch (ptr->m_type)
-        {
-            case detail::value_t::object:
-            {
-                // use unchecked object access
-                ptr = &ptr->operator[](reference_token);
-                break;
-            }
-
-            case detail::value_t::array:
-            {
-                if (JSON_UNLIKELY(reference_token == "-"))
-                {
-                    // "-" cannot be used for const access
-                    JSON_THROW(detail::out_of_range::create(402,
-                        fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
-                }
-
-                // error condition (cf. RFC 6901, Sect. 4)
-                if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
-                {
-                    JSON_THROW(detail::parse_error::create(106, 0,
-                        fmt::format("array index '{}' must not begin with '0'", reference_token)));
-                }
-
-                // use unchecked array access
-                JSON_TRY
-                {
-                    ptr = &ptr->operator[](
-                        static_cast<size_type>(array_index(reference_token)));
-                }
-                JSON_CATCH(std::invalid_argument&)
-                {
-                    JSON_THROW(detail::parse_error::create(109, 0,
-                        fmt::format("array index '{}' is not a number", reference_token)));
-                }
-                break;
-            }
-
-            default:
-                JSON_THROW(detail::out_of_range::create(404,
-                    fmt::format("unresolved reference token '{}'", reference_token)));
-        }
-    }
-
-    return *ptr;
-}
-
-const json& json_pointer::get_checked(const json* ptr) const
-{
-    using size_type = typename json::size_type;
-    for (const auto& reference_token : reference_tokens)
-    {
-        switch (ptr->m_type)
-        {
-            case detail::value_t::object:
-            {
-                // note: at performs range check
-                ptr = &ptr->at(reference_token);
-                break;
-            }
-
-            case detail::value_t::array:
-            {
-                if (JSON_UNLIKELY(reference_token == "-"))
-                {
-                    // "-" always fails the range check
-                    JSON_THROW(detail::out_of_range::create(402,
-                        fmt::format("array index '-' ({}) is out of range", ptr->m_value.array->size())));
-                }
-
-                // error condition (cf. RFC 6901, Sect. 4)
-                if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
-                {
-                    JSON_THROW(detail::parse_error::create(106, 0,
-                        fmt::format("array index '{}' must not begin with '0'", reference_token)));
-                }
-
-                // note: at performs range check
-                JSON_TRY
-                {
-                    ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
-                }
-                JSON_CATCH(std::invalid_argument&)
-                {
-                    JSON_THROW(detail::parse_error::create(109, 0,
-                        fmt::format("array index '{}' is not a number", reference_token)));
-                }
-                break;
-            }
-
-            default:
-                JSON_THROW(detail::out_of_range::create(404,
-                    fmt::format("unresolved reference token '{}'", reference_token)));
-        }
-    }
-
-    return *ptr;
-}
-
-std::vector<std::string> json_pointer::split(std::string_view ref_str)
-{
-    std::vector<std::string> result;
-
-    // special case: empty reference string -> no reference tokens
-    if (ref_str.empty())
-    {
-        return result;
-    }
-
-    // check if nonempty reference string begins with slash
-    if (JSON_UNLIKELY(ref_str[0] != '/'))
-    {
-        JSON_THROW(detail::parse_error::create(107, 1,
-            fmt::format("JSON pointer must be empty or begin with '/' - was: '{}'", ref_str)));
-    }
-
-    // extract the reference tokens:
-    // - slash: position of the last read slash (or end of string)
-    // - start: position after the previous slash
-    for (
-        // search for the first slash after the first character
-        std::size_t slash = ref_str.find_first_of('/', 1),
-        // set the beginning of the first reference token
-        start = 1;
-        // we can stop if start == string::npos+1 = 0
-        start != 0;
-        // set the beginning of the next reference token
-        // (will eventually be 0 if slash == std::string::npos)
-        start = slash + 1,
-        // find next slash
-        slash = ref_str.find_first_of('/', start))
-    {
-        // use the text between the beginning of the reference token
-        // (start) and the last slash (slash).
-        auto reference_token = slice(ref_str, start, slash);
-
-        // check reference tokens are properly escaped
-        for (std::size_t pos = reference_token.find_first_of('~');
-                pos != std::string_view::npos;
-                pos = reference_token.find_first_of('~', pos + 1))
-        {
-            assert(reference_token[pos] == '~');
-
-            // ~ must be followed by 0 or 1
-            if (JSON_UNLIKELY(pos == reference_token.size() - 1 or
-                              (reference_token[pos + 1] != '0' and
-                               reference_token[pos + 1] != '1')))
-            {
-                JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
-            }
-        }
-
-        // finally, store the reference token
-        std::string ref_tok{reference_token};
-        unescape(ref_tok);
-        result.emplace_back(std::move(ref_tok));
-    }
-
-    return result;
-}
-
-void json_pointer::replace_substring(std::string& s, const std::string& f,
-                              const std::string& t)
-{
-    assert(not f.empty());
-    for (auto pos = s.find(f);                // find first occurrence of f
-            pos != std::string::npos;         // make sure f was found
-            s.replace(pos, f.size(), t),      // replace with t, and
-            pos = s.find(f, pos + t.size()))  // find next occurrence of f
-    {}
-}
-
-std::string json_pointer::escape(std::string s)
-{
-    replace_substring(s, "~", "~0");
-    replace_substring(s, "/", "~1");
-    return s;
-}
-
-/// unescape "~1" to tilde and "~0" to slash (order is important!)
-void json_pointer::unescape(std::string& s)
-{
-    replace_substring(s, "~1", "/");
-    replace_substring(s, "~0", "~");
-}
-
-void json_pointer::flatten(std::string_view reference_string,
-                    const json& value,
-                    json& result)
-{
-    switch (value.m_type)
-    {
-        case detail::value_t::array:
-        {
-            if (value.m_value.array->empty())
-            {
-                // flatten empty array as null
-                result[reference_string] = nullptr;
-            }
-            else
-            {
-                // iterate array and use index as reference string
-                for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
-                {
-                    flatten(fmt::format("{}/{}", reference_string, i),
-                            value.m_value.array->operator[](i), result);
-                }
-            }
-            break;
-        }
-
-        case detail::value_t::object:
-        {
-            if (value.m_value.object->empty())
-            {
-                // flatten empty object as null
-                result[reference_string] = nullptr;
-            }
-            else
-            {
-                // iterate object and use keys as reference string
-                for (const auto& element : *value.m_value.object)
-                {
-                    flatten(fmt::format("{}/{}", reference_string, escape(std::string{element.first()})), element.second, result);
-                }
-            }
-            break;
-        }
-
-        default:
-        {
-            // add primitive value with its reference string
-            result[reference_string] = value;
-            break;
-        }
-    }
-}
-
-json
-json_pointer::unflatten(const json& value)
-{
-    if (JSON_UNLIKELY(not value.is_object()))
-    {
-        JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
-    }
-
-    // we need to iterate over the object values in sorted key order
-    SmallVector<StringMapConstIterator<json>, 64> sorted;
-    for (auto i = value.m_value.object->begin(),
-         end = value.m_value.object->end(); i != end; ++i)
-    {
-        if (!i->second.is_primitive())
-        {
-            JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
-        }
-        sorted.push_back(i);
-    }
-    std::sort(sorted.begin(), sorted.end(),
-              [](const StringMapConstIterator<json>& a,
-                 const StringMapConstIterator<json>& b) {
-                return a->getKey() < b->getKey();
-              });
-
-    json result;
-
-    // iterate the sorted JSON object values
-    for (const auto& element : sorted)
-    {
-
-        // assign value to reference pointed to by JSON pointer; Note
-        // that if the JSON pointer is "" (i.e., points to the whole
-        // value), function get_and_create returns a reference to
-        // result itself. An assignment will then create a primitive
-        // value.
-        json_pointer(element->first()).get_and_create(result) = element->second;
-    }
-
-    return result;
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp
deleted file mode 100644
index 1101f66..0000000
--- a/wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp
+++ /dev/null
@@ -1,1531 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#define WPI_JSON_IMPLEMENTATION
-#include "wpi/json.h"
-
-#include "fmt/format.h"
-#include "wpi/SmallString.h"
-#include "wpi/raw_os_ostream.h"
-
-#include "wpi/json_serializer.h"
-
-namespace wpi {
-
-namespace {
-
-/*!
-@brief implements the Grisu2 algorithm for binary to decimal floating-point
-conversion.
-
-This implementation is a slightly modified version of the reference
-implementation which may be obtained from
-http://florian.loitsch.com/publications (bench.tar.gz).
-
-The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
-
-For a detailed description of the algorithm see:
-
-[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
-    Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
-    Language Design and Implementation, PLDI 2010
-[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
-    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
-    Design and Implementation, PLDI 1996
-*/
-namespace dtoa_impl
-{
-
-template <typename Target, typename Source>
-Target reinterpret_bits(const Source source)
-{
-    static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
-
-    Target target;
-    std::memcpy(&target, &source, sizeof(Source));
-    return target;
-}
-
-struct diyfp // f * 2^e
-{
-    static constexpr int kPrecision = 64; // = q
-
-    uint64_t f;
-    int e;
-
-    constexpr diyfp() noexcept : f(0), e(0) {}
-    constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
-
-    /*!
-    @brief returns x - y
-    @pre x.e == y.e and x.f >= y.f
-    */
-    static diyfp sub(const diyfp& x, const diyfp& y) noexcept
-    {
-        assert(x.e == y.e);
-        assert(x.f >= y.f);
-
-        return diyfp(x.f - y.f, x.e);
-    }
-
-    /*!
-    @brief returns x * y
-    @note The result is rounded. (Only the upper q bits are returned.)
-    */
-    static diyfp mul(const diyfp& x, const diyfp& y) noexcept
-    {
-        static_assert(kPrecision == 64, "internal error");
-
-        // Computes:
-        //  f = round((x.f * y.f) / 2^q)
-        //  e = x.e + y.e + q
-
-        // Emulate the 64-bit * 64-bit multiplication:
-        //
-        // p = u * v
-        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
-        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )
-        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )
-        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )
-        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)
-        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )
-        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )
-        //
-        // (Since Q might be larger than 2^32 - 1)
-        //
-        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
-        //
-        // (Q_hi + H does not overflow a 64-bit int)
-        //
-        //   = p_lo + 2^64 p_hi
-
-        const uint64_t u_lo = x.f & 0xFFFFFFFF;
-        const uint64_t u_hi = x.f >> 32;
-        const uint64_t v_lo = y.f & 0xFFFFFFFF;
-        const uint64_t v_hi = y.f >> 32;
-
-        const uint64_t p0 = u_lo * v_lo;
-        const uint64_t p1 = u_lo * v_hi;
-        const uint64_t p2 = u_hi * v_lo;
-        const uint64_t p3 = u_hi * v_hi;
-
-        const uint64_t p0_hi = p0 >> 32;
-        const uint64_t p1_lo = p1 & 0xFFFFFFFF;
-        const uint64_t p1_hi = p1 >> 32;
-        const uint64_t p2_lo = p2 & 0xFFFFFFFF;
-        const uint64_t p2_hi = p2 >> 32;
-
-        uint64_t Q = p0_hi + p1_lo + p2_lo;
-
-        // The full product might now be computed as
-        //
-        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
-        // p_lo = p0_lo + (Q << 32)
-        //
-        // But in this particular case here, the full p_lo is not required.
-        // Effectively we only need to add the highest bit in p_lo to p_hi (and
-        // Q_hi + 1 does not overflow).
-
-        Q += uint64_t{1} << (64 - 32 - 1); // round, ties up
-
-        const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
-
-        return diyfp(h, x.e + y.e + 64);
-    }
-
-    /*!
-    @brief normalize x such that the significand is >= 2^(q-1)
-    @pre x.f != 0
-    */
-    static diyfp normalize(diyfp x) noexcept
-    {
-        assert(x.f != 0);
-
-        while ((x.f >> 63) == 0)
-        {
-            x.f <<= 1;
-            x.e--;
-        }
-
-        return x;
-    }
-
-    /*!
-    @brief normalize x such that the result has the exponent E
-    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
-    */
-    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
-    {
-        const int delta = x.e - target_exponent;
-
-        assert(delta >= 0);
-        assert(((x.f << delta) >> delta) == x.f);
-
-        return diyfp(x.f << delta, target_exponent);
-    }
-};
-
-struct boundaries
-{
-    diyfp w;
-    diyfp minus;
-    diyfp plus;
-};
-
-/*!
-Compute the (normalized) diyfp representing the input number 'value' and its
-boundaries.
-
-@pre value must be finite and positive
-*/
-template <typename FloatType>
-boundaries compute_boundaries(FloatType value)
-{
-    assert(std::isfinite(value));
-    assert(value > 0);
-
-    // Convert the IEEE representation into a diyfp.
-    //
-    // If v is denormal:
-    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))
-    // If v is normalized:
-    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
-
-    static_assert(std::numeric_limits<FloatType>::is_iec559,
-                  "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
-
-    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
-    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
-    constexpr int      kMinExp    = 1 - kBias;
-    constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
-
-    using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type;
-
-    const uint64_t bits = reinterpret_bits<bits_type>(value);
-    const uint64_t E = bits >> (kPrecision - 1);
-    const uint64_t F = bits & (kHiddenBit - 1);
-
-    const bool is_denormal = (E == 0);
-    const diyfp v = is_denormal
-                    ? diyfp(F, kMinExp)
-                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
-
-    // Compute the boundaries m- and m+ of the floating-point value
-    // v = f * 2^e.
-    //
-    // Determine v- and v+, the floating-point predecessor and successor if v,
-    // respectively.
-    //
-    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)
-    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)
-    //
-    //      v+ = v + 2^e
-    //
-    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
-    // between m- and m+ round to v, regardless of how the input rounding
-    // algorithm breaks ties.
-    //
-    //      ---+-------------+-------------+-------------+-------------+---  (A)
-    //         v-            m-            v             m+            v+
-    //
-    //      -----------------+------+------+-------------+-------------+---  (B)
-    //                       v-     m-     v             m+            v+
-
-    const bool lower_boundary_is_closer = (F == 0 and E > 1);
-    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
-    const diyfp m_minus = lower_boundary_is_closer
-                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)
-                          : diyfp(2 * v.f - 1, v.e - 1); // (A)
-
-    // Determine the normalized w+ = m+.
-    const diyfp w_plus = diyfp::normalize(m_plus);
-
-    // Determine w- = m- such that e_(w-) = e_(w+).
-    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
-
-    return {diyfp::normalize(v), w_minus, w_plus};
-}
-
-// Given normalized diyfp w, Grisu needs to find a (normalized) cached
-// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
-// within a certain range [alpha, gamma] (Definition 3.2 from [1])
-//
-//      alpha <= e = e_c + e_w + q <= gamma
-//
-// or
-//
-//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
-//                          <= f_c * f_w * 2^gamma
-//
-// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
-//
-//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
-//
-// or
-//
-//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
-//
-// The choice of (alpha,gamma) determines the size of the table and the form of
-// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
-// in practice:
-//
-// The idea is to cut the number c * w = f * 2^e into two parts, which can be
-// processed independently: An integral part p1, and a fractional part p2:
-//
-//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
-//              = (f div 2^-e) + (f mod 2^-e) * 2^e
-//              = p1 + p2 * 2^e
-//
-// The conversion of p1 into decimal form requires a series of divisions and
-// modulos by (a power of) 10. These operations are faster for 32-bit than for
-// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
-// achieved by choosing
-//
-//      -e >= 32   or   e <= -32 := gamma
-//
-// In order to convert the fractional part
-//
-//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
-//
-// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
-// d[-i] are extracted in order:
-//
-//      (10 * p2) div 2^-e = d[-1]
-//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
-//
-// The multiplication by 10 must not overflow. It is sufficient to choose
-//
-//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
-//
-// Since p2 = f mod 2^-e < 2^-e,
-//
-//      -e <= 60   or   e >= -60 := alpha
-
-constexpr int kAlpha = -60;
-constexpr int kGamma = -32;
-
-struct cached_power // c = f * 2^e ~= 10^k
-{
-    uint64_t f;
-    int e;
-    int k;
-};
-
-/*!
-For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
-power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
-satisfies (Definition 3.2 from [1])
-
-     alpha <= e_c + e + q <= gamma.
-*/
-inline cached_power get_cached_power_for_binary_exponent(int e)
-{
-    // Now
-    //
-    //      alpha <= e_c + e + q <= gamma                                    (1)
-    //      ==> f_c * 2^alpha <= c * 2^e * 2^q
-    //
-    // and since the c's are normalized, 2^(q-1) <= f_c,
-    //
-    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
-    //      ==> 2^(alpha - e - 1) <= c
-    //
-    // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as
-    //
-    //      k = ceil( log_10( 2^(alpha - e - 1) ) )
-    //        = ceil( (alpha - e - 1) * log_10(2) )
-    //
-    // From the paper:
-    // "In theory the result of the procedure could be wrong since c is rounded,
-    //  and the computation itself is approximated [...]. In practice, however,
-    //  this simple function is sufficient."
-    //
-    // For IEEE double precision floating-point numbers converted into
-    // normalized diyfp's w = f * 2^e, with q = 64,
-    //
-    //      e >= -1022      (min IEEE exponent)
-    //           -52        (p - 1)
-    //           -52        (p - 1, possibly normalize denormal IEEE numbers)
-    //           -11        (normalize the diyfp)
-    //         = -1137
-    //
-    // and
-    //
-    //      e <= +1023      (max IEEE exponent)
-    //           -52        (p - 1)
-    //           -11        (normalize the diyfp)
-    //         = 960
-    //
-    // This binary exponent range [-1137,960] results in a decimal exponent
-    // range [-307,324]. One does not need to store a cached power for each
-    // k in this range. For each such k it suffices to find a cached power
-    // such that the exponent of the product lies in [alpha,gamma].
-    // This implies that the difference of the decimal exponents of adjacent
-    // table entries must be less than or equal to
-    //
-    //      floor( (gamma - alpha) * log_10(2) ) = 8.
-    //
-    // (A smaller distance gamma-alpha would require a larger table.)
-
-    // NB:
-    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
-
-    constexpr int kCachedPowersSize = 79;
-    constexpr int kCachedPowersMinDecExp = -300;
-    constexpr int kCachedPowersDecStep = 8;
-
-    static constexpr cached_power kCachedPowers[] =
-    {
-        { 0xAB70FE17C79AC6CA, -1060, -300 },
-        { 0xFF77B1FCBEBCDC4F, -1034, -292 },
-        { 0xBE5691EF416BD60C, -1007, -284 },
-        { 0x8DD01FAD907FFC3C,  -980, -276 },
-        { 0xD3515C2831559A83,  -954, -268 },
-        { 0x9D71AC8FADA6C9B5,  -927, -260 },
-        { 0xEA9C227723EE8BCB,  -901, -252 },
-        { 0xAECC49914078536D,  -874, -244 },
-        { 0x823C12795DB6CE57,  -847, -236 },
-        { 0xC21094364DFB5637,  -821, -228 },
-        { 0x9096EA6F3848984F,  -794, -220 },
-        { 0xD77485CB25823AC7,  -768, -212 },
-        { 0xA086CFCD97BF97F4,  -741, -204 },
-        { 0xEF340A98172AACE5,  -715, -196 },
-        { 0xB23867FB2A35B28E,  -688, -188 },
-        { 0x84C8D4DFD2C63F3B,  -661, -180 },
-        { 0xC5DD44271AD3CDBA,  -635, -172 },
-        { 0x936B9FCEBB25C996,  -608, -164 },
-        { 0xDBAC6C247D62A584,  -582, -156 },
-        { 0xA3AB66580D5FDAF6,  -555, -148 },
-        { 0xF3E2F893DEC3F126,  -529, -140 },
-        { 0xB5B5ADA8AAFF80B8,  -502, -132 },
-        { 0x87625F056C7C4A8B,  -475, -124 },
-        { 0xC9BCFF6034C13053,  -449, -116 },
-        { 0x964E858C91BA2655,  -422, -108 },
-        { 0xDFF9772470297EBD,  -396, -100 },
-        { 0xA6DFBD9FB8E5B88F,  -369,  -92 },
-        { 0xF8A95FCF88747D94,  -343,  -84 },
-        { 0xB94470938FA89BCF,  -316,  -76 },
-        { 0x8A08F0F8BF0F156B,  -289,  -68 },
-        { 0xCDB02555653131B6,  -263,  -60 },
-        { 0x993FE2C6D07B7FAC,  -236,  -52 },
-        { 0xE45C10C42A2B3B06,  -210,  -44 },
-        { 0xAA242499697392D3,  -183,  -36 },
-        { 0xFD87B5F28300CA0E,  -157,  -28 },
-        { 0xBCE5086492111AEB,  -130,  -20 },
-        { 0x8CBCCC096F5088CC,  -103,  -12 },
-        { 0xD1B71758E219652C,   -77,   -4 },
-        { 0x9C40000000000000,   -50,    4 },
-        { 0xE8D4A51000000000,   -24,   12 },
-        { 0xAD78EBC5AC620000,     3,   20 },
-        { 0x813F3978F8940984,    30,   28 },
-        { 0xC097CE7BC90715B3,    56,   36 },
-        { 0x8F7E32CE7BEA5C70,    83,   44 },
-        { 0xD5D238A4ABE98068,   109,   52 },
-        { 0x9F4F2726179A2245,   136,   60 },
-        { 0xED63A231D4C4FB27,   162,   68 },
-        { 0xB0DE65388CC8ADA8,   189,   76 },
-        { 0x83C7088E1AAB65DB,   216,   84 },
-        { 0xC45D1DF942711D9A,   242,   92 },
-        { 0x924D692CA61BE758,   269,  100 },
-        { 0xDA01EE641A708DEA,   295,  108 },
-        { 0xA26DA3999AEF774A,   322,  116 },
-        { 0xF209787BB47D6B85,   348,  124 },
-        { 0xB454E4A179DD1877,   375,  132 },
-        { 0x865B86925B9BC5C2,   402,  140 },
-        { 0xC83553C5C8965D3D,   428,  148 },
-        { 0x952AB45CFA97A0B3,   455,  156 },
-        { 0xDE469FBD99A05FE3,   481,  164 },
-        { 0xA59BC234DB398C25,   508,  172 },
-        { 0xF6C69A72A3989F5C,   534,  180 },
-        { 0xB7DCBF5354E9BECE,   561,  188 },
-        { 0x88FCF317F22241E2,   588,  196 },
-        { 0xCC20CE9BD35C78A5,   614,  204 },
-        { 0x98165AF37B2153DF,   641,  212 },
-        { 0xE2A0B5DC971F303A,   667,  220 },
-        { 0xA8D9D1535CE3B396,   694,  228 },
-        { 0xFB9B7CD9A4A7443C,   720,  236 },
-        { 0xBB764C4CA7A44410,   747,  244 },
-        { 0x8BAB8EEFB6409C1A,   774,  252 },
-        { 0xD01FEF10A657842C,   800,  260 },
-        { 0x9B10A4E5E9913129,   827,  268 },
-        { 0xE7109BFBA19C0C9D,   853,  276 },
-        { 0xAC2820D9623BF429,   880,  284 },
-        { 0x80444B5E7AA7CF85,   907,  292 },
-        { 0xBF21E44003ACDD2D,   933,  300 },
-        { 0x8E679C2F5E44FF8F,   960,  308 },
-        { 0xD433179D9C8CB841,   986,  316 },
-        { 0x9E19DB92B4E31BA9,  1013,  324 },
-    };
-
-    // This computation gives exactly the same results for k as
-    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)
-    // for |e| <= 1500, but doesn't require floating-point operations.
-    // NB: log_10(2) ~= 78913 / 2^18
-    assert(e >= -1500);
-    assert(e <=  1500);
-    const int f = kAlpha - e - 1;
-    const int k = (f * 78913) / (1 << 18) + (f > 0);
-
-    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
-    assert(index >= 0);
-    assert(index < kCachedPowersSize);
-    static_cast<void>(kCachedPowersSize); // Fix warning.
-
-    const cached_power cached = kCachedPowers[index];
-    assert(kAlpha <= cached.e + e + 64);
-    assert(kGamma >= cached.e + e + 64);
-
-    return cached;
-}
-
-/*!
-For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
-For n == 0, returns 1 and sets pow10 := 1.
-*/
-inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
-{
-    // LCOV_EXCL_START
-    if (n >= 1000000000)
-    {
-        pow10 = 1000000000;
-        return 10;
-    }
-    // LCOV_EXCL_STOP
-    else if (n >= 100000000)
-    {
-        pow10 = 100000000;
-        return  9;
-    }
-    else if (n >= 10000000)
-    {
-        pow10 = 10000000;
-        return  8;
-    }
-    else if (n >= 1000000)
-    {
-        pow10 = 1000000;
-        return  7;
-    }
-    else if (n >= 100000)
-    {
-        pow10 = 100000;
-        return  6;
-    }
-    else if (n >= 10000)
-    {
-        pow10 = 10000;
-        return  5;
-    }
-    else if (n >= 1000)
-    {
-        pow10 = 1000;
-        return  4;
-    }
-    else if (n >= 100)
-    {
-        pow10 = 100;
-        return  3;
-    }
-    else if (n >= 10)
-    {
-        pow10 = 10;
-        return  2;
-    }
-    else
-    {
-        pow10 = 1;
-        return 1;
-    }
-}
-
-inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,
-                         uint64_t rest, uint64_t ten_k)
-{
-    assert(len >= 1);
-    assert(dist <= delta);
-    assert(rest <= delta);
-    assert(ten_k > 0);
-
-    //               <--------------------------- delta ---->
-    //                                  <---- dist --------->
-    // --------------[------------------+-------------------]--------------
-    //               M-                 w                   M+
-    //
-    //                                  ten_k
-    //                                <------>
-    //                                       <---- rest ---->
-    // --------------[------------------+----+--------------]--------------
-    //                                  w    V
-    //                                       = buf * 10^k
-    //
-    // ten_k represents a unit-in-the-last-place in the decimal representation
-    // stored in buf.
-    // Decrement buf by ten_k while this takes buf closer to w.
-
-    // The tests are written in this order to avoid overflow in unsigned
-    // integer arithmetic.
-
-    while (rest < dist
-            and delta - rest >= ten_k
-            and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))
-    {
-        assert(buf[len - 1] != '0');
-        buf[len - 1]--;
-        rest += ten_k;
-    }
-}
-
-/*!
-Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
-M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
-*/
-inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
-                             diyfp M_minus, diyfp w, diyfp M_plus)
-{
-    static_assert(kAlpha >= -60, "internal error");
-    static_assert(kGamma <= -32, "internal error");
-
-    // Generates the digits (and the exponent) of a decimal floating-point
-    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
-    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
-    //
-    //               <--------------------------- delta ---->
-    //                                  <---- dist --------->
-    // --------------[------------------+-------------------]--------------
-    //               M-                 w                   M+
-    //
-    // Grisu2 generates the digits of M+ from left to right and stops as soon as
-    // V is in [M-,M+].
-
-    assert(M_plus.e >= kAlpha);
-    assert(M_plus.e <= kGamma);
-
-    uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
-    uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)
-
-    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
-    //
-    //      M+ = f * 2^e
-    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
-    //         = ((p1        ) * 2^-e + (p2        )) * 2^e
-    //         = p1 + p2 * 2^e
-
-    const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e);
-
-    uint32_t p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
-    uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e
-
-    // 1)
-    //
-    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
-
-    assert(p1 > 0);
-
-    uint32_t pow10;
-    const int k = find_largest_pow10(p1, pow10);
-
-    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
-    //
-    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
-    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))
-    //
-    //      M+ = p1                                             + p2 * 2^e
-    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e
-    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
-    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e
-    //
-    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
-    //
-    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
-    //
-    // but stop as soon as
-    //
-    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
-
-    int n = k;
-    while (n > 0)
-    {
-        // Invariants:
-        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)
-        //      pow10 = 10^(n-1) <= p1 < 10^n
-        //
-        const uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)
-        const uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)
-        //
-        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
-        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
-        //
-        assert(d <= 9);
-        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
-        //
-        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
-        //
-        p1 = r;
-        n--;
-        //
-        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)
-        //      pow10 = 10^n
-        //
-
-        // Now check if enough digits have been generated.
-        // Compute
-        //
-        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
-        //
-        // Note:
-        // Since rest and delta share the same exponent e, it suffices to
-        // compare the significands.
-        const uint64_t rest = (uint64_t{p1} << -one.e) + p2;
-        if (rest <= delta)
-        {
-            // V = buffer * 10^n, with M- <= V <= M+.
-
-            decimal_exponent += n;
-
-            // We may now just stop. But instead look if the buffer could be
-            // decremented to bring V closer to w.
-            //
-            // pow10 = 10^n is now 1 ulp in the decimal representation V.
-            // The rounding procedure works with diyfp's with an implicit
-            // exponent of e.
-            //
-            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
-            //
-            const uint64_t ten_n = uint64_t{pow10} << -one.e;
-            grisu2_round(buffer, length, dist, delta, rest, ten_n);
-
-            return;
-        }
-
-        pow10 /= 10;
-        //
-        //      pow10 = 10^(n-1) <= p1 < 10^n
-        // Invariants restored.
-    }
-
-    // 2)
-    //
-    // The digits of the integral part have been generated:
-    //
-    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e
-    //         = buffer            + p2 * 2^e
-    //
-    // Now generate the digits of the fractional part p2 * 2^e.
-    //
-    // Note:
-    // No decimal point is generated: the exponent is adjusted instead.
-    //
-    // p2 actually represents the fraction
-    //
-    //      p2 * 2^e
-    //          = p2 / 2^-e
-    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...
-    //
-    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
-    //
-    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
-    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
-    //
-    // using
-    //
-    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
-    //                = (                   d) * 2^-e + (                   r)
-    //
-    // or
-    //      10^m * p2 * 2^e = d + r * 2^e
-    //
-    // i.e.
-    //
-    //      M+ = buffer + p2 * 2^e
-    //         = buffer + 10^-m * (d + r * 2^e)
-    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
-    //
-    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
-
-    assert(p2 > delta);
-
-    int m = 0;
-    for (;;)
-    {
-        // Invariant:
-        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
-        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e
-        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e
-        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
-        //
-        assert(p2 <= UINT64_MAX / 10);
-        p2 *= 10;
-        const uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e
-        const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
-        //
-        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
-        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
-        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
-        //
-        assert(d <= 9);
-        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
-        //
-        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
-        //
-        p2 = r;
-        m++;
-        //
-        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e
-        // Invariant restored.
-
-        // Check if enough digits have been generated.
-        //
-        //      10^-m * p2 * 2^e <= delta * 2^e
-        //              p2 * 2^e <= 10^m * delta * 2^e
-        //                    p2 <= 10^m * delta
-        delta *= 10;
-        dist  *= 10;
-        if (p2 <= delta)
-        {
-            break;
-        }
-    }
-
-    // V = buffer * 10^-m, with M- <= V <= M+.
-
-    decimal_exponent -= m;
-
-    // 1 ulp in the decimal representation is now 10^-m.
-    // Since delta and dist are now scaled by 10^m, we need to do the
-    // same with ulp in order to keep the units in sync.
-    //
-    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
-    //
-    const uint64_t ten_m = one.f;
-    grisu2_round(buffer, length, dist, delta, p2, ten_m);
-
-    // By construction this algorithm generates the shortest possible decimal
-    // number (Loitsch, Theorem 6.2) which rounds back to w.
-    // For an input number of precision p, at least
-    //
-    //      N = 1 + ceil(p * log_10(2))
-    //
-    // decimal digits are sufficient to identify all binary floating-point
-    // numbers (Matula, "In-and-Out conversions").
-    // This implies that the algorithm does not produce more than N decimal
-    // digits.
-    //
-    //      N = 17 for p = 53 (IEEE double precision)
-    //      N = 9  for p = 24 (IEEE single precision)
-}
-
-/*!
-v = buf * 10^decimal_exponent
-len is the length of the buffer (number of decimal digits)
-The buffer must be large enough, i.e. >= max_digits10.
-*/
-inline void grisu2(char* buf, int& len, int& decimal_exponent,
-                   diyfp m_minus, diyfp v, diyfp m_plus)
-{
-    assert(m_plus.e == m_minus.e);
-    assert(m_plus.e == v.e);
-
-    //  --------(-----------------------+-----------------------)--------    (A)
-    //          m-                      v                       m+
-    //
-    //  --------------------(-----------+-----------------------)--------    (B)
-    //                      m-          v                       m+
-    //
-    // First scale v (and m- and m+) such that the exponent is in the range
-    // [alpha, gamma].
-
-    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
-
-    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
-
-    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
-    const diyfp w       = diyfp::mul(v,       c_minus_k);
-    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
-    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);
-
-    //  ----(---+---)---------------(---+---)---------------(---+---)----
-    //          w-                      w                       w+
-    //          = c*m-                  = c*v                   = c*m+
-    //
-    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
-    // w+ are now off by a small amount.
-    // In fact:
-    //
-    //      w - v * 10^k < 1 ulp
-    //
-    // To account for this inaccuracy, add resp. subtract 1 ulp.
-    //
-    //  --------+---[---------------(---+---)---------------]---+--------
-    //          w-  M-                  w                   M+  w+
-    //
-    // Now any number in [M-, M+] (bounds included) will round to w when input,
-    // regardless of how the input rounding algorithm breaks ties.
-    //
-    // And digit_gen generates the shortest possible such number in [M-, M+].
-    // Note that this does not mean that Grisu2 always generates the shortest
-    // possible number in the interval (m-, m+).
-    const diyfp M_minus(w_minus.f + 1, w_minus.e);
-    const diyfp M_plus (w_plus.f  - 1, w_plus.e );
-
-    decimal_exponent = -cached.k; // = -(-k) = k
-
-    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
-}
-
-/*!
-v = buf * 10^decimal_exponent
-len is the length of the buffer (number of decimal digits)
-The buffer must be large enough, i.e. >= max_digits10.
-*/
-template <typename FloatType>
-void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
-{
-    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
-                  "internal error: not enough precision");
-
-    assert(std::isfinite(value));
-    assert(value > 0);
-
-    // If the neighbors (and boundaries) of 'value' are always computed for double-precision
-    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
-    // decimal representations are not exactly "short".
-    //
-    // The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars)
-    // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
-    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
-    // does.
-    // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
-    // representation using the corresponding std::from_chars function recovers value exactly". That
-    // indicates that single precision floating-point numbers should be recovered using
-    // 'std::strtof'.
-    //
-    // NB: If the neighbors are computed for single-precision numbers, there is a single float
-    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
-    //     value is off by 1 ulp.
-#if 0
-    const boundaries w = compute_boundaries(static_cast<double>(value));
-#else
-    const boundaries w = compute_boundaries(value);
-#endif
-
-    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
-}
-
-/*!
-@brief appends a decimal representation of e to buf
-@return a pointer to the element following the exponent.
-@pre -1000 < e < 1000
-*/
-inline char* append_exponent(char* buf, int e)
-{
-    assert(e > -1000);
-    assert(e <  1000);
-
-    if (e < 0)
-    {
-        e = -e;
-        *buf++ = '-';
-    }
-    else
-    {
-        *buf++ = '+';
-    }
-
-    uint32_t k = static_cast<uint32_t>(e);
-    if (k < 10)
-    {
-        // Always print at least two digits in the exponent.
-        // This is for compatibility with printf("%g").
-        *buf++ = '0';
-        *buf++ = static_cast<char>('0' + k);
-    }
-    else if (k < 100)
-    {
-        *buf++ = static_cast<char>('0' + k / 10);
-        k %= 10;
-        *buf++ = static_cast<char>('0' + k);
-    }
-    else
-    {
-        *buf++ = static_cast<char>('0' + k / 100);
-        k %= 100;
-        *buf++ = static_cast<char>('0' + k / 10);
-        k %= 10;
-        *buf++ = static_cast<char>('0' + k);
-    }
-
-    return buf;
-}
-
-/*!
-@brief prettify v = buf * 10^decimal_exponent
-
-If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
-notation. Otherwise it will be printed in exponential notation.
-
-@pre min_exp < 0
-@pre max_exp > 0
-*/
-inline char* format_buffer(char* buf, int len, int decimal_exponent,
-                           int min_exp, int max_exp)
-{
-    assert(min_exp < 0);
-    assert(max_exp > 0);
-
-    const int k = len;
-    const int n = len + decimal_exponent;
-
-    // v = buf * 10^(n-k)
-    // k is the length of the buffer (number of decimal digits)
-    // n is the position of the decimal point relative to the start of the buffer.
-
-    if (k <= n and n <= max_exp)
-    {
-        // digits[000]
-        // len <= max_exp + 2
-
-        std::memset(buf + k, '0', static_cast<size_t>(n - k));
-        // Make it look like a floating-point number (#362, #378)
-        buf[n + 0] = '.';
-        buf[n + 1] = '0';
-        return buf + (n + 2);
-    }
-
-    if (0 < n and n <= max_exp)
-    {
-        // dig.its
-        // len <= max_digits10 + 1
-
-        assert(k > n);
-
-        std::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));
-        buf[n] = '.';
-        return buf + (k + 1);
-    }
-
-    if (min_exp < n and n <= 0)
-    {
-        // 0.[000]digits
-        // len <= 2 + (-min_exp - 1) + max_digits10
-
-        std::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));
-        buf[0] = '0';
-        buf[1] = '.';
-        std::memset(buf + 2, '0', static_cast<size_t>(-n));
-        return buf + (2 + (-n) + k);
-    }
-
-    if (k == 1)
-    {
-        // dE+123
-        // len <= 1 + 5
-
-        buf += 1;
-    }
-    else
-    {
-        // d.igitsE+123
-        // len <= max_digits10 + 1 + 5
-
-        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));
-        buf[1] = '.';
-        buf += 1 + k;
-    }
-
-    *buf++ = 'e';
-    return append_exponent(buf, n - 1);
-}
-
-} // namespace dtoa_impl
-
-/*!
-@brief generates a decimal representation of the floating-point number value in [first, last).
-
-The format of the resulting decimal representation is similar to printf's %g
-format. Returns an iterator pointing past-the-end of the decimal representation.
-
-@note The input number must be finite, i.e. NaN's and Inf's are not supported.
-@note The buffer must be large enough.
-@note The result is NOT null-terminated.
-*/
-template <typename FloatType>
-char* to_chars(char* first, char* last, FloatType value)
-{
-    static_cast<void>(last); // maybe unused - fix warning
-    assert(std::isfinite(value));
-
-    // Use signbit(value) instead of (value < 0) since signbit works for -0.
-    if (std::signbit(value))
-    {
-        value = -value;
-        *first++ = '-';
-    }
-
-    if (value == 0) // +-0
-    {
-        *first++ = '0';
-        // Make it look like a floating-point number (#362, #378)
-        *first++ = '.';
-        *first++ = '0';
-        return first;
-    }
-
-    assert(last - first >= std::numeric_limits<FloatType>::max_digits10);
-
-    // Compute v = buffer * 10^decimal_exponent.
-    // The decimal digits are stored in the buffer, which needs to be interpreted
-    // as an unsigned decimal integer.
-    // len is the length of the buffer, i.e. the number of decimal digits.
-    int len = 0;
-    int decimal_exponent = 0;
-    dtoa_impl::grisu2(first, len, decimal_exponent, value);
-
-    assert(len <= std::numeric_limits<FloatType>::max_digits10);
-
-    // Format the buffer like printf("%.*g", prec, value)
-    constexpr int kMinExp = -4;
-    // Use digits10 here to increase compatibility with version 2.
-    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
-
-    assert(last - first >= kMaxExp + 2);
-    assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
-    assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
-
-    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
-}
-
-}  // namespace
-
-void json::serializer::dump(const json& val, const bool pretty_print,
-          const bool ensure_ascii,
-          const unsigned int indent_step,
-          const unsigned int current_indent)
-{
-    switch (val.m_type)
-    {
-        case value_t::object:
-        {
-            if (val.m_value.object->empty())
-            {
-                o << "{}";
-                return;
-            }
-
-            // we need to iterate over the object values in sorted key order
-            SmallVector<StringMapConstIterator<json>, 64> sorted;
-            for (auto i = val.m_value.object->begin(),
-                 end = val.m_value.object->end(); i != end; ++i)
-            {
-                sorted.push_back(i);
-            }
-            std::sort(sorted.begin(), sorted.end(),
-                      [](const StringMapConstIterator<json>& a,
-                         const StringMapConstIterator<json>& b) {
-                        return a->getKey() < b->getKey();
-                      });
-
-            if (pretty_print)
-            {
-                o << "{\n";
-
-                // variable to hold indentation for recursive calls
-                const auto new_indent = current_indent + indent_step;
-                if (JSON_UNLIKELY(indent_string.size() < new_indent))
-                {
-                    indent_string.resize(indent_string.size() * 2, indent_char);
-                }
-
-                // first n-1 elements
-                auto i = sorted.begin();
-                for (std::size_t cnt = 0; cnt < sorted.size() - 1; ++cnt, ++i)
-                {
-                    o.write(indent_string.c_str(), new_indent);
-                    o << '\"';
-                    dump_escaped((*i)->first(), ensure_ascii);
-                    o << "\": ";
-                    dump((*i)->second, true, ensure_ascii, indent_step, new_indent);
-                    o << ",\n";
-                }
-
-                // last element
-                assert(i != sorted.end());
-                //assert(std::next(i) == val.m_value.object->end());
-                o.write(indent_string.c_str(), new_indent);
-                o << '\"';
-                dump_escaped((*i)->first(), ensure_ascii);
-                o << "\": ";
-                dump((*i)->second, true, ensure_ascii, indent_step, new_indent);
-
-                o << '\n';
-                o.write(indent_string.c_str(), current_indent);
-                o << '}';
-            }
-            else
-            {
-                o << '{';
-
-                // first n-1 elements
-                auto i = sorted.begin();
-                for (std::size_t cnt = 0; cnt < sorted.size() - 1; ++cnt, ++i)
-                {
-                    o << '\"';
-                    dump_escaped((*i)->first(), ensure_ascii);
-                    o << "\":";
-                    dump((*i)->second, false, ensure_ascii, indent_step, current_indent);
-                    o << ',';
-                }
-
-                // last element
-                assert(i != sorted.end());
-                //assert(std::next(i) == val.m_value.object->end());
-                o << '\"';
-                dump_escaped((*i)->first(), ensure_ascii);
-                o << "\":";
-                dump((*i)->second, false, ensure_ascii, indent_step, current_indent);
-
-                o << '}';
-            }
-
-            return;
-        }
-
-        case value_t::array:
-        {
-            if (val.m_value.array->empty())
-            {
-                o << "[]";
-                return;
-            }
-
-            if (pretty_print)
-            {
-                o << "[\n";
-
-                // variable to hold indentation for recursive calls
-                const auto new_indent = current_indent + indent_step;
-                if (JSON_UNLIKELY(indent_string.size() < new_indent))
-                {
-                    indent_string.resize(indent_string.size() * 2, indent_char);
-                }
-
-                // first n-1 elements
-                for (auto i = val.m_value.array->cbegin();
-                        i != val.m_value.array->cend() - 1; ++i)
-                {
-                    o.write(indent_string.c_str(), new_indent);
-                    dump(*i, true, ensure_ascii, indent_step, new_indent);
-                    o << ",\n";
-                }
-
-                // last element
-                assert(not val.m_value.array->empty());
-                o.write(indent_string.c_str(), new_indent);
-                dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
-
-                o << '\n';
-                o.write(indent_string.c_str(), current_indent);
-                o << ']';
-            }
-            else
-            {
-                o << '[';
-
-                // first n-1 elements
-                for (auto i = val.m_value.array->cbegin();
-                        i != val.m_value.array->cend() - 1; ++i)
-                {
-                    dump(*i, false, ensure_ascii, indent_step, current_indent);
-                    o << ',';
-                }
-
-                // last element
-                assert(not val.m_value.array->empty());
-                dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
-
-                o << ']';
-            }
-
-            return;
-        }
-
-        case value_t::string:
-        {
-            o << '\"';
-            dump_escaped(*val.m_value.string, ensure_ascii);
-            o << '\"';
-            return;
-        }
-
-        case value_t::boolean:
-        {
-            if (val.m_value.boolean)
-            {
-                o << "true";
-            }
-            else
-            {
-                o << "false";
-            }
-            return;
-        }
-
-        case value_t::number_integer:
-        {
-            dump_integer(val.m_value.number_integer);
-            return;
-        }
-
-        case value_t::number_unsigned:
-        {
-            dump_integer(val.m_value.number_unsigned);
-            return;
-        }
-
-        case value_t::number_float:
-        {
-            dump_float(val.m_value.number_float);
-            return;
-        }
-
-        case value_t::discarded:
-        {
-            o << "<discarded>";
-            return;
-        }
-
-        case value_t::null:
-        {
-            o << "null";
-            return;
-        }
-    }
-}
-
-void json::serializer::dump_escaped(std::string_view s, const bool ensure_ascii)
-{
-    uint32_t codepoint;
-    uint8_t state = UTF8_ACCEPT;
-
-    for (std::size_t i = 0; i < s.size(); ++i)
-    {
-        const auto byte = static_cast<uint8_t>(s[i]);
-
-        switch (decode(state, codepoint, byte))
-        {
-            case UTF8_ACCEPT:  // decode found a new code point
-            {
-                switch (codepoint)
-                {
-                    case 0x08: // backspace
-                    {
-                        o << '\\' << 'b';
-                        break;
-                    }
-
-                    case 0x09: // horizontal tab
-                    {
-                        o << '\\' << 't';
-                        break;
-                    }
-
-                    case 0x0A: // newline
-                    {
-                        o << '\\' << 'n';
-                        break;
-                    }
-
-                    case 0x0C: // formfeed
-                    {
-                        o << '\\' << 'f';
-                        break;
-                    }
-
-                    case 0x0D: // carriage return
-                    {
-                        o << '\\' << 'r';
-                        break;
-                    }
-
-                    case 0x22: // quotation mark
-                    {
-                        o << '\\' << '\"';
-                        break;
-                    }
-
-                    case 0x5C: // reverse solidus
-                    {
-                        o << '\\' << '\\';
-                        break;
-                    }
-
-                    default:
-                    {
-                        // escape control characters (0x00..0x1F) or, if
-                        // ensure_ascii parameter is used, non-ASCII characters
-                        if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))
-                        {
-                            if (codepoint <= 0xFFFF)
-                            {
-                                o << fmt::format("\\u{:04x}", codepoint);
-                            }
-                            else
-                            {
-                                o << fmt::format("\\u{:04x}", 0xD7C0 + (codepoint >> 10));
-                                o << fmt::format("\\u{:04x}", 0xDC00 + (codepoint & 0x3FF));
-                            }
-                        }
-                        else
-                        {
-                            // copy byte to buffer (all previous bytes
-                            // been copied have in default case above)
-                            o << s[i];
-                        }
-                        break;
-                    }
-                }
-                break;
-            }
-
-            case UTF8_REJECT:  // decode found invalid UTF-8 byte
-            {
-                JSON_THROW(type_error::create(316, fmt::format("invalid UTF-8 byte at index {}: {:#02x}", i, byte)));
-            }
-
-            default:  // decode found yet incomplete multi-byte code point
-            {
-                if (not ensure_ascii)
-                {
-                    // code point will not be escaped - copy byte to buffer
-                    o << s[i];
-                }
-                break;
-            }
-        }
-    }
-
-    if (JSON_UNLIKELY(state != UTF8_ACCEPT))
-    {
-        // we finish reading, but do not accept: string was incomplete
-        JSON_THROW(type_error::create(316, fmt::format("incomplete UTF-8 string; last byte: {:#02x}", s.back())));
-    }
-}
-
-void json::serializer::dump_float(double x)
-{
-    // NaN / inf
-    if (not std::isfinite(x))
-    {
-        o << "null";
-        return;
-    }
-
-    // use the Grisu2 algorithm to produce short numbers which are
-    // guaranteed to round-trip, using strtof and strtod, resp.
-    char* begin = number_buffer.data();
-    char* end = to_chars(begin, begin + number_buffer.size(), x);
-
-    o.write(begin, static_cast<size_t>(end - begin));
-}
-
-uint8_t json::serializer::decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept
-{
-    static const std::array<uint8_t, 400> utf8d =
-    {
-        {
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
-            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
-            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
-            8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
-            0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
-            0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
-            0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
-            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
-            1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
-            1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
-            1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
-        }
-    };
-
-    const uint8_t type = utf8d[byte];
-
-    codep = (state != UTF8_ACCEPT)
-            ? (byte & 0x3fu) | (codep << 6)
-            : static_cast<uint32_t>(0xff >> type) & (byte);
-
-    state = utf8d[256u + state * 16u + type];
-    return state;
-}
-
-std::string json::dump(const int indent, const char indent_char,
-                 const bool ensure_ascii) const
-{
-    std::string result;
-    raw_string_ostream os(result);
-    dump(os, indent, indent_char, ensure_ascii);
-    return result;
-}
-
-void json::dump(raw_ostream& os, int indent, const char indent_char,
-          const bool ensure_ascii) const
-{
-    serializer s(os, indent_char);
-
-    if (indent >= 0)
-    {
-        s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
-    }
-    else
-    {
-        s.dump(*this, false, ensure_ascii, 0);
-    }
-
-    os.flush();
-}
-
-raw_ostream& operator<<(raw_ostream& o, const json& j)
-{
-    j.dump(o, 0);
-    return o;
-}
-
-std::ostream& operator<<(std::ostream& o, const json& j)
-{
-    raw_os_ostream os(o);
-    j.dump(os, 0);
-    return o;
-}
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/adl_serializer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/adl_serializer.h
new file mode 100644
index 0000000..ad339bc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/adl_serializer.h
@@ -0,0 +1,55 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <utility>
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/conversions/from_json.h>
+#include <wpi/detail/conversions/to_json.h>
+#include <wpi/detail/meta/identity_tag.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+/// @sa https://json.nlohmann.me/api/adl_serializer/
+template<typename ValueType, typename>
+struct adl_serializer
+{
+    /// @brief convert a JSON value to any value type
+    /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
+    template<typename BasicJsonType, typename TargetType = ValueType>
+    static auto from_json(BasicJsonType && j, TargetType& val) noexcept(
+        noexcept(::wpi::from_json(std::forward<BasicJsonType>(j), val)))
+    -> decltype(::wpi::from_json(std::forward<BasicJsonType>(j), val), void())
+    {
+        ::wpi::from_json(std::forward<BasicJsonType>(j), val);
+    }
+
+    /// @brief convert a JSON value to any value type
+    /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
+    template<typename BasicJsonType, typename TargetType = ValueType>
+    static auto from_json(BasicJsonType && j) noexcept(
+    noexcept(::wpi::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))
+    -> decltype(::wpi::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))
+    {
+        return ::wpi::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});
+    }
+
+    /// @brief convert any value type to a JSON value
+    /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/
+    template<typename BasicJsonType, typename TargetType = ValueType>
+    static auto to_json(BasicJsonType& j, TargetType && val) noexcept(
+        noexcept(::wpi::to_json(j, std::forward<TargetType>(val))))
+    -> decltype(::wpi::to_json(j, std::forward<TargetType>(val)), void())
+    {
+        ::wpi::to_json(j, std::forward<TargetType>(val));
+    }
+};
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/byte_container_with_subtype.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/byte_container_with_subtype.h
new file mode 100644
index 0000000..f97a2a7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/byte_container_with_subtype.h
@@ -0,0 +1,103 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstdint> // uint8_t, uint64_t
+#include <tuple> // tie
+#include <utility> // move
+
+#include <wpi/detail/abi_macros.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+/// @brief an internal type for a backed binary type
+/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/
+template<typename BinaryType>
+class byte_container_with_subtype : public BinaryType
+{
+  public:
+    using container_type = BinaryType;
+    using subtype_type = std::uint64_t;
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype() noexcept(noexcept(container_type()))
+        : container_type()
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))
+        : container_type(b)
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))
+        : container_type(std::move(b))
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
+        : container_type(b)
+        , m_subtype(subtype_)
+        , m_has_subtype(true)
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
+        : container_type(std::move(b))
+        , m_subtype(subtype_)
+        , m_has_subtype(true)
+    {}
+
+    bool operator==(const byte_container_with_subtype& rhs) const
+    {
+        return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
+               std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
+    }
+
+    bool operator!=(const byte_container_with_subtype& rhs) const
+    {
+        return !(rhs == *this);
+    }
+
+    /// @brief sets the binary subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/
+    void set_subtype(subtype_type subtype_) noexcept
+    {
+        m_subtype = subtype_;
+        m_has_subtype = true;
+    }
+
+    /// @brief return the binary subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/
+    constexpr subtype_type subtype() const noexcept
+    {
+        return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1);
+    }
+
+    /// @brief return whether the value has a subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/
+    constexpr bool has_subtype() const noexcept
+    {
+        return m_has_subtype;
+    }
+
+    /// @brief clears the binary subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/
+    void clear_subtype() noexcept
+    {
+        m_subtype = 0;
+        m_has_subtype = false;
+    }
+
+  private:
+    subtype_type m_subtype = 0;
+    bool m_has_subtype = false;
+};
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/abi_macros.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/abi_macros.h
new file mode 100644
index 0000000..438af89
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/abi_macros.h
@@ -0,0 +1,61 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+// This file contains all macro definitions affecting or depending on the ABI
+
+#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
+    #if defined(WPI_JSON_VERSION_MAJOR) && defined(WPI_JSON_VERSION_MINOR) && defined(WPI_JSON_VERSION_PATCH)
+        #if WPI_JSON_VERSION_MAJOR != 3 || WPI_JSON_VERSION_MINOR != 11 || WPI_JSON_VERSION_PATCH != 2
+            #warning "Already included a different version of the library!"
+        #endif
+    #endif
+#endif
+
+#define WPI_JSON_VERSION_MAJOR 3   // NOLINT(modernize-macro-to-enum)
+#define WPI_JSON_VERSION_MINOR 11  // NOLINT(modernize-macro-to-enum)
+#define WPI_JSON_VERSION_PATCH 2   // NOLINT(modernize-macro-to-enum)
+
+#ifndef JSON_DIAGNOSTICS
+    #define JSON_DIAGNOSTICS 0
+#endif
+
+#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
+#endif
+
+#if JSON_DIAGNOSTICS
+    #define WPI_JSON_ABI_TAG_DIAGNOSTICS _diag
+#else
+    #define WPI_JSON_ABI_TAG_DIAGNOSTICS
+#endif
+
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    #define WPI_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
+#else
+    #define WPI_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
+#endif
+
+#ifndef WPI_JSON_NAMESPACE
+#define WPI_JSON_NAMESPACE               \
+    wpi::WPI_JSON_NAMESPACE_CONCAT( \
+            WPI_JSON_ABI_TAGS,           \
+            WPI_JSON_NAMESPACE_VERSION)
+#endif
+
+#ifndef WPI_JSON_NAMESPACE_BEGIN
+#define WPI_JSON_NAMESPACE_BEGIN \
+    namespace wpi                \
+    {
+#endif
+
+#ifndef WPI_JSON_NAMESPACE_END
+#define WPI_JSON_NAMESPACE_END \
+    }  // namespace wpi
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/from_json.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/from_json.h
new file mode 100644
index 0000000..f232f23
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/from_json.h
@@ -0,0 +1,497 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // transform
+#include <array> // array
+#include <forward_list> // forward_list
+#include <iterator> // inserter, front_inserter, end
+#include <map> // map
+#include <string> // string
+#include <tuple> // tuple, make_tuple
+#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
+#include <unordered_map> // unordered_map
+#include <utility> // pair, declval
+#include <valarray> // valarray
+
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/identity_tag.h>
+#include <wpi/detail/meta/std_fs.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/string_concat.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
+    }
+    n = nullptr;
+}
+
+// overloads for basic_json template parameters
+template < typename BasicJsonType, typename ArithmeticType,
+           enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
+                         !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
+                         int > = 0 >
+void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
+{
+    switch (static_cast<value_t>(j))
+    {
+        case value_t::number_unsigned:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
+            break;
+        }
+        case value_t::number_integer:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
+            break;
+        }
+        case value_t::number_float:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
+            break;
+        }
+
+        case value_t::null:
+        case value_t::object:
+        case value_t::array:
+        case value_t::string:
+        case value_t::boolean:
+        case value_t::binary:
+        case value_t::discarded:
+        default:
+            JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
+    }
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
+    }
+    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
+    }
+    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
+}
+
+template <
+    typename BasicJsonType, typename StringType,
+    enable_if_t <
+        std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
+        && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
+        && !std::is_same<typename BasicJsonType::string_t, StringType>::value
+        && !is_json_ref<StringType>::value, int > = 0 >
+inline void from_json(const BasicJsonType& j, StringType& s)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
+    }
+
+    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
+{
+    get_arithmetic_value(j, val);
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
+{
+    get_arithmetic_value(j, val);
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
+{
+    get_arithmetic_value(j, val);
+}
+
+#if !JSON_DISABLE_ENUM_SERIALIZATION
+template<typename BasicJsonType, typename EnumType,
+         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, EnumType& e)
+{
+    typename std::underlying_type<EnumType>::type val;
+    get_arithmetic_value(j, val);
+    e = static_cast<EnumType>(val);
+}
+#endif  // JSON_DISABLE_ENUM_SERIALIZATION
+
+// forward_list doesn't have an insert method
+template<typename BasicJsonType, typename T, typename Allocator,
+         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    l.clear();
+    std::transform(j.rbegin(), j.rend(),
+                   std::front_inserter(l), [](const BasicJsonType & i)
+    {
+        return i.template get<T>();
+    });
+}
+
+// valarray doesn't have an insert method
+template<typename BasicJsonType, typename T,
+         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    l.resize(j.size());
+    std::transform(j.begin(), j.end(), std::begin(l),
+                   [](const BasicJsonType & elem)
+    {
+        return elem.template get<T>();
+    });
+}
+
+template<typename BasicJsonType, typename T, std::size_t N>
+auto from_json(const BasicJsonType& j, T (&arr)[N])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+-> decltype(j.template get<T>(), void())
+{
+    for (std::size_t i = 0; i < N; ++i)
+    {
+        arr[i] = j.at(i).template get<T>();
+    }
+}
+
+template<typename BasicJsonType>
+inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
+{
+    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
+}
+
+template<typename BasicJsonType, typename T, std::size_t N>
+auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
+                          priority_tag<2> /*unused*/)
+-> decltype(j.template get<T>(), void())
+{
+    for (std::size_t i = 0; i < N; ++i)
+    {
+        arr[i] = j.at(i).template get<T>();
+    }
+}
+
+template<typename BasicJsonType, typename ConstructibleArrayType,
+         enable_if_t<
+             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
+             int> = 0>
+auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
+-> decltype(
+    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
+    j.template get<typename ConstructibleArrayType::value_type>(),
+    void())
+{
+    using std::end;
+
+    ConstructibleArrayType ret;
+    ret.reserve(j.size());
+    std::transform(j.begin(), j.end(),
+                   std::inserter(ret, end(ret)), [](const BasicJsonType & i)
+    {
+        // get<BasicJsonType>() returns *this, this won't call a from_json
+        // method when value_type is BasicJsonType
+        return i.template get<typename ConstructibleArrayType::value_type>();
+    });
+    arr = std::move(ret);
+}
+
+template<typename BasicJsonType, typename ConstructibleArrayType,
+         enable_if_t<
+             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
+             int> = 0>
+inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
+                                 priority_tag<0> /*unused*/)
+{
+    using std::end;
+
+    ConstructibleArrayType ret;
+    std::transform(
+        j.begin(), j.end(), std::inserter(ret, end(ret)),
+        [](const BasicJsonType & i)
+    {
+        // get<BasicJsonType>() returns *this, this won't call a from_json
+        // method when value_type is BasicJsonType
+        return i.template get<typename ConstructibleArrayType::value_type>();
+    });
+    arr = std::move(ret);
+}
+
+template < typename BasicJsonType, typename ConstructibleArrayType,
+           enable_if_t <
+               is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
+               !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
+               !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
+               !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
+               !is_basic_json<ConstructibleArrayType>::value,
+               int > = 0 >
+auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
+-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
+j.template get<typename ConstructibleArrayType::value_type>(),
+void())
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+
+    from_json_array_impl(j, arr, priority_tag<3> {});
+}
+
+template < typename BasicJsonType, typename T, std::size_t... Idx >
+std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
+        identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)
+{
+    return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };
+}
+
+template < typename BasicJsonType, typename T, std::size_t N >
+auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
+-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+
+    return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
+    }
+
+    bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
+}
+
+template<typename BasicJsonType, typename ConstructibleObjectType,
+         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
+    }
+
+    ConstructibleObjectType ret;
+    const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
+    using value_type = typename ConstructibleObjectType::value_type;
+    std::transform(
+        inner_object->begin(), inner_object->end(),
+        std::inserter(ret, ret.begin()),
+        [](typename BasicJsonType::object_t::value_type const & p)
+    {
+        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
+    });
+    obj = std::move(ret);
+}
+
+// overload for arithmetic types, not chosen for basic_json template arguments
+// (BooleanType, etc..); note: Is it really necessary to provide explicit
+// overloads for boolean_t etc. in case of a custom BooleanType which is not
+// an arithmetic type?
+template < typename BasicJsonType, typename ArithmeticType,
+           enable_if_t <
+               std::is_arithmetic<ArithmeticType>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
+               int > = 0 >
+inline void from_json(const BasicJsonType& j, ArithmeticType& val)
+{
+    switch (static_cast<value_t>(j))
+    {
+        case value_t::number_unsigned:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
+            break;
+        }
+        case value_t::number_integer:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
+            break;
+        }
+        case value_t::number_float:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
+            break;
+        }
+        case value_t::boolean:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
+            break;
+        }
+
+        case value_t::null:
+        case value_t::object:
+        case value_t::array:
+        case value_t::string:
+        case value_t::binary:
+        case value_t::discarded:
+        default:
+            JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
+    }
+}
+
+template<typename BasicJsonType, typename... Args, std::size_t... Idx>
+std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
+{
+    return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
+}
+
+template < typename BasicJsonType, class A1, class A2 >
+std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
+{
+    return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
+            std::forward<BasicJsonType>(j).at(1).template get<A2>()};
+}
+
+template<typename BasicJsonType, typename A1, typename A2>
+inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
+{
+    p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
+}
+
+template<typename BasicJsonType, typename... Args>
+std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
+{
+    return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
+}
+
+template<typename BasicJsonType, typename... Args>
+inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
+{
+    t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
+}
+
+template<typename BasicJsonType, typename TupleRelated>
+auto from_json(BasicJsonType&& j, TupleRelated&& t)
+-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+
+    return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
+}
+
+template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
+           typename = enable_if_t < !std::is_constructible <
+                                        typename BasicJsonType::string_t, Key >::value >>
+inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    m.clear();
+    for (const auto& p : j)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
+        {
+            JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
+        }
+        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
+    }
+}
+
+template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
+           typename = enable_if_t < !std::is_constructible <
+                                        typename BasicJsonType::string_t, Key >::value >>
+inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    m.clear();
+    for (const auto& p : j)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
+        {
+            JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
+        }
+        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
+    }
+}
+
+#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, std_fs::path& p)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
+    }
+    p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
+}
+#endif
+
+struct from_json_fn
+{
+    template<typename BasicJsonType, typename T>
+    auto operator()(const BasicJsonType& j, T&& val) const
+    noexcept(noexcept(from_json(j, std::forward<T>(val))))
+    -> decltype(from_json(j, std::forward<T>(val)))
+    {
+        return from_json(j, std::forward<T>(val));
+    }
+};
+
+}  // namespace detail
+
+#ifndef JSON_HAS_CPP_17
+/// namespace to hold default `from_json` function
+/// to see why this is required:
+/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
+namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
+{
+#endif
+JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
+    detail::static_const<detail::from_json_fn>::value;
+#ifndef JSON_HAS_CPP_17
+}  // namespace
+#endif
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/to_chars.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/to_chars.h
new file mode 100644
index 0000000..f1845dc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/to_chars.h
@@ -0,0 +1,1118 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <array> // array
+#include <cmath>   // signbit, isfinite
+#include <cstdint> // intN_t, uintN_t
+#include <cstring> // memcpy, memmove
+#include <limits> // numeric_limits
+#include <type_traits> // conditional
+
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief implements the Grisu2 algorithm for binary to decimal floating-point
+conversion.
+
+This implementation is a slightly modified version of the reference
+implementation which may be obtained from
+http://florian.loitsch.com/publications (bench.tar.gz).
+
+The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
+
+For a detailed description of the algorithm see:
+
+[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
+    Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
+    Language Design and Implementation, PLDI 2010
+[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
+    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
+    Design and Implementation, PLDI 1996
+*/
+namespace dtoa_impl
+{
+
+template<typename Target, typename Source>
+Target reinterpret_bits(const Source source)
+{
+    static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
+
+    Target target;
+    std::memcpy(&target, &source, sizeof(Source));
+    return target;
+}
+
+struct diyfp // f * 2^e
+{
+    static constexpr int kPrecision = 64; // = q
+
+    std::uint64_t f = 0;
+    int e = 0;
+
+    constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
+
+    /*!
+    @brief returns x - y
+    @pre x.e == y.e and x.f >= y.f
+    */
+    static diyfp sub(const diyfp& x, const diyfp& y) noexcept
+    {
+        JSON_ASSERT(x.e == y.e);
+        JSON_ASSERT(x.f >= y.f);
+
+        return {x.f - y.f, x.e};
+    }
+
+    /*!
+    @brief returns x * y
+    @note The result is rounded. (Only the upper q bits are returned.)
+    */
+    static diyfp mul(const diyfp& x, const diyfp& y) noexcept
+    {
+        static_assert(kPrecision == 64, "internal error");
+
+        // Computes:
+        //  f = round((x.f * y.f) / 2^q)
+        //  e = x.e + y.e + q
+
+        // Emulate the 64-bit * 64-bit multiplication:
+        //
+        // p = u * v
+        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
+        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )
+        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )
+        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )
+        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)
+        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )
+        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )
+        //
+        // (Since Q might be larger than 2^32 - 1)
+        //
+        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
+        //
+        // (Q_hi + H does not overflow a 64-bit int)
+        //
+        //   = p_lo + 2^64 p_hi
+
+        const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
+        const std::uint64_t u_hi = x.f >> 32u;
+        const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
+        const std::uint64_t v_hi = y.f >> 32u;
+
+        const std::uint64_t p0 = u_lo * v_lo;
+        const std::uint64_t p1 = u_lo * v_hi;
+        const std::uint64_t p2 = u_hi * v_lo;
+        const std::uint64_t p3 = u_hi * v_hi;
+
+        const std::uint64_t p0_hi = p0 >> 32u;
+        const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
+        const std::uint64_t p1_hi = p1 >> 32u;
+        const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
+        const std::uint64_t p2_hi = p2 >> 32u;
+
+        std::uint64_t Q = p0_hi + p1_lo + p2_lo;
+
+        // The full product might now be computed as
+        //
+        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
+        // p_lo = p0_lo + (Q << 32)
+        //
+        // But in this particular case here, the full p_lo is not required.
+        // Effectively we only need to add the highest bit in p_lo to p_hi (and
+        // Q_hi + 1 does not overflow).
+
+        Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
+
+        const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
+
+        return {h, x.e + y.e + 64};
+    }
+
+    /*!
+    @brief normalize x such that the significand is >= 2^(q-1)
+    @pre x.f != 0
+    */
+    static diyfp normalize(diyfp x) noexcept
+    {
+        JSON_ASSERT(x.f != 0);
+
+        while ((x.f >> 63u) == 0)
+        {
+            x.f <<= 1u;
+            x.e--;
+        }
+
+        return x;
+    }
+
+    /*!
+    @brief normalize x such that the result has the exponent E
+    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
+    */
+    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
+    {
+        const int delta = x.e - target_exponent;
+
+        JSON_ASSERT(delta >= 0);
+        JSON_ASSERT(((x.f << delta) >> delta) == x.f);
+
+        return {x.f << delta, target_exponent};
+    }
+};
+
+struct boundaries
+{
+    diyfp w;
+    diyfp minus;
+    diyfp plus;
+};
+
+/*!
+Compute the (normalized) diyfp representing the input number 'value' and its
+boundaries.
+
+@pre value must be finite and positive
+*/
+template<typename FloatType>
+boundaries compute_boundaries(FloatType value)
+{
+    JSON_ASSERT(std::isfinite(value));
+    JSON_ASSERT(value > 0);
+
+    // Convert the IEEE representation into a diyfp.
+    //
+    // If v is denormal:
+    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))
+    // If v is normalized:
+    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
+
+    static_assert(std::numeric_limits<FloatType>::is_iec559,
+                  "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
+
+    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
+    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
+    constexpr int      kMinExp    = 1 - kBias;
+    constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
+
+    using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
+
+    const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));
+    const std::uint64_t E = bits >> (kPrecision - 1);
+    const std::uint64_t F = bits & (kHiddenBit - 1);
+
+    const bool is_denormal = E == 0;
+    const diyfp v = is_denormal
+                    ? diyfp(F, kMinExp)
+                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
+
+    // Compute the boundaries m- and m+ of the floating-point value
+    // v = f * 2^e.
+    //
+    // Determine v- and v+, the floating-point predecessor and successor if v,
+    // respectively.
+    //
+    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)
+    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)
+    //
+    //      v+ = v + 2^e
+    //
+    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
+    // between m- and m+ round to v, regardless of how the input rounding
+    // algorithm breaks ties.
+    //
+    //      ---+-------------+-------------+-------------+-------------+---  (A)
+    //         v-            m-            v             m+            v+
+    //
+    //      -----------------+------+------+-------------+-------------+---  (B)
+    //                       v-     m-     v             m+            v+
+
+    const bool lower_boundary_is_closer = F == 0 && E > 1;
+    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
+    const diyfp m_minus = lower_boundary_is_closer
+                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)
+                          : diyfp(2 * v.f - 1, v.e - 1); // (A)
+
+    // Determine the normalized w+ = m+.
+    const diyfp w_plus = diyfp::normalize(m_plus);
+
+    // Determine w- = m- such that e_(w-) = e_(w+).
+    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
+
+    return {diyfp::normalize(v), w_minus, w_plus};
+}
+
+// Given normalized diyfp w, Grisu needs to find a (normalized) cached
+// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
+// within a certain range [alpha, gamma] (Definition 3.2 from [1])
+//
+//      alpha <= e = e_c + e_w + q <= gamma
+//
+// or
+//
+//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
+//                          <= f_c * f_w * 2^gamma
+//
+// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
+//
+//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
+//
+// or
+//
+//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
+//
+// The choice of (alpha,gamma) determines the size of the table and the form of
+// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
+// in practice:
+//
+// The idea is to cut the number c * w = f * 2^e into two parts, which can be
+// processed independently: An integral part p1, and a fractional part p2:
+//
+//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
+//              = (f div 2^-e) + (f mod 2^-e) * 2^e
+//              = p1 + p2 * 2^e
+//
+// The conversion of p1 into decimal form requires a series of divisions and
+// modulos by (a power of) 10. These operations are faster for 32-bit than for
+// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
+// achieved by choosing
+//
+//      -e >= 32   or   e <= -32 := gamma
+//
+// In order to convert the fractional part
+//
+//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
+//
+// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
+// d[-i] are extracted in order:
+//
+//      (10 * p2) div 2^-e = d[-1]
+//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
+//
+// The multiplication by 10 must not overflow. It is sufficient to choose
+//
+//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
+//
+// Since p2 = f mod 2^-e < 2^-e,
+//
+//      -e <= 60   or   e >= -60 := alpha
+
+constexpr int kAlpha = -60;
+constexpr int kGamma = -32;
+
+struct cached_power // c = f * 2^e ~= 10^k
+{
+    std::uint64_t f;
+    int e;
+    int k;
+};
+
+/*!
+For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
+power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
+satisfies (Definition 3.2 from [1])
+
+     alpha <= e_c + e + q <= gamma.
+*/
+inline cached_power get_cached_power_for_binary_exponent(int e)
+{
+    // Now
+    //
+    //      alpha <= e_c + e + q <= gamma                                    (1)
+    //      ==> f_c * 2^alpha <= c * 2^e * 2^q
+    //
+    // and since the c's are normalized, 2^(q-1) <= f_c,
+    //
+    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
+    //      ==> 2^(alpha - e - 1) <= c
+    //
+    // If c were an exact power of ten, i.e. c = 10^k, one may determine k as
+    //
+    //      k = ceil( log_10( 2^(alpha - e - 1) ) )
+    //        = ceil( (alpha - e - 1) * log_10(2) )
+    //
+    // From the paper:
+    // "In theory the result of the procedure could be wrong since c is rounded,
+    //  and the computation itself is approximated [...]. In practice, however,
+    //  this simple function is sufficient."
+    //
+    // For IEEE double precision floating-point numbers converted into
+    // normalized diyfp's w = f * 2^e, with q = 64,
+    //
+    //      e >= -1022      (min IEEE exponent)
+    //           -52        (p - 1)
+    //           -52        (p - 1, possibly normalize denormal IEEE numbers)
+    //           -11        (normalize the diyfp)
+    //         = -1137
+    //
+    // and
+    //
+    //      e <= +1023      (max IEEE exponent)
+    //           -52        (p - 1)
+    //           -11        (normalize the diyfp)
+    //         = 960
+    //
+    // This binary exponent range [-1137,960] results in a decimal exponent
+    // range [-307,324]. One does not need to store a cached power for each
+    // k in this range. For each such k it suffices to find a cached power
+    // such that the exponent of the product lies in [alpha,gamma].
+    // This implies that the difference of the decimal exponents of adjacent
+    // table entries must be less than or equal to
+    //
+    //      floor( (gamma - alpha) * log_10(2) ) = 8.
+    //
+    // (A smaller distance gamma-alpha would require a larger table.)
+
+    // NB:
+    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
+
+    constexpr int kCachedPowersMinDecExp = -300;
+    constexpr int kCachedPowersDecStep = 8;
+
+    static constexpr std::array<cached_power, 79> kCachedPowers =
+    {
+        {
+            { 0xAB70FE17C79AC6CA, -1060, -300 },
+            { 0xFF77B1FCBEBCDC4F, -1034, -292 },
+            { 0xBE5691EF416BD60C, -1007, -284 },
+            { 0x8DD01FAD907FFC3C,  -980, -276 },
+            { 0xD3515C2831559A83,  -954, -268 },
+            { 0x9D71AC8FADA6C9B5,  -927, -260 },
+            { 0xEA9C227723EE8BCB,  -901, -252 },
+            { 0xAECC49914078536D,  -874, -244 },
+            { 0x823C12795DB6CE57,  -847, -236 },
+            { 0xC21094364DFB5637,  -821, -228 },
+            { 0x9096EA6F3848984F,  -794, -220 },
+            { 0xD77485CB25823AC7,  -768, -212 },
+            { 0xA086CFCD97BF97F4,  -741, -204 },
+            { 0xEF340A98172AACE5,  -715, -196 },
+            { 0xB23867FB2A35B28E,  -688, -188 },
+            { 0x84C8D4DFD2C63F3B,  -661, -180 },
+            { 0xC5DD44271AD3CDBA,  -635, -172 },
+            { 0x936B9FCEBB25C996,  -608, -164 },
+            { 0xDBAC6C247D62A584,  -582, -156 },
+            { 0xA3AB66580D5FDAF6,  -555, -148 },
+            { 0xF3E2F893DEC3F126,  -529, -140 },
+            { 0xB5B5ADA8AAFF80B8,  -502, -132 },
+            { 0x87625F056C7C4A8B,  -475, -124 },
+            { 0xC9BCFF6034C13053,  -449, -116 },
+            { 0x964E858C91BA2655,  -422, -108 },
+            { 0xDFF9772470297EBD,  -396, -100 },
+            { 0xA6DFBD9FB8E5B88F,  -369,  -92 },
+            { 0xF8A95FCF88747D94,  -343,  -84 },
+            { 0xB94470938FA89BCF,  -316,  -76 },
+            { 0x8A08F0F8BF0F156B,  -289,  -68 },
+            { 0xCDB02555653131B6,  -263,  -60 },
+            { 0x993FE2C6D07B7FAC,  -236,  -52 },
+            { 0xE45C10C42A2B3B06,  -210,  -44 },
+            { 0xAA242499697392D3,  -183,  -36 },
+            { 0xFD87B5F28300CA0E,  -157,  -28 },
+            { 0xBCE5086492111AEB,  -130,  -20 },
+            { 0x8CBCCC096F5088CC,  -103,  -12 },
+            { 0xD1B71758E219652C,   -77,   -4 },
+            { 0x9C40000000000000,   -50,    4 },
+            { 0xE8D4A51000000000,   -24,   12 },
+            { 0xAD78EBC5AC620000,     3,   20 },
+            { 0x813F3978F8940984,    30,   28 },
+            { 0xC097CE7BC90715B3,    56,   36 },
+            { 0x8F7E32CE7BEA5C70,    83,   44 },
+            { 0xD5D238A4ABE98068,   109,   52 },
+            { 0x9F4F2726179A2245,   136,   60 },
+            { 0xED63A231D4C4FB27,   162,   68 },
+            { 0xB0DE65388CC8ADA8,   189,   76 },
+            { 0x83C7088E1AAB65DB,   216,   84 },
+            { 0xC45D1DF942711D9A,   242,   92 },
+            { 0x924D692CA61BE758,   269,  100 },
+            { 0xDA01EE641A708DEA,   295,  108 },
+            { 0xA26DA3999AEF774A,   322,  116 },
+            { 0xF209787BB47D6B85,   348,  124 },
+            { 0xB454E4A179DD1877,   375,  132 },
+            { 0x865B86925B9BC5C2,   402,  140 },
+            { 0xC83553C5C8965D3D,   428,  148 },
+            { 0x952AB45CFA97A0B3,   455,  156 },
+            { 0xDE469FBD99A05FE3,   481,  164 },
+            { 0xA59BC234DB398C25,   508,  172 },
+            { 0xF6C69A72A3989F5C,   534,  180 },
+            { 0xB7DCBF5354E9BECE,   561,  188 },
+            { 0x88FCF317F22241E2,   588,  196 },
+            { 0xCC20CE9BD35C78A5,   614,  204 },
+            { 0x98165AF37B2153DF,   641,  212 },
+            { 0xE2A0B5DC971F303A,   667,  220 },
+            { 0xA8D9D1535CE3B396,   694,  228 },
+            { 0xFB9B7CD9A4A7443C,   720,  236 },
+            { 0xBB764C4CA7A44410,   747,  244 },
+            { 0x8BAB8EEFB6409C1A,   774,  252 },
+            { 0xD01FEF10A657842C,   800,  260 },
+            { 0x9B10A4E5E9913129,   827,  268 },
+            { 0xE7109BFBA19C0C9D,   853,  276 },
+            { 0xAC2820D9623BF429,   880,  284 },
+            { 0x80444B5E7AA7CF85,   907,  292 },
+            { 0xBF21E44003ACDD2D,   933,  300 },
+            { 0x8E679C2F5E44FF8F,   960,  308 },
+            { 0xD433179D9C8CB841,   986,  316 },
+            { 0x9E19DB92B4E31BA9,  1013,  324 },
+        }
+    };
+
+    // This computation gives exactly the same results for k as
+    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)
+    // for |e| <= 1500, but doesn't require floating-point operations.
+    // NB: log_10(2) ~= 78913 / 2^18
+    JSON_ASSERT(e >= -1500);
+    JSON_ASSERT(e <=  1500);
+    const int f = kAlpha - e - 1;
+    const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
+
+    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
+    JSON_ASSERT(index >= 0);
+    JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
+
+    const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
+    JSON_ASSERT(kAlpha <= cached.e + e + 64);
+    JSON_ASSERT(kGamma >= cached.e + e + 64);
+
+    return cached;
+}
+
+/*!
+For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
+For n == 0, returns 1 and sets pow10 := 1.
+*/
+inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
+{
+    // LCOV_EXCL_START
+    if (n >= 1000000000)
+    {
+        pow10 = 1000000000;
+        return 10;
+    }
+    // LCOV_EXCL_STOP
+    if (n >= 100000000)
+    {
+        pow10 = 100000000;
+        return  9;
+    }
+    if (n >= 10000000)
+    {
+        pow10 = 10000000;
+        return  8;
+    }
+    if (n >= 1000000)
+    {
+        pow10 = 1000000;
+        return  7;
+    }
+    if (n >= 100000)
+    {
+        pow10 = 100000;
+        return  6;
+    }
+    if (n >= 10000)
+    {
+        pow10 = 10000;
+        return  5;
+    }
+    if (n >= 1000)
+    {
+        pow10 = 1000;
+        return  4;
+    }
+    if (n >= 100)
+    {
+        pow10 = 100;
+        return  3;
+    }
+    if (n >= 10)
+    {
+        pow10 = 10;
+        return  2;
+    }
+
+    pow10 = 1;
+    return 1;
+}
+
+inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
+                         std::uint64_t rest, std::uint64_t ten_k)
+{
+    JSON_ASSERT(len >= 1);
+    JSON_ASSERT(dist <= delta);
+    JSON_ASSERT(rest <= delta);
+    JSON_ASSERT(ten_k > 0);
+
+    //               <--------------------------- delta ---->
+    //                                  <---- dist --------->
+    // --------------[------------------+-------------------]--------------
+    //               M-                 w                   M+
+    //
+    //                                  ten_k
+    //                                <------>
+    //                                       <---- rest ---->
+    // --------------[------------------+----+--------------]--------------
+    //                                  w    V
+    //                                       = buf * 10^k
+    //
+    // ten_k represents a unit-in-the-last-place in the decimal representation
+    // stored in buf.
+    // Decrement buf by ten_k while this takes buf closer to w.
+
+    // The tests are written in this order to avoid overflow in unsigned
+    // integer arithmetic.
+
+    while (rest < dist
+            && delta - rest >= ten_k
+            && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
+    {
+        JSON_ASSERT(buf[len - 1] != '0');
+        buf[len - 1]--;
+        rest += ten_k;
+    }
+}
+
+/*!
+Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
+M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
+*/
+inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
+                             diyfp M_minus, diyfp w, diyfp M_plus)
+{
+    static_assert(kAlpha >= -60, "internal error");
+    static_assert(kGamma <= -32, "internal error");
+
+    // Generates the digits (and the exponent) of a decimal floating-point
+    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
+    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
+    //
+    //               <--------------------------- delta ---->
+    //                                  <---- dist --------->
+    // --------------[------------------+-------------------]--------------
+    //               M-                 w                   M+
+    //
+    // Grisu2 generates the digits of M+ from left to right and stops as soon as
+    // V is in [M-,M+].
+
+    JSON_ASSERT(M_plus.e >= kAlpha);
+    JSON_ASSERT(M_plus.e <= kGamma);
+
+    std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
+    std::uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)
+
+    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
+    //
+    //      M+ = f * 2^e
+    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
+    //         = ((p1        ) * 2^-e + (p2        )) * 2^e
+    //         = p1 + p2 * 2^e
+
+    const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
+
+    auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
+    std::uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e
+
+    // 1)
+    //
+    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
+
+    JSON_ASSERT(p1 > 0);
+
+    std::uint32_t pow10{};
+    const int k = find_largest_pow10(p1, pow10);
+
+    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
+    //
+    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
+    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))
+    //
+    //      M+ = p1                                             + p2 * 2^e
+    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e
+    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
+    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e
+    //
+    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
+    //
+    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
+    //
+    // but stop as soon as
+    //
+    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
+
+    int n = k;
+    while (n > 0)
+    {
+        // Invariants:
+        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)
+        //      pow10 = 10^(n-1) <= p1 < 10^n
+        //
+        const std::uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)
+        const std::uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)
+        //
+        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
+        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
+        //
+        JSON_ASSERT(d <= 9);
+        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
+        //
+        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
+        //
+        p1 = r;
+        n--;
+        //
+        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)
+        //      pow10 = 10^n
+        //
+
+        // Now check if enough digits have been generated.
+        // Compute
+        //
+        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
+        //
+        // Note:
+        // Since rest and delta share the same exponent e, it suffices to
+        // compare the significands.
+        const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
+        if (rest <= delta)
+        {
+            // V = buffer * 10^n, with M- <= V <= M+.
+
+            decimal_exponent += n;
+
+            // We may now just stop. But instead look if the buffer could be
+            // decremented to bring V closer to w.
+            //
+            // pow10 = 10^n is now 1 ulp in the decimal representation V.
+            // The rounding procedure works with diyfp's with an implicit
+            // exponent of e.
+            //
+            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
+            //
+            const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
+            grisu2_round(buffer, length, dist, delta, rest, ten_n);
+
+            return;
+        }
+
+        pow10 /= 10;
+        //
+        //      pow10 = 10^(n-1) <= p1 < 10^n
+        // Invariants restored.
+    }
+
+    // 2)
+    //
+    // The digits of the integral part have been generated:
+    //
+    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e
+    //         = buffer            + p2 * 2^e
+    //
+    // Now generate the digits of the fractional part p2 * 2^e.
+    //
+    // Note:
+    // No decimal point is generated: the exponent is adjusted instead.
+    //
+    // p2 actually represents the fraction
+    //
+    //      p2 * 2^e
+    //          = p2 / 2^-e
+    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...
+    //
+    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
+    //
+    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
+    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
+    //
+    // using
+    //
+    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
+    //                = (                   d) * 2^-e + (                   r)
+    //
+    // or
+    //      10^m * p2 * 2^e = d + r * 2^e
+    //
+    // i.e.
+    //
+    //      M+ = buffer + p2 * 2^e
+    //         = buffer + 10^-m * (d + r * 2^e)
+    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
+    //
+    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
+
+    JSON_ASSERT(p2 > delta);
+
+    int m = 0;
+    for (;;)
+    {
+        // Invariant:
+        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
+        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e
+        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e
+        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
+        //
+        JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
+        p2 *= 10;
+        const std::uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e
+        const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
+        //
+        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
+        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
+        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
+        //
+        JSON_ASSERT(d <= 9);
+        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
+        //
+        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
+        //
+        p2 = r;
+        m++;
+        //
+        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e
+        // Invariant restored.
+
+        // Check if enough digits have been generated.
+        //
+        //      10^-m * p2 * 2^e <= delta * 2^e
+        //              p2 * 2^e <= 10^m * delta * 2^e
+        //                    p2 <= 10^m * delta
+        delta *= 10;
+        dist  *= 10;
+        if (p2 <= delta)
+        {
+            break;
+        }
+    }
+
+    // V = buffer * 10^-m, with M- <= V <= M+.
+
+    decimal_exponent -= m;
+
+    // 1 ulp in the decimal representation is now 10^-m.
+    // Since delta and dist are now scaled by 10^m, we need to do the
+    // same with ulp in order to keep the units in sync.
+    //
+    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
+    //
+    const std::uint64_t ten_m = one.f;
+    grisu2_round(buffer, length, dist, delta, p2, ten_m);
+
+    // By construction this algorithm generates the shortest possible decimal
+    // number (Loitsch, Theorem 6.2) which rounds back to w.
+    // For an input number of precision p, at least
+    //
+    //      N = 1 + ceil(p * log_10(2))
+    //
+    // decimal digits are sufficient to identify all binary floating-point
+    // numbers (Matula, "In-and-Out conversions").
+    // This implies that the algorithm does not produce more than N decimal
+    // digits.
+    //
+    //      N = 17 for p = 53 (IEEE double precision)
+    //      N = 9  for p = 24 (IEEE single precision)
+}
+
+/*!
+v = buf * 10^decimal_exponent
+len is the length of the buffer (number of decimal digits)
+The buffer must be large enough, i.e. >= max_digits10.
+*/
+JSON_HEDLEY_NON_NULL(1)
+inline void grisu2(char* buf, int& len, int& decimal_exponent,
+                   diyfp m_minus, diyfp v, diyfp m_plus)
+{
+    JSON_ASSERT(m_plus.e == m_minus.e);
+    JSON_ASSERT(m_plus.e == v.e);
+
+    //  --------(-----------------------+-----------------------)--------    (A)
+    //          m-                      v                       m+
+    //
+    //  --------------------(-----------+-----------------------)--------    (B)
+    //                      m-          v                       m+
+    //
+    // First scale v (and m- and m+) such that the exponent is in the range
+    // [alpha, gamma].
+
+    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
+
+    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
+
+    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
+    const diyfp w       = diyfp::mul(v,       c_minus_k);
+    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
+    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);
+
+    //  ----(---+---)---------------(---+---)---------------(---+---)----
+    //          w-                      w                       w+
+    //          = c*m-                  = c*v                   = c*m+
+    //
+    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
+    // w+ are now off by a small amount.
+    // In fact:
+    //
+    //      w - v * 10^k < 1 ulp
+    //
+    // To account for this inaccuracy, add resp. subtract 1 ulp.
+    //
+    //  --------+---[---------------(---+---)---------------]---+--------
+    //          w-  M-                  w                   M+  w+
+    //
+    // Now any number in [M-, M+] (bounds included) will round to w when input,
+    // regardless of how the input rounding algorithm breaks ties.
+    //
+    // And digit_gen generates the shortest possible such number in [M-, M+].
+    // Note that this does not mean that Grisu2 always generates the shortest
+    // possible number in the interval (m-, m+).
+    const diyfp M_minus(w_minus.f + 1, w_minus.e);
+    const diyfp M_plus (w_plus.f  - 1, w_plus.e );
+
+    decimal_exponent = -cached.k; // = -(-k) = k
+
+    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
+}
+
+/*!
+v = buf * 10^decimal_exponent
+len is the length of the buffer (number of decimal digits)
+The buffer must be large enough, i.e. >= max_digits10.
+*/
+template<typename FloatType>
+JSON_HEDLEY_NON_NULL(1)
+void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
+{
+    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
+                  "internal error: not enough precision");
+
+    JSON_ASSERT(std::isfinite(value));
+    JSON_ASSERT(value > 0);
+
+    // If the neighbors (and boundaries) of 'value' are always computed for double-precision
+    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
+    // decimal representations are not exactly "short".
+    //
+    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
+    // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
+    // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars'
+    // does.
+    // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
+    // representation using the corresponding std::from_chars function recovers value exactly". That
+    // indicates that single precision floating-point numbers should be recovered using
+    // 'std::strtof'.
+    //
+    // NB: If the neighbors are computed for single-precision numbers, there is a single float
+    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
+    //     value is off by 1 ulp.
+#if 0
+    const boundaries w = compute_boundaries(static_cast<double>(value));
+#else
+    const boundaries w = compute_boundaries(value);
+#endif
+
+    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
+}
+
+/*!
+@brief appends a decimal representation of e to buf
+@return a pointer to the element following the exponent.
+@pre -1000 < e < 1000
+*/
+JSON_HEDLEY_NON_NULL(1)
+JSON_HEDLEY_RETURNS_NON_NULL
+inline char* append_exponent(char* buf, int e)
+{
+    JSON_ASSERT(e > -1000);
+    JSON_ASSERT(e <  1000);
+
+    if (e < 0)
+    {
+        e = -e;
+        *buf++ = '-';
+    }
+    else
+    {
+        *buf++ = '+';
+    }
+
+    auto k = static_cast<std::uint32_t>(e);
+    if (k < 10)
+    {
+        // Always print at least two digits in the exponent.
+        // This is for compatibility with printf("%g").
+        *buf++ = '0';
+        *buf++ = static_cast<char>('0' + k);
+    }
+    else if (k < 100)
+    {
+        *buf++ = static_cast<char>('0' + k / 10);
+        k %= 10;
+        *buf++ = static_cast<char>('0' + k);
+    }
+    else
+    {
+        *buf++ = static_cast<char>('0' + k / 100);
+        k %= 100;
+        *buf++ = static_cast<char>('0' + k / 10);
+        k %= 10;
+        *buf++ = static_cast<char>('0' + k);
+    }
+
+    return buf;
+}
+
+/*!
+@brief prettify v = buf * 10^decimal_exponent
+
+If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
+notation. Otherwise it will be printed in exponential notation.
+
+@pre min_exp < 0
+@pre max_exp > 0
+*/
+JSON_HEDLEY_NON_NULL(1)
+JSON_HEDLEY_RETURNS_NON_NULL
+inline char* format_buffer(char* buf, int len, int decimal_exponent,
+                           int min_exp, int max_exp)
+{
+    JSON_ASSERT(min_exp < 0);
+    JSON_ASSERT(max_exp > 0);
+
+    const int k = len;
+    const int n = len + decimal_exponent;
+
+    // v = buf * 10^(n-k)
+    // k is the length of the buffer (number of decimal digits)
+    // n is the position of the decimal point relative to the start of the buffer.
+
+    if (k <= n && n <= max_exp)
+    {
+        // digits[000]
+        // len <= max_exp + 2
+
+        std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
+        // Make it look like a floating-point number (#362, #378)
+        buf[n + 0] = '.';
+        buf[n + 1] = '0';
+        return buf + (static_cast<size_t>(n) + 2);
+    }
+
+    if (0 < n && n <= max_exp)
+    {
+        // dig.its
+        // len <= max_digits10 + 1
+
+        JSON_ASSERT(k > n);
+
+        std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
+        buf[n] = '.';
+        return buf + (static_cast<size_t>(k) + 1U);
+    }
+
+    if (min_exp < n && n <= 0)
+    {
+        // 0.[000]digits
+        // len <= 2 + (-min_exp - 1) + max_digits10
+
+        std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));
+        buf[0] = '0';
+        buf[1] = '.';
+        std::memset(buf + 2, '0', static_cast<size_t>(-n));
+        return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));
+    }
+
+    if (k == 1)
+    {
+        // dE+123
+        // len <= 1 + 5
+
+        buf += 1;
+    }
+    else
+    {
+        // d.igitsE+123
+        // len <= max_digits10 + 1 + 5
+
+        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);
+        buf[1] = '.';
+        buf += 1 + static_cast<size_t>(k);
+    }
+
+    *buf++ = 'e';
+    return append_exponent(buf, n - 1);
+}
+
+}  // namespace dtoa_impl
+
+/*!
+@brief generates a decimal representation of the floating-point number value in [first, last).
+
+The format of the resulting decimal representation is similar to printf's %g
+format. Returns an iterator pointing past-the-end of the decimal representation.
+
+@note The input number must be finite, i.e. NaN's and Inf's are not supported.
+@note The buffer must be large enough.
+@note The result is NOT null-terminated.
+*/
+template<typename FloatType>
+JSON_HEDLEY_NON_NULL(1, 2)
+JSON_HEDLEY_RETURNS_NON_NULL
+char* to_chars(char* first, const char* last, FloatType value)
+{
+    static_cast<void>(last); // maybe unused - fix warning
+    JSON_ASSERT(std::isfinite(value));
+
+    // Use signbit(value) instead of (value < 0) since signbit works for -0.
+    if (std::signbit(value))
+    {
+        value = -value;
+        *first++ = '-';
+    }
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+    if (value == 0) // +-0
+    {
+        *first++ = '0';
+        // Make it look like a floating-point number (#362, #378)
+        *first++ = '.';
+        *first++ = '0';
+        return first;
+    }
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
+
+    // Compute v = buffer * 10^decimal_exponent.
+    // The decimal digits are stored in the buffer, which needs to be interpreted
+    // as an unsigned decimal integer.
+    // len is the length of the buffer, i.e. the number of decimal digits.
+    int len = 0;
+    int decimal_exponent = 0;
+    dtoa_impl::grisu2(first, len, decimal_exponent, value);
+
+    JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
+
+    // Format the buffer like printf("%.*g", prec, value)
+    constexpr int kMinExp = -4;
+    // Use digits10 here to increase compatibility with version 2.
+    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
+
+    JSON_ASSERT(last - first >= kMaxExp + 2);
+    JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
+    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
+
+    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
+}
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/to_json.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/to_json.h
new file mode 100644
index 0000000..59db3be
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/conversions/to_json.h
@@ -0,0 +1,446 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // copy
+#include <iterator> // begin, end
+#include <string> // string
+#include <tuple> // tuple, get
+#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
+#include <utility> // move, forward, declval, pair
+#include <valarray> // valarray
+#include <vector> // vector
+
+#include <wpi/detail/iterators/iteration_proxy.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/std_fs.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+//////////////////
+// constructors //
+//////////////////
+
+/*
+ * Note all external_constructor<>::construct functions need to call
+ * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
+ * allocated value (e.g., a string). See bug issue
+ * https://github.com/nlohmann/json/issues/2865 for more information.
+ */
+
+template<value_t> struct external_constructor;
+
+template<>
+struct external_constructor<value_t::boolean>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::boolean;
+        j.m_value = b;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::string>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::string;
+        j.m_value = s;
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::string;
+        j.m_value = std::move(s);
+        j.assert_invariant();
+    }
+
+    template < typename BasicJsonType, typename CompatibleStringType,
+               enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
+                             int > = 0 >
+    static void construct(BasicJsonType& j, const CompatibleStringType& str)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::string;
+        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::binary>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::binary;
+        j.m_value = typename BasicJsonType::binary_t(b);
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::binary;
+        j.m_value = typename BasicJsonType::binary_t(std::move(b));
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::number_float>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::number_float;
+        j.m_value = val;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::number_unsigned>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::number_unsigned;
+        j.m_value = val;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::number_integer>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::number_integer;
+        j.m_value = val;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::array>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = arr;
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = std::move(arr);
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template < typename BasicJsonType, typename CompatibleArrayType,
+               enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
+                             int > = 0 >
+    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
+    {
+        using std::begin;
+        using std::end;
+
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const std::vector<bool>& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = value_t::array;
+        j.m_value.array->reserve(arr.size());
+        for (const bool x : arr)
+        {
+            j.m_value.array->push_back(x);
+            j.set_parent(j.m_value.array->back());
+        }
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType, typename T,
+             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
+    static void construct(BasicJsonType& j, const std::valarray<T>& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = value_t::array;
+        j.m_value.array->resize(arr.size());
+        if (arr.size() > 0)
+        {
+            std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
+        }
+        j.set_parents();
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::object>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::object;
+        j.m_value = obj;
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::object;
+        j.m_value = std::move(obj);
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template < typename BasicJsonType, typename CompatibleObjectType,
+               enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
+    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
+    {
+        using std::begin;
+        using std::end;
+
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::object;
+        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
+        j.set_parents();
+        j.assert_invariant();
+    }
+};
+
+/////////////
+// to_json //
+/////////////
+
+template<typename BasicJsonType, typename T,
+         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
+inline void to_json(BasicJsonType& j, T b) noexcept
+{
+    external_constructor<value_t::boolean>::construct(j, b);
+}
+
+template < typename BasicJsonType, typename BoolRef,
+           enable_if_t <
+               ((std::is_same<std::vector<bool>::reference, BoolRef>::value
+                 && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
+                || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
+                    && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
+                                      typename BasicJsonType::boolean_t >::value))
+               && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
+inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
+{
+    external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
+}
+
+template<typename BasicJsonType, typename CompatibleString,
+         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
+inline void to_json(BasicJsonType& j, const CompatibleString& s)
+{
+    external_constructor<value_t::string>::construct(j, s);
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
+{
+    external_constructor<value_t::string>::construct(j, std::move(s));
+}
+
+template<typename BasicJsonType, typename FloatType,
+         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, FloatType val) noexcept
+{
+    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
+}
+
+template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
+         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
+{
+    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
+}
+
+template<typename BasicJsonType, typename CompatibleNumberIntegerType,
+         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
+{
+    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
+}
+
+#if !JSON_DISABLE_ENUM_SERIALIZATION
+template<typename BasicJsonType, typename EnumType,
+         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, EnumType e) noexcept
+{
+    using underlying_type = typename std::underlying_type<EnumType>::type;
+    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
+}
+#endif  // JSON_DISABLE_ENUM_SERIALIZATION
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
+{
+    external_constructor<value_t::array>::construct(j, e);
+}
+
+template < typename BasicJsonType, typename CompatibleArrayType,
+           enable_if_t < is_compatible_array_type<BasicJsonType,
+                         CompatibleArrayType>::value&&
+                         !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
+                         !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
+                         !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
+                         !is_basic_json<CompatibleArrayType>::value,
+                         int > = 0 >
+inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
+{
+    external_constructor<value_t::array>::construct(j, arr);
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
+{
+    external_constructor<value_t::binary>::construct(j, bin);
+}
+
+template<typename BasicJsonType, typename T,
+         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
+{
+    external_constructor<value_t::array>::construct(j, std::move(arr));
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
+{
+    external_constructor<value_t::array>::construct(j, std::move(arr));
+}
+
+template < typename BasicJsonType, typename CompatibleObjectType,
+           enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
+inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
+{
+    external_constructor<value_t::object>::construct(j, obj);
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
+{
+    external_constructor<value_t::object>::construct(j, std::move(obj));
+}
+
+template <
+    typename BasicJsonType, typename T, std::size_t N,
+    enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
+                  const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+                  int > = 0 >
+inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+{
+    external_constructor<value_t::array>::construct(j, arr);
+}
+
+template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
+inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
+{
+    j = { p.first, p.second };
+}
+
+// for https://github.com/nlohmann/json/pull/1134
+template<typename BasicJsonType, typename T,
+         enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
+inline void to_json(BasicJsonType& j, const T& b)
+{
+    j = { {b.key(), b.value()} };
+}
+
+template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
+inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
+{
+    j = { std::get<Idx>(t)... };
+}
+
+template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
+inline void to_json(BasicJsonType& j, const T& t)
+{
+    to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
+}
+
+#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, const std_fs::path& p)
+{
+    j = p.string();
+}
+#endif
+
+struct to_json_fn
+{
+    template<typename BasicJsonType, typename T>
+    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
+    -> decltype(to_json(j, std::forward<T>(val)), void())
+    {
+        return to_json(j, std::forward<T>(val));
+    }
+};
+}  // namespace detail
+
+#ifndef JSON_HAS_CPP_17
+/// namespace to hold default `to_json` function
+/// to see why this is required:
+/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
+namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
+{
+#endif
+JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
+    detail::static_const<detail::to_json_fn>::value;
+#ifndef JSON_HAS_CPP_17
+}  // namespace
+#endif
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/exceptions.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/exceptions.h
new file mode 100644
index 0000000..278ffaa
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/exceptions.h
@@ -0,0 +1,255 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstddef> // nullptr_t
+#include <exception> // exception
+#include <stdexcept> // runtime_error
+#include <string> // to_string
+#include <vector> // vector
+
+#include <wpi/detail/value_t.h>
+#include <wpi/detail/string_escape.h>
+#include <wpi/detail/input/position_t.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/string_concat.h>
+
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+////////////////
+// exceptions //
+////////////////
+
+/// @brief general exception of the @ref basic_json class
+/// @sa https://json.nlohmann.me/api/basic_json/exception/
+class exception : public std::exception
+{
+  public:
+    /// returns the explanatory string
+    const char* what() const noexcept override
+    {
+        return m.what();
+    }
+
+    /// the id of the exception
+    const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
+
+  protected:
+    JSON_HEDLEY_NON_NULL(3)
+    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
+
+    static std::string name(const std::string& ename, int id_)
+    {
+        return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
+    }
+
+    static std::string diagnostics(std::nullptr_t /*leaf_element*/)
+    {
+        return "";
+    }
+
+    template<typename BasicJsonType>
+    static std::string diagnostics(const BasicJsonType* leaf_element)
+    {
+#if JSON_DIAGNOSTICS
+        std::vector<std::string> tokens;
+        for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
+        {
+            switch (current->m_parent->type())
+            {
+                case value_t::array:
+                {
+                    for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
+                    {
+                        if (&current->m_parent->m_value.array->operator[](i) == current)
+                        {
+                            tokens.emplace_back(std::to_string(i));
+                            break;
+                        }
+                    }
+                    break;
+                }
+
+                case value_t::object:
+                {
+                    for (const auto& element : *current->m_parent->m_value.object)
+                    {
+                        if (&element.second == current)
+                        {
+                            tokens.emplace_back(element.first.c_str());
+                            break;
+                        }
+                    }
+                    break;
+                }
+
+                case value_t::null: // LCOV_EXCL_LINE
+                case value_t::string: // LCOV_EXCL_LINE
+                case value_t::boolean: // LCOV_EXCL_LINE
+                case value_t::number_integer: // LCOV_EXCL_LINE
+                case value_t::number_unsigned: // LCOV_EXCL_LINE
+                case value_t::number_float: // LCOV_EXCL_LINE
+                case value_t::binary: // LCOV_EXCL_LINE
+                case value_t::discarded: // LCOV_EXCL_LINE
+                default:   // LCOV_EXCL_LINE
+                    break; // LCOV_EXCL_LINE
+            }
+        }
+
+        if (tokens.empty())
+        {
+            return "";
+        }
+
+        auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
+                                   [](const std::string & a, const std::string & b)
+        {
+            return concat(a, '/', detail::escape(b));
+        });
+        return concat('(', str, ") ");
+#else
+        static_cast<void>(leaf_element);
+        return "";
+#endif
+    }
+
+  private:
+    /// an exception object as storage for error messages
+    std::runtime_error m;
+};
+
+/// @brief exception indicating a parse error
+/// @sa https://json.nlohmann.me/api/basic_json/parse_error/
+class parse_error : public exception
+{
+  public:
+    /*!
+    @brief create a parse error exception
+    @param[in] id_       the id of the exception
+    @param[in] pos       the position where the error occurred (or with
+                         chars_read_total=0 if the position cannot be
+                         determined)
+    @param[in] what_arg  the explanatory string
+    @return parse_error object
+    */
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("parse_error", id_), "parse error",
+                               position_string(pos), ": ", exception::diagnostics(context), what_arg);
+        return {id_, pos.chars_read_total, w.c_str()};
+    }
+
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("parse_error", id_), "parse error",
+                               (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
+                               ": ", exception::diagnostics(context), what_arg);
+        return {id_, byte_, w.c_str()};
+    }
+
+    /*!
+    @brief byte index of the parse error
+
+    The byte index of the last read character in the input file.
+
+    @note For an input with n bytes, 1 is the index of the first character and
+          n+1 is the index of the terminating null byte or the end of file.
+          This also holds true when reading a byte vector (CBOR or MessagePack).
+    */
+    const std::size_t byte;
+
+  private:
+    parse_error(int id_, std::size_t byte_, const char* what_arg)
+        : exception(id_, what_arg), byte(byte_) {}
+
+    static std::string position_string(const position_t& pos)
+    {
+        return concat(" at line ", std::to_string(pos.lines_read + 1),
+                      ", column ", std::to_string(pos.chars_read_current_line));
+    }
+};
+
+/// @brief exception indicating errors with iterators
+/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
+class invalid_iterator : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    invalid_iterator(int id_, const char* what_arg)
+        : exception(id_, what_arg) {}
+};
+
+/// @brief exception indicating executing a member function with a wrong type
+/// @sa https://json.nlohmann.me/api/basic_json/type_error/
+class type_error : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
+};
+
+/// @brief exception indicating access out of the defined range
+/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
+class out_of_range : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
+};
+
+/// @brief exception indicating other library errors
+/// @sa https://json.nlohmann.me/api/basic_json/other_error/
+class other_error : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/hash.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/hash.h
new file mode 100644
index 0000000..156fb24
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/hash.h
@@ -0,0 +1,129 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstdint> // uint8_t
+#include <cstddef> // size_t
+#include <functional> // hash
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// boost::hash_combine
+inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
+{
+    seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
+    return seed;
+}
+
+/*!
+@brief hash a JSON value
+
+The hash function tries to rely on std::hash where possible. Furthermore, the
+type of the JSON value is taken into account to have different hash values for
+null, 0, 0U, and false, etc.
+
+@tparam BasicJsonType basic_json specialization
+@param j JSON value to hash
+@return hash value of j
+*/
+template<typename BasicJsonType>
+std::size_t hash(const BasicJsonType& j)
+{
+    using string_t = typename BasicJsonType::string_t;
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+
+    const auto type = static_cast<std::size_t>(j.type());
+    switch (j.type())
+    {
+        case BasicJsonType::value_t::null:
+        case BasicJsonType::value_t::discarded:
+        {
+            return combine(type, 0);
+        }
+
+        case BasicJsonType::value_t::object:
+        {
+            auto seed = combine(type, j.size());
+            for (const auto& element : j.items())
+            {
+                const auto h = std::hash<string_t> {}(element.key());
+                seed = combine(seed, h);
+                seed = combine(seed, hash(element.value()));
+            }
+            return seed;
+        }
+
+        case BasicJsonType::value_t::array:
+        {
+            auto seed = combine(type, j.size());
+            for (const auto& element : j)
+            {
+                seed = combine(seed, hash(element));
+            }
+            return seed;
+        }
+
+        case BasicJsonType::value_t::string:
+        {
+            const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::boolean:
+        {
+            const auto h = std::hash<bool> {}(j.template get<bool>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::number_integer:
+        {
+            const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::number_unsigned:
+        {
+            const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::number_float:
+        {
+            const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::binary:
+        {
+            auto seed = combine(type, j.get_binary().size());
+            const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
+            seed = combine(seed, h);
+            seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
+            for (const auto byte : j.get_binary())
+            {
+                seed = combine(seed, std::hash<std::uint8_t> {}(byte));
+            }
+            return seed;
+        }
+
+        default:                   // LCOV_EXCL_LINE
+            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+            return 0;              // LCOV_EXCL_LINE
+    }
+}
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/binary_reader.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/binary_reader.h
new file mode 100644
index 0000000..0241fe0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/binary_reader.h
@@ -0,0 +1,3010 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // generate_n
+#include <array> // array
+#include <cmath> // ldexp
+#include <cstddef> // size_t
+#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
+#include <cstdio> // snprintf
+#include <cstring> // memcpy
+#include <iterator> // back_inserter
+#include <limits> // numeric_limits
+#include <string> // char_traits, string
+#include <utility> // make_pair, move
+#include <vector> // vector
+
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/input/input_adapters.h>
+#include <wpi/detail/input/json_sax.h>
+#include <wpi/detail/input/lexer.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/is_sax.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/string_concat.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// how to treat CBOR tags
+enum class cbor_tag_handler_t
+{
+    error,   ///< throw a parse_error exception in case of a tag
+    ignore,  ///< ignore tags
+    store    ///< store tags as binary type
+};
+
+/*!
+@brief determine system byte order
+
+@return true if and only if system's byte order is little endian
+
+@note from https://stackoverflow.com/a/1001328/266378
+*/
+static inline bool little_endianness(int num = 1) noexcept
+{
+    return *reinterpret_cast<char*>(&num) == 1;
+}
+
+
+///////////////////
+// binary reader //
+///////////////////
+
+/*!
+@brief deserialization of CBOR, MessagePack, and UBJSON values
+*/
+template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
+class binary_reader
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using json_sax_t = SAX;
+    using char_type = typename InputAdapterType::char_type;
+    using char_int_type = typename std::char_traits<char_type>::int_type;
+
+  public:
+    /*!
+    @brief create a binary reader
+
+    @param[in] adapter  input adapter to read from
+    */
+    explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format)
+    {
+        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
+    }
+
+    // make class move-only
+    binary_reader(const binary_reader&) = delete;
+    binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    binary_reader& operator=(const binary_reader&) = delete;
+    binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~binary_reader() = default;
+
+    /*!
+    @param[in] format  the binary format to parse
+    @param[in] sax_    a SAX event processor
+    @param[in] strict  whether to expect the input to be consumed completed
+    @param[in] tag_handler  how to treat CBOR tags
+
+    @return whether parsing was successful
+    */
+    JSON_HEDLEY_NON_NULL(3)
+    bool sax_parse(const input_format_t format,
+                   json_sax_t* sax_,
+                   const bool strict = true,
+                   const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        sax = sax_;
+        bool result = false;
+
+        switch (format)
+        {
+            case input_format_t::bson:
+                result = parse_bson_internal();
+                break;
+
+            case input_format_t::cbor:
+                result = parse_cbor_internal(true, tag_handler);
+                break;
+
+            case input_format_t::msgpack:
+                result = parse_msgpack_internal();
+                break;
+
+            case input_format_t::ubjson:
+            case input_format_t::bjdata:
+                result = parse_ubjson_internal();
+                break;
+
+            case input_format_t::json: // LCOV_EXCL_LINE
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+
+        // strict mode: next byte must be EOF
+        if (result && strict)
+        {
+            if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata)
+            {
+                get_ignore_noop();
+            }
+            else
+            {
+                get();
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
+            {
+                return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
+                                        exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
+            }
+        }
+
+        return result;
+    }
+
+  private:
+    //////////
+    // BSON //
+    //////////
+
+    /*!
+    @brief Reads in a BSON-object and passes it to the SAX-parser.
+    @return whether a valid BSON-value was passed to the SAX parser
+    */
+    bool parse_bson_internal()
+    {
+        std::int32_t document_size{};
+        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
+        {
+            return false;
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
+        {
+            return false;
+        }
+
+        return sax->end_object();
+    }
+
+    /*!
+    @brief Parses a C-style string from the BSON input.
+    @param[in,out] result  A reference to the string variable where the read
+                            string is to be stored.
+    @return `true` if the \x00-byte indicating the end of the string was
+             encountered before the EOF; false` indicates an unexpected EOF.
+    */
+    bool get_bson_cstr(string_t& result)
+    {
+        auto out = std::back_inserter(result);
+        while (true)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring")))
+            {
+                return false;
+            }
+            if (current == 0x00)
+            {
+                return true;
+            }
+            *out++ = static_cast<typename string_t::value_type>(current);
+        }
+    }
+
+    /*!
+    @brief Parses a zero-terminated string of length @a len from the BSON
+           input.
+    @param[in] len  The length (including the zero-byte at the end) of the
+                    string to be read.
+    @param[in,out] result  A reference to the string variable where the read
+                            string is to be stored.
+    @tparam NumberType The type of the length @a len
+    @pre len >= 1
+    @return `true` if the string was successfully parsed
+    */
+    template<typename NumberType>
+    bool get_bson_string(const NumberType len, string_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(len < 1))
+        {
+            auto last_token = get_token_string();
+            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                    exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
+        }
+
+        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();
+    }
+
+    /*!
+    @brief Parses a byte array input of length @a len from the BSON input.
+    @param[in] len  The length of the byte array to be read.
+    @param[in,out] result  A reference to the binary variable where the read
+                            array is to be stored.
+    @tparam NumberType The type of the length @a len
+    @pre len >= 0
+    @return `true` if the byte array was successfully parsed
+    */
+    template<typename NumberType>
+    bool get_bson_binary(const NumberType len, binary_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(len < 0))
+        {
+            auto last_token = get_token_string();
+            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                    exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
+        }
+
+        // All BSON binary values have a subtype
+        std::uint8_t subtype{};
+        get_number<std::uint8_t>(input_format_t::bson, subtype);
+        result.set_subtype(subtype);
+
+        return get_binary(input_format_t::bson, len, result);
+    }
+
+    /*!
+    @brief Read a BSON document element of the given @a element_type.
+    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
+    @param[in] element_type_parse_position The position in the input stream,
+               where the `element_type` was read.
+    @warning Not all BSON element types are supported yet. An unsupported
+             @a element_type will give rise to a parse_error.114:
+             Unsupported BSON record type 0x...
+    @return whether a valid BSON-object/array was passed to the SAX parser
+    */
+    bool parse_bson_element_internal(const char_int_type element_type,
+                                     const std::size_t element_type_parse_position)
+    {
+        switch (element_type)
+        {
+            case 0x01: // double
+            {
+                double number{};
+                return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0x02: // string
+            {
+                std::int32_t len{};
+                string_t value;
+                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
+            }
+
+            case 0x03: // object
+            {
+                return parse_bson_internal();
+            }
+
+            case 0x04: // array
+            {
+                return parse_bson_array();
+            }
+
+            case 0x05: // binary
+            {
+                std::int32_t len{};
+                binary_t value;
+                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
+            }
+
+            case 0x08: // boolean
+            {
+                return sax->boolean(get() != 0);
+            }
+
+            case 0x0A: // null
+            {
+                return sax->null();
+            }
+
+            case 0x10: // int32
+            {
+                std::int32_t value{};
+                return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
+            }
+
+            case 0x12: // int64
+            {
+                std::int64_t value{};
+                return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
+            }
+
+            default: // anything else not supported (yet)
+            {
+                std::array<char, 3> cr{{}};
+                static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                std::string cr_str{cr.data()};
+                return sax->parse_error(element_type_parse_position, cr_str,
+                                        parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief Read a BSON element list (as specified in the BSON-spec)
+
+    The same binary layout is used for objects and arrays, hence it must be
+    indicated with the argument @a is_array which one is expected
+    (true --> array, false --> object).
+
+    @param[in] is_array Determines if the element list being read is to be
+                        treated as an object (@a is_array == false), or as an
+                        array (@a is_array == true).
+    @return whether a valid BSON-object/array was passed to the SAX parser
+    */
+    bool parse_bson_element_list(const bool is_array)
+    {
+        string_t key;
+
+        while (auto element_type = get())
+        {
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list")))
+            {
+                return false;
+            }
+
+            const std::size_t element_type_parse_position = chars_read;
+            if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
+            {
+                return false;
+            }
+
+            if (!is_array && !sax->key(key))
+            {
+                return false;
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
+            {
+                return false;
+            }
+
+            // get_bson_cstr only appends
+            key.clear();
+        }
+
+        return true;
+    }
+
+    /*!
+    @brief Reads an array from the BSON input and passes it to the SAX-parser.
+    @return whether a valid BSON-array was passed to the SAX parser
+    */
+    bool parse_bson_array()
+    {
+        std::int32_t document_size{};
+        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
+        {
+            return false;
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))
+        {
+            return false;
+        }
+
+        return sax->end_array();
+    }
+
+    //////////
+    // CBOR //
+    //////////
+
+    /*!
+    @param[in] get_char  whether a new character should be retrieved from the
+                         input (true) or whether the last read character should
+                         be considered instead (false)
+    @param[in] tag_handler how CBOR tags should be treated
+
+    @return whether a valid CBOR value was passed to the SAX parser
+    */
+    bool parse_cbor_internal(const bool get_char,
+                             const cbor_tag_handler_t tag_handler)
+    {
+        switch (get_char ? get() : current)
+        {
+            // EOF
+            case std::char_traits<char_type>::eof():
+                return unexpect_eof(input_format_t::cbor, "value");
+
+            // Integer 0x00..0x17 (0..23)
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0A:
+            case 0x0B:
+            case 0x0C:
+            case 0x0D:
+            case 0x0E:
+            case 0x0F:
+            case 0x10:
+            case 0x11:
+            case 0x12:
+            case 0x13:
+            case 0x14:
+            case 0x15:
+            case 0x16:
+            case 0x17:
+                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
+
+            case 0x18: // Unsigned integer (one-byte uint8_t follows)
+            {
+                std::uint8_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            case 0x19: // Unsigned integer (two-byte uint16_t follows)
+            {
+                std::uint16_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            case 0x1A: // Unsigned integer (four-byte uint32_t follows)
+            {
+                std::uint32_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
+            {
+                std::uint64_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            // Negative integer -1-0x00..-1-0x17 (-1..-24)
+            case 0x20:
+            case 0x21:
+            case 0x22:
+            case 0x23:
+            case 0x24:
+            case 0x25:
+            case 0x26:
+            case 0x27:
+            case 0x28:
+            case 0x29:
+            case 0x2A:
+            case 0x2B:
+            case 0x2C:
+            case 0x2D:
+            case 0x2E:
+            case 0x2F:
+            case 0x30:
+            case 0x31:
+            case 0x32:
+            case 0x33:
+            case 0x34:
+            case 0x35:
+            case 0x36:
+            case 0x37:
+                return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
+
+            case 0x38: // Negative integer (one-byte uint8_t follows)
+            {
+                std::uint8_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+            }
+
+            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
+            {
+                std::uint16_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+            }
+
+            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
+            {
+                std::uint32_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+            }
+
+            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
+            {
+                std::uint64_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
+                        - static_cast<number_integer_t>(number));
+            }
+
+            // Binary data (0x00..0x17 bytes follow)
+            case 0x40:
+            case 0x41:
+            case 0x42:
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46:
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4A:
+            case 0x4B:
+            case 0x4C:
+            case 0x4D:
+            case 0x4E:
+            case 0x4F:
+            case 0x50:
+            case 0x51:
+            case 0x52:
+            case 0x53:
+            case 0x54:
+            case 0x55:
+            case 0x56:
+            case 0x57:
+            case 0x58: // Binary data (one-byte uint8_t for n follows)
+            case 0x59: // Binary data (two-byte uint16_t for n follow)
+            case 0x5A: // Binary data (four-byte uint32_t for n follow)
+            case 0x5B: // Binary data (eight-byte uint64_t for n follow)
+            case 0x5F: // Binary data (indefinite length)
+            {
+                binary_t b;
+                return get_cbor_binary(b) && sax->binary(b);
+            }
+
+            // UTF-8 string (0x00..0x17 bytes follow)
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x6D:
+            case 0x6E:
+            case 0x6F:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
+            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
+            case 0x7F: // UTF-8 string (indefinite length)
+            {
+                string_t s;
+                return get_cbor_string(s) && sax->string(s);
+            }
+
+            // array (0x00..0x17 data items follow)
+            case 0x80:
+            case 0x81:
+            case 0x82:
+            case 0x83:
+            case 0x84:
+            case 0x85:
+            case 0x86:
+            case 0x87:
+            case 0x88:
+            case 0x89:
+            case 0x8A:
+            case 0x8B:
+            case 0x8C:
+            case 0x8D:
+            case 0x8E:
+            case 0x8F:
+            case 0x90:
+            case 0x91:
+            case 0x92:
+            case 0x93:
+            case 0x94:
+            case 0x95:
+            case 0x96:
+            case 0x97:
+                return get_cbor_array(
+                           conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
+
+            case 0x98: // array (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x99: // array (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x9A: // array (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x9B: // array (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x9F: // array (indefinite length)
+                return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
+
+            // map (0x00..0x17 pairs of data items follow)
+            case 0xA0:
+            case 0xA1:
+            case 0xA2:
+            case 0xA3:
+            case 0xA4:
+            case 0xA5:
+            case 0xA6:
+            case 0xA7:
+            case 0xA8:
+            case 0xA9:
+            case 0xAA:
+            case 0xAB:
+            case 0xAC:
+            case 0xAD:
+            case 0xAE:
+            case 0xAF:
+            case 0xB0:
+            case 0xB1:
+            case 0xB2:
+            case 0xB3:
+            case 0xB4:
+            case 0xB5:
+            case 0xB6:
+            case 0xB7:
+                return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
+
+            case 0xB8: // map (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xB9: // map (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xBA: // map (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xBB: // map (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xBF: // map (indefinite length)
+                return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
+
+            case 0xC6: // tagged item
+            case 0xC7:
+            case 0xC8:
+            case 0xC9:
+            case 0xCA:
+            case 0xCB:
+            case 0xCC:
+            case 0xCD:
+            case 0xCE:
+            case 0xCF:
+            case 0xD0:
+            case 0xD1:
+            case 0xD2:
+            case 0xD3:
+            case 0xD4:
+            case 0xD8: // tagged item (1 bytes follow)
+            case 0xD9: // tagged item (2 bytes follow)
+            case 0xDA: // tagged item (4 bytes follow)
+            case 0xDB: // tagged item (8 bytes follow)
+            {
+                switch (tag_handler)
+                {
+                    case cbor_tag_handler_t::error:
+                    {
+                        auto last_token = get_token_string();
+                        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                                exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
+                    }
+
+                    case cbor_tag_handler_t::ignore:
+                    {
+                        // ignore binary subtype
+                        switch (current)
+                        {
+                            case 0xD8:
+                            {
+                                std::uint8_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            case 0xD9:
+                            {
+                                std::uint16_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            case 0xDA:
+                            {
+                                std::uint32_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            case 0xDB:
+                            {
+                                std::uint64_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            default:
+                                break;
+                        }
+                        return parse_cbor_internal(true, tag_handler);
+                    }
+
+                    case cbor_tag_handler_t::store:
+                    {
+                        binary_t b;
+                        // use binary subtype and store in binary container
+                        switch (current)
+                        {
+                            case 0xD8:
+                            {
+                                std::uint8_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            case 0xD9:
+                            {
+                                std::uint16_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            case 0xDA:
+                            {
+                                std::uint32_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            case 0xDB:
+                            {
+                                std::uint64_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            default:
+                                return parse_cbor_internal(true, tag_handler);
+                        }
+                        get();
+                        return get_cbor_binary(b) && sax->binary(b);
+                    }
+
+                    default:                 // LCOV_EXCL_LINE
+                        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+                        return false;        // LCOV_EXCL_LINE
+                }
+            }
+
+            case 0xF4: // false
+                return sax->boolean(false);
+
+            case 0xF5: // true
+                return sax->boolean(true);
+
+            case 0xF6: // null
+                return sax->null();
+
+            case 0xF9: // Half-Precision Float (two-byte IEEE 754)
+            {
+                const auto byte1_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
+                {
+                    return false;
+                }
+                const auto byte2_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
+                {
+                    return false;
+                }
+
+                const auto byte1 = static_cast<unsigned char>(byte1_raw);
+                const auto byte2 = static_cast<unsigned char>(byte2_raw);
+
+                // code from RFC 7049, Appendix D, Figure 3:
+                // As half-precision floating-point numbers were only added
+                // to IEEE 754 in 2008, today's programming platforms often
+                // still only have limited support for them. It is very
+                // easy to include at least decoding support for them even
+                // without such support. An example of a small decoder for
+                // half-precision floating-point numbers in the C language
+                // is shown in Fig. 3.
+                const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
+                const double val = [&half]
+                {
+                    const int exp = (half >> 10u) & 0x1Fu;
+                    const unsigned int mant = half & 0x3FFu;
+                    JSON_ASSERT(0 <= exp&& exp <= 32);
+                    JSON_ASSERT(mant <= 1024);
+                    switch (exp)
+                    {
+                        case 0:
+                            return std::ldexp(mant, -24);
+                        case 31:
+                            return (mant == 0)
+                            ? std::numeric_limits<double>::infinity()
+                            : std::numeric_limits<double>::quiet_NaN();
+                        default:
+                            return std::ldexp(mant + 1024, exp - 25);
+                    }
+                }();
+                return sax->number_float((half & 0x8000u) != 0
+                                         ? static_cast<number_float_t>(-val)
+                                         : static_cast<number_float_t>(val), "");
+            }
+
+            case 0xFA: // Single-Precision Float (four-byte IEEE 754)
+            {
+                float number{};
+                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
+            {
+                double number{};
+                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            default: // anything else (0xFF is handled inside the other types)
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a CBOR string
+
+    This function first reads starting bytes to determine the expected
+    string length and then copies this number of bytes into a string.
+    Additionally, CBOR's strings with indefinite lengths are supported.
+
+    @param[out] result  created string
+
+    @return whether string creation completed
+    */
+    bool get_cbor_string(string_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            // UTF-8 string (0x00..0x17 bytes follow)
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x6D:
+            case 0x6E:
+            case 0x6F:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            {
+                return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
+            }
+
+            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x7F: // UTF-8 string (indefinite length)
+            {
+                while (get() != 0xFF)
+                {
+                    string_t chunk;
+                    if (!get_cbor_string(chunk))
+                    {
+                        return false;
+                    }
+                    result.append(chunk);
+                }
+                return true;
+            }
+
+            default:
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                        exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a CBOR byte array
+
+    This function first reads starting bytes to determine the expected
+    byte array length and then copies this number of bytes into the byte array.
+    Additionally, CBOR's byte arrays with indefinite lengths are supported.
+
+    @param[out] result  created byte array
+
+    @return whether byte array creation completed
+    */
+    bool get_cbor_binary(binary_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            // Binary data (0x00..0x17 bytes follow)
+            case 0x40:
+            case 0x41:
+            case 0x42:
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46:
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4A:
+            case 0x4B:
+            case 0x4C:
+            case 0x4D:
+            case 0x4E:
+            case 0x4F:
+            case 0x50:
+            case 0x51:
+            case 0x52:
+            case 0x53:
+            case 0x54:
+            case 0x55:
+            case 0x56:
+            case 0x57:
+            {
+                return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
+            }
+
+            case 0x58: // Binary data (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x59: // Binary data (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x5A: // Binary data (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x5B: // Binary data (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x5F: // Binary data (indefinite length)
+            {
+                while (get() != 0xFF)
+                {
+                    binary_t chunk;
+                    if (!get_cbor_binary(chunk))
+                    {
+                        return false;
+                    }
+                    result.insert(result.end(), chunk.begin(), chunk.end());
+                }
+                return true;
+            }
+
+            default:
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                        exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @param[in] len  the length of the array or static_cast<std::size_t>(-1) for an
+                    array of indefinite size
+    @param[in] tag_handler how CBOR tags should be treated
+    @return whether array creation completed
+    */
+    bool get_cbor_array(const std::size_t len,
+                        const cbor_tag_handler_t tag_handler)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
+        {
+            return false;
+        }
+
+        if (len != static_cast<std::size_t>(-1))
+        {
+            for (std::size_t i = 0; i < len; ++i)
+            {
+                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            while (get() != 0xFF)
+            {
+                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
+                {
+                    return false;
+                }
+            }
+        }
+
+        return sax->end_array();
+    }
+
+    /*!
+    @param[in] len  the length of the object or static_cast<std::size_t>(-1) for an
+                    object of indefinite size
+    @param[in] tag_handler how CBOR tags should be treated
+    @return whether object creation completed
+    */
+    bool get_cbor_object(const std::size_t len,
+                         const cbor_tag_handler_t tag_handler)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
+        {
+            return false;
+        }
+
+        if (len != 0)
+        {
+            string_t key;
+            if (len != static_cast<std::size_t>(-1))
+            {
+                for (std::size_t i = 0; i < len; ++i)
+                {
+                    get();
+                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+
+                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+            else
+            {
+                while (get() != 0xFF)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+
+                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+        }
+
+        return sax->end_object();
+    }
+
+    /////////////
+    // MsgPack //
+    /////////////
+
+    /*!
+    @return whether a valid MessagePack value was passed to the SAX parser
+    */
+    bool parse_msgpack_internal()
+    {
+        switch (get())
+        {
+            // EOF
+            case std::char_traits<char_type>::eof():
+                return unexpect_eof(input_format_t::msgpack, "value");
+
+            // positive fixint
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0A:
+            case 0x0B:
+            case 0x0C:
+            case 0x0D:
+            case 0x0E:
+            case 0x0F:
+            case 0x10:
+            case 0x11:
+            case 0x12:
+            case 0x13:
+            case 0x14:
+            case 0x15:
+            case 0x16:
+            case 0x17:
+            case 0x18:
+            case 0x19:
+            case 0x1A:
+            case 0x1B:
+            case 0x1C:
+            case 0x1D:
+            case 0x1E:
+            case 0x1F:
+            case 0x20:
+            case 0x21:
+            case 0x22:
+            case 0x23:
+            case 0x24:
+            case 0x25:
+            case 0x26:
+            case 0x27:
+            case 0x28:
+            case 0x29:
+            case 0x2A:
+            case 0x2B:
+            case 0x2C:
+            case 0x2D:
+            case 0x2E:
+            case 0x2F:
+            case 0x30:
+            case 0x31:
+            case 0x32:
+            case 0x33:
+            case 0x34:
+            case 0x35:
+            case 0x36:
+            case 0x37:
+            case 0x38:
+            case 0x39:
+            case 0x3A:
+            case 0x3B:
+            case 0x3C:
+            case 0x3D:
+            case 0x3E:
+            case 0x3F:
+            case 0x40:
+            case 0x41:
+            case 0x42:
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46:
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4A:
+            case 0x4B:
+            case 0x4C:
+            case 0x4D:
+            case 0x4E:
+            case 0x4F:
+            case 0x50:
+            case 0x51:
+            case 0x52:
+            case 0x53:
+            case 0x54:
+            case 0x55:
+            case 0x56:
+            case 0x57:
+            case 0x58:
+            case 0x59:
+            case 0x5A:
+            case 0x5B:
+            case 0x5C:
+            case 0x5D:
+            case 0x5E:
+            case 0x5F:
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x6D:
+            case 0x6E:
+            case 0x6F:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            case 0x78:
+            case 0x79:
+            case 0x7A:
+            case 0x7B:
+            case 0x7C:
+            case 0x7D:
+            case 0x7E:
+            case 0x7F:
+                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
+
+            // fixmap
+            case 0x80:
+            case 0x81:
+            case 0x82:
+            case 0x83:
+            case 0x84:
+            case 0x85:
+            case 0x86:
+            case 0x87:
+            case 0x88:
+            case 0x89:
+            case 0x8A:
+            case 0x8B:
+            case 0x8C:
+            case 0x8D:
+            case 0x8E:
+            case 0x8F:
+                return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
+
+            // fixarray
+            case 0x90:
+            case 0x91:
+            case 0x92:
+            case 0x93:
+            case 0x94:
+            case 0x95:
+            case 0x96:
+            case 0x97:
+            case 0x98:
+            case 0x99:
+            case 0x9A:
+            case 0x9B:
+            case 0x9C:
+            case 0x9D:
+            case 0x9E:
+            case 0x9F:
+                return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
+
+            // fixstr
+            case 0xA0:
+            case 0xA1:
+            case 0xA2:
+            case 0xA3:
+            case 0xA4:
+            case 0xA5:
+            case 0xA6:
+            case 0xA7:
+            case 0xA8:
+            case 0xA9:
+            case 0xAA:
+            case 0xAB:
+            case 0xAC:
+            case 0xAD:
+            case 0xAE:
+            case 0xAF:
+            case 0xB0:
+            case 0xB1:
+            case 0xB2:
+            case 0xB3:
+            case 0xB4:
+            case 0xB5:
+            case 0xB6:
+            case 0xB7:
+            case 0xB8:
+            case 0xB9:
+            case 0xBA:
+            case 0xBB:
+            case 0xBC:
+            case 0xBD:
+            case 0xBE:
+            case 0xBF:
+            case 0xD9: // str 8
+            case 0xDA: // str 16
+            case 0xDB: // str 32
+            {
+                string_t s;
+                return get_msgpack_string(s) && sax->string(s);
+            }
+
+            case 0xC0: // nil
+                return sax->null();
+
+            case 0xC2: // false
+                return sax->boolean(false);
+
+            case 0xC3: // true
+                return sax->boolean(true);
+
+            case 0xC4: // bin 8
+            case 0xC5: // bin 16
+            case 0xC6: // bin 32
+            case 0xC7: // ext 8
+            case 0xC8: // ext 16
+            case 0xC9: // ext 32
+            case 0xD4: // fixext 1
+            case 0xD5: // fixext 2
+            case 0xD6: // fixext 4
+            case 0xD7: // fixext 8
+            case 0xD8: // fixext 16
+            {
+                binary_t b;
+                return get_msgpack_binary(b) && sax->binary(b);
+            }
+
+            case 0xCA: // float 32
+            {
+                float number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0xCB: // float 64
+            {
+                double number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0xCC: // uint 8
+            {
+                std::uint8_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xCD: // uint 16
+            {
+                std::uint16_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xCE: // uint 32
+            {
+                std::uint32_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xCF: // uint 64
+            {
+                std::uint64_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xD0: // int 8
+            {
+                std::int8_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xD1: // int 16
+            {
+                std::int16_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xD2: // int 32
+            {
+                std::int32_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xD3: // int 64
+            {
+                std::int64_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xDC: // array 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
+            }
+
+            case 0xDD: // array 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
+            }
+
+            case 0xDE: // map 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
+            }
+
+            case 0xDF: // map 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
+            }
+
+            // negative fixint
+            case 0xE0:
+            case 0xE1:
+            case 0xE2:
+            case 0xE3:
+            case 0xE4:
+            case 0xE5:
+            case 0xE6:
+            case 0xE7:
+            case 0xE8:
+            case 0xE9:
+            case 0xEA:
+            case 0xEB:
+            case 0xEC:
+            case 0xED:
+            case 0xEE:
+            case 0xEF:
+            case 0xF0:
+            case 0xF1:
+            case 0xF2:
+            case 0xF3:
+            case 0xF4:
+            case 0xF5:
+            case 0xF6:
+            case 0xF7:
+            case 0xF8:
+            case 0xF9:
+            case 0xFA:
+            case 0xFB:
+            case 0xFC:
+            case 0xFD:
+            case 0xFE:
+            case 0xFF:
+                return sax->number_integer(static_cast<std::int8_t>(current));
+
+            default: // anything else
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a MessagePack string
+
+    This function first reads starting bytes to determine the expected
+    string length and then copies this number of bytes into a string.
+
+    @param[out] result  created string
+
+    @return whether string creation completed
+    */
+    bool get_msgpack_string(string_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            // fixstr
+            case 0xA0:
+            case 0xA1:
+            case 0xA2:
+            case 0xA3:
+            case 0xA4:
+            case 0xA5:
+            case 0xA6:
+            case 0xA7:
+            case 0xA8:
+            case 0xA9:
+            case 0xAA:
+            case 0xAB:
+            case 0xAC:
+            case 0xAD:
+            case 0xAE:
+            case 0xAF:
+            case 0xB0:
+            case 0xB1:
+            case 0xB2:
+            case 0xB3:
+            case 0xB4:
+            case 0xB5:
+            case 0xB6:
+            case 0xB7:
+            case 0xB8:
+            case 0xB9:
+            case 0xBA:
+            case 0xBB:
+            case 0xBC:
+            case 0xBD:
+            case 0xBE:
+            case 0xBF:
+            {
+                return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
+            }
+
+            case 0xD9: // str 8
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+            }
+
+            case 0xDA: // str 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+            }
+
+            case 0xDB: // str 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+            }
+
+            default:
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                        exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a MessagePack byte array
+
+    This function first reads starting bytes to determine the expected
+    byte array length and then copies this number of bytes into a byte array.
+
+    @param[out] result  created byte array
+
+    @return whether byte array creation completed
+    */
+    bool get_msgpack_binary(binary_t& result)
+    {
+        // helper function to set the subtype
+        auto assign_and_return_true = [&result](std::int8_t subtype)
+        {
+            result.set_subtype(static_cast<std::uint8_t>(subtype));
+            return true;
+        };
+
+        switch (current)
+        {
+            case 0xC4: // bin 8
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_binary(input_format_t::msgpack, len, result);
+            }
+
+            case 0xC5: // bin 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_binary(input_format_t::msgpack, len, result);
+            }
+
+            case 0xC6: // bin 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_binary(input_format_t::msgpack, len, result);
+            }
+
+            case 0xC7: // ext 8
+            {
+                std::uint8_t len{};
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, len, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xC8: // ext 16
+            {
+                std::uint16_t len{};
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, len, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xC9: // ext 32
+            {
+                std::uint32_t len{};
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, len, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD4: // fixext 1
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 1, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD5: // fixext 2
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 2, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD6: // fixext 4
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 4, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD7: // fixext 8
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 8, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD8: // fixext 16
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 16, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            default:           // LCOV_EXCL_LINE
+                return false;  // LCOV_EXCL_LINE
+        }
+    }
+
+    /*!
+    @param[in] len  the length of the array
+    @return whether array creation completed
+    */
+    bool get_msgpack_array(const std::size_t len)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
+        {
+            return false;
+        }
+
+        for (std::size_t i = 0; i < len; ++i)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
+            {
+                return false;
+            }
+        }
+
+        return sax->end_array();
+    }
+
+    /*!
+    @param[in] len  the length of the object
+    @return whether object creation completed
+    */
+    bool get_msgpack_object(const std::size_t len)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
+        {
+            return false;
+        }
+
+        string_t key;
+        for (std::size_t i = 0; i < len; ++i)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
+            {
+                return false;
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
+            {
+                return false;
+            }
+            key.clear();
+        }
+
+        return sax->end_object();
+    }
+
+    ////////////
+    // UBJSON //
+    ////////////
+
+    /*!
+    @param[in] get_char  whether a new character should be retrieved from the
+                         input (true, default) or whether the last read
+                         character should be considered instead
+
+    @return whether a valid UBJSON value was passed to the SAX parser
+    */
+    bool parse_ubjson_internal(const bool get_char = true)
+    {
+        return get_ubjson_value(get_char ? get_ignore_noop() : current);
+    }
+
+    /*!
+    @brief reads a UBJSON string
+
+    This function is either called after reading the 'S' byte explicitly
+    indicating a string, or in case of an object key where the 'S' byte can be
+    left out.
+
+    @param[out] result   created string
+    @param[in] get_char  whether a new character should be retrieved from the
+                         input (true, default) or whether the last read
+                         character should be considered instead
+
+    @return whether string creation completed
+    */
+    bool get_ubjson_string(string_t& result, const bool get_char = true)
+    {
+        if (get_char)
+        {
+            get();  // TODO(niels): may we ignore N here?
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            case 'U':
+            {
+                std::uint8_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'i':
+            {
+                std::int8_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'I':
+            {
+                std::int16_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'l':
+            {
+                std::int32_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'L':
+            {
+                std::int64_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'u':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint16_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'm':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint32_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'M':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint64_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            default:
+                break;
+        }
+        auto last_token = get_token_string();
+        std::string message;
+
+        if (input_format != input_format_t::bjdata)
+        {
+            message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
+        }
+        else
+        {
+            message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
+        }
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
+    }
+
+    /*!
+    @param[out] dim  an integer vector storing the ND array dimensions
+    @return whether reading ND array size vector is successful
+    */
+    bool get_ubjson_ndarray_size(std::vector<size_t>& dim)
+    {
+        std::pair<std::size_t, char_int_type> size_and_type;
+        size_t dimlen = 0;
+        bool no_ndarray = true;
+
+        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray)))
+        {
+            return false;
+        }
+
+        if (size_and_type.first != npos)
+        {
+            if (size_and_type.second != 0)
+            {
+                if (size_and_type.second != 'N')
+                {
+                    for (std::size_t i = 0; i < size_and_type.first; ++i)
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second)))
+                        {
+                            return false;
+                        }
+                        dim.push_back(dimlen);
+                    }
+                }
+            }
+            else
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray)))
+                    {
+                        return false;
+                    }
+                    dim.push_back(dimlen);
+                }
+            }
+        }
+        else
+        {
+            while (current != ']')
+            {
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current)))
+                {
+                    return false;
+                }
+                dim.push_back(dimlen);
+                get_ignore_noop();
+            }
+        }
+        return true;
+    }
+
+    /*!
+    @param[out] result  determined size
+    @param[in,out] is_ndarray  for input, `true` means already inside an ndarray vector
+                               or ndarray dimension is not allowed; `false` means ndarray
+                               is allowed; for output, `true` means an ndarray is found;
+                               is_ndarray can only return `true` when its initial value
+                               is `false`
+    @param[in] prefix  type marker if already read, otherwise set to 0
+
+    @return whether size determination completed
+    */
+    bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0)
+    {
+        if (prefix == 0)
+        {
+            prefix = get_ignore_noop();
+        }
+
+        switch (prefix)
+        {
+            case 'U':
+            {
+                std::uint8_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'i':
+            {
+                std::int8_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
+                return true;
+            }
+
+            case 'I':
+            {
+                std::int16_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'l':
+            {
+                std::int32_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'L':
+            {
+                std::int64_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                if (!value_in_range_of<std::size_t>(number))
+                {
+                    return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
+                                            exception_message(input_format, "integer value overflow", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'u':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint16_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'm':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint32_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                result = conditional_static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'M':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint64_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (!value_in_range_of<std::size_t>(number))
+                {
+                    return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
+                                            exception_message(input_format, "integer value overflow", "size"), nullptr));
+                }
+                result = detail::conditional_static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case '[':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr));
+                }
+                std::vector<size_t> dim;
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
+                {
+                    return false;
+                }
+                if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector
+                {
+                    result = dim.at(dim.size() - 1);
+                    return true;
+                }
+                if (!dim.empty())  // if ndarray, convert to an object in JData annotated array format
+                {
+                    for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container
+                    {
+                        if ( i == 0 )
+                        {
+                            result = 0;
+                            return true;
+                        }
+                    }
+
+                    string_t key = "_ArraySize_";
+                    if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
+                    {
+                        return false;
+                    }
+                    result = 1;
+                    for (auto i : dim)
+                    {
+                        result *= i;
+                        if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type()
+                        {
+                            return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
+                        }
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i))))
+                        {
+                            return false;
+                        }
+                    }
+                    is_ndarray = true;
+                    return sax->end_array();
+                }
+                result = 0;
+                return true;
+            }
+
+            default:
+                break;
+        }
+        auto last_token = get_token_string();
+        std::string message;
+
+        if (input_format != input_format_t::bjdata)
+        {
+            message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
+        }
+        else
+        {
+            message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
+        }
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
+    }
+
+    /*!
+    @brief determine the type and size for a container
+
+    In the optimized UBJSON format, a type and a size can be provided to allow
+    for a more compact representation.
+
+    @param[out] result  pair of the size and the type
+    @param[in] inside_ndarray  whether the parser is parsing an ND array dimensional vector
+
+    @return whether pair creation completed
+    */
+    bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false)
+    {
+        result.first = npos; // size
+        result.second = 0; // type
+        bool is_ndarray = false;
+
+        get_ignore_noop();
+
+        if (current == '$')
+        {
+            result.second = get();  // must not ignore 'N', because 'N' maybe the type
+            if (input_format == input_format_t::bjdata
+                    && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type")))
+            {
+                return false;
+            }
+
+            get_ignore_noop();
+            if (JSON_HEDLEY_UNLIKELY(current != '#'))
+            {
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
+                {
+                    return false;
+                }
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
+            }
+
+            bool is_error = get_ubjson_size_value(result.first, is_ndarray);
+            if (input_format == input_format_t::bjdata && is_ndarray)
+            {
+                if (inside_ndarray)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
+                                            exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
+                }
+                result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
+            }
+            return is_error;
+        }
+
+        if (current == '#')
+        {
+            bool is_error = get_ubjson_size_value(result.first, is_ndarray);
+            if (input_format == input_format_t::bjdata && is_ndarray)
+            {
+                return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
+                                        exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
+            }
+            return is_error;
+        }
+
+        return true;
+    }
+
+    /*!
+    @param prefix  the previously read or set type prefix
+    @return whether value creation completed
+    */
+    bool get_ubjson_value(const char_int_type prefix)
+    {
+        switch (prefix)
+        {
+            case std::char_traits<char_type>::eof():  // EOF
+                return unexpect_eof(input_format, "value");
+
+            case 'T':  // true
+                return sax->boolean(true);
+            case 'F':  // false
+                return sax->boolean(false);
+
+            case 'Z':  // null
+                return sax->null();
+
+            case 'U':
+            {
+                std::uint8_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'i':
+            {
+                std::int8_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'I':
+            {
+                std::int16_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'l':
+            {
+                std::int32_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'L':
+            {
+                std::int64_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'u':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint16_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'm':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint32_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'M':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint64_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'h':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                const auto byte1_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
+                {
+                    return false;
+                }
+                const auto byte2_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
+                {
+                    return false;
+                }
+
+                const auto byte1 = static_cast<unsigned char>(byte1_raw);
+                const auto byte2 = static_cast<unsigned char>(byte2_raw);
+
+                // code from RFC 7049, Appendix D, Figure 3:
+                // As half-precision floating-point numbers were only added
+                // to IEEE 754 in 2008, today's programming platforms often
+                // still only have limited support for them. It is very
+                // easy to include at least decoding support for them even
+                // without such support. An example of a small decoder for
+                // half-precision floating-point numbers in the C language
+                // is shown in Fig. 3.
+                const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);
+                const double val = [&half]
+                {
+                    const int exp = (half >> 10u) & 0x1Fu;
+                    const unsigned int mant = half & 0x3FFu;
+                    JSON_ASSERT(0 <= exp&& exp <= 32);
+                    JSON_ASSERT(mant <= 1024);
+                    switch (exp)
+                    {
+                        case 0:
+                            return std::ldexp(mant, -24);
+                        case 31:
+                            return (mant == 0)
+                            ? std::numeric_limits<double>::infinity()
+                            : std::numeric_limits<double>::quiet_NaN();
+                        default:
+                            return std::ldexp(mant + 1024, exp - 25);
+                    }
+                }();
+                return sax->number_float((half & 0x8000u) != 0
+                                         ? static_cast<number_float_t>(-val)
+                                         : static_cast<number_float_t>(val), "");
+            }
+
+            case 'd':
+            {
+                float number{};
+                return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 'D':
+            {
+                double number{};
+                return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 'H':
+            {
+                return get_ubjson_high_precision_number();
+            }
+
+            case 'C':  // char
+            {
+                get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char")))
+                {
+                    return false;
+                }
+                if (JSON_HEDLEY_UNLIKELY(current > 127))
+                {
+                    auto last_token = get_token_string();
+                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                            exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
+                }
+                string_t s(1, static_cast<typename string_t::value_type>(current));
+                return sax->string(s);
+            }
+
+            case 'S':  // string
+            {
+                string_t s;
+                return get_ubjson_string(s) && sax->string(s);
+            }
+
+            case '[':  // array
+                return get_ubjson_array();
+
+            case '{':  // object
+                return get_ubjson_object();
+
+            default: // anything else
+                break;
+        }
+        auto last_token = get_token_string();
+        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr));
+    }
+
+    /*!
+    @return whether array creation completed
+    */
+    bool get_ubjson_array()
+    {
+        std::pair<std::size_t, char_int_type> size_and_type;
+        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
+        {
+            return false;
+        }
+
+        // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
+        // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
+
+        if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
+        {
+            size_and_type.second &= ~(static_cast<char_int_type>(1) << 8);  // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
+            auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)
+            {
+                return p.first < t;
+            });
+            string_t key = "_ArrayType_";
+            if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
+            }
+
+            string_t type = it->second; // sax->string() takes a reference
+            if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
+            {
+                return false;
+            }
+
+            if (size_and_type.second == 'C')
+            {
+                size_and_type.second = 'U';
+            }
+
+            key = "_ArrayData_";
+            if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
+            {
+                return false;
+            }
+
+            for (std::size_t i = 0; i < size_and_type.first; ++i)
+            {
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+                {
+                    return false;
+                }
+            }
+
+            return (sax->end_array() && sax->end_object());
+        }
+
+        if (size_and_type.first != npos)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
+            {
+                return false;
+            }
+
+            if (size_and_type.second != 0)
+            {
+                if (size_and_type.second != 'N')
+                {
+                    for (std::size_t i = 0; i < size_and_type.first; ++i)
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+                        {
+                            return false;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        else
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
+            {
+                return false;
+            }
+
+            while (current != ']')
+            {
+                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))
+                {
+                    return false;
+                }
+                get_ignore_noop();
+            }
+        }
+
+        return sax->end_array();
+    }
+
+    /*!
+    @return whether object creation completed
+    */
+    bool get_ubjson_object()
+    {
+        std::pair<std::size_t, char_int_type> size_and_type;
+        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
+        {
+            return false;
+        }
+
+        // do not accept ND-array size in objects in BJData
+        if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
+        {
+            auto last_token = get_token_string();
+            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                    exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr));
+        }
+
+        string_t key;
+        if (size_and_type.first != npos)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
+            {
+                return false;
+            }
+
+            if (size_and_type.second != 0)
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+            else
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+        }
+        else
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
+            {
+                return false;
+            }
+
+            while (current != '}')
+            {
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
+                {
+                    return false;
+                }
+                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+                {
+                    return false;
+                }
+                get_ignore_noop();
+                key.clear();
+            }
+        }
+
+        return sax->end_object();
+    }
+
+    // Note, no reader for UBJSON binary types is implemented because they do
+    // not exist
+
+    bool get_ubjson_high_precision_number()
+    {
+        // get size of following number string
+        std::size_t size{};
+        bool no_ndarray = true;
+        auto res = get_ubjson_size_value(size, no_ndarray);
+        if (JSON_HEDLEY_UNLIKELY(!res))
+        {
+            return res;
+        }
+
+        // get number string
+        std::vector<char> number_vector;
+        for (std::size_t i = 0; i < size; ++i)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
+            {
+                return false;
+            }
+            number_vector.push_back(static_cast<char>(current));
+        }
+
+        // parse number string
+        using ia_type = decltype(detail::input_adapter(number_vector));
+        auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);
+        const auto result_number = number_lexer.scan();
+        const auto number_string = number_lexer.get_token_string();
+        const auto result_remainder = number_lexer.scan();
+
+        using token_type = typename detail::lexer_base<BasicJsonType>::token_type;
+
+        if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
+        {
+            return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
+                                    exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
+        }
+
+        switch (result_number)
+        {
+            case token_type::value_integer:
+                return sax->number_integer(number_lexer.get_number_integer());
+            case token_type::value_unsigned:
+                return sax->number_unsigned(number_lexer.get_number_unsigned());
+            case token_type::value_float:
+                return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
+            case token_type::uninitialized:
+            case token_type::literal_true:
+            case token_type::literal_false:
+            case token_type::literal_null:
+            case token_type::value_string:
+            case token_type::begin_array:
+            case token_type::begin_object:
+            case token_type::end_array:
+            case token_type::end_object:
+            case token_type::name_separator:
+            case token_type::value_separator:
+            case token_type::parse_error:
+            case token_type::end_of_input:
+            case token_type::literal_or_value:
+            default:
+                return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
+                                        exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
+        }
+    }
+
+    ///////////////////////
+    // Utility functions //
+    ///////////////////////
+
+    /*!
+    @brief get next character from the input
+
+    This function provides the interface to the used input adapter. It does
+    not throw in case the input reached EOF, but returns a -'ve valued
+    `std::char_traits<char_type>::eof()` in that case.
+
+    @return character read from the input
+    */
+    char_int_type get()
+    {
+        ++chars_read;
+        return current = ia.get_character();
+    }
+
+    /*!
+    @return character read from the input after ignoring all 'N' entries
+    */
+    char_int_type get_ignore_noop()
+    {
+        do
+        {
+            get();
+        }
+        while (current == 'N');
+
+        return current;
+    }
+
+    /*
+    @brief read a number from the input
+
+    @tparam NumberType the type of the number
+    @param[in] format   the current format (for diagnostics)
+    @param[out] result  number of type @a NumberType
+
+    @return whether conversion completed
+
+    @note This function needs to respect the system's endianness, because
+          bytes in CBOR, MessagePack, and UBJSON are stored in network order
+          (big endian) and therefore need reordering on little endian systems.
+          On the other hand, BSON and BJData use little endian and should reorder
+          on big endian systems.
+    */
+    template<typename NumberType, bool InputIsLittleEndian = false>
+    bool get_number(const input_format_t format, NumberType& result)
+    {
+        // step 1: read input into array with system's byte order
+        std::array<std::uint8_t, sizeof(NumberType)> vec{};
+        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
+            {
+                return false;
+            }
+
+            // reverse byte order prior to conversion if necessary
+            if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
+            {
+                vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
+            }
+            else
+            {
+                vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
+            }
+        }
+
+        // step 2: convert array into number of type T and return
+        std::memcpy(&result, vec.data(), sizeof(NumberType));
+        return true;
+    }
+
+    /*!
+    @brief create a string by reading characters from the input
+
+    @tparam NumberType the type of the number
+    @param[in] format the current format (for diagnostics)
+    @param[in] len number of characters to read
+    @param[out] result string created by reading @a len bytes
+
+    @return whether string creation completed
+
+    @note We can not reserve @a len bytes for the result, because @a len
+          may be too large. Usually, @ref unexpect_eof() detects the end of
+          the input before we run out of string memory.
+    */
+    template<typename NumberType>
+    bool get_string(const input_format_t format,
+                    const NumberType len,
+                    string_t& result)
+    {
+        bool success = true;
+        for (NumberType i = 0; i < len; i++)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string")))
+            {
+                success = false;
+                break;
+            }
+            result.push_back(static_cast<typename string_t::value_type>(current));
+        }
+        return success;
+    }
+
+    /*!
+    @brief create a byte array by reading bytes from the input
+
+    @tparam NumberType the type of the number
+    @param[in] format the current format (for diagnostics)
+    @param[in] len number of bytes to read
+    @param[out] result byte array created by reading @a len bytes
+
+    @return whether byte array creation completed
+
+    @note We can not reserve @a len bytes for the result, because @a len
+          may be too large. Usually, @ref unexpect_eof() detects the end of
+          the input before we run out of memory.
+    */
+    template<typename NumberType>
+    bool get_binary(const input_format_t format,
+                    const NumberType len,
+                    binary_t& result)
+    {
+        bool success = true;
+        for (NumberType i = 0; i < len; i++)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary")))
+            {
+                success = false;
+                break;
+            }
+            result.push_back(static_cast<std::uint8_t>(current));
+        }
+        return success;
+    }
+
+    /*!
+    @param[in] format   the current format (for diagnostics)
+    @param[in] context  further context information (for diagnostics)
+    @return whether the last read character is not EOF
+    */
+    JSON_HEDLEY_NON_NULL(3)
+    bool unexpect_eof(const input_format_t format, const char* context) const
+    {
+        if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
+        {
+            return sax->parse_error(chars_read, "<end of file>",
+                                    parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
+        }
+        return true;
+    }
+
+    /*!
+    @return a string representation of the last read byte
+    */
+    std::string get_token_string() const
+    {
+        std::array<char, 3> cr{{}};
+        static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+        return std::string{cr.data()};
+    }
+
+    /*!
+    @param[in] format   the current format
+    @param[in] detail   a detailed error message
+    @param[in] context  further context information
+    @return a message string to use in the parse_error exceptions
+    */
+    std::string exception_message(const input_format_t format,
+                                  const std::string& detail,
+                                  const std::string& context) const
+    {
+        std::string error_msg = "syntax error while parsing ";
+
+        switch (format)
+        {
+            case input_format_t::cbor:
+                error_msg += "CBOR";
+                break;
+
+            case input_format_t::msgpack:
+                error_msg += "MessagePack";
+                break;
+
+            case input_format_t::ubjson:
+                error_msg += "UBJSON";
+                break;
+
+            case input_format_t::bson:
+                error_msg += "BSON";
+                break;
+
+            case input_format_t::bjdata:
+                error_msg += "BJData";
+                break;
+
+            case input_format_t::json: // LCOV_EXCL_LINE
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+
+        return concat(error_msg, ' ', context, ": ", detail);
+    }
+
+  private:
+    static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1);
+
+    /// input adapter
+    InputAdapterType ia;
+
+    /// the current character
+    char_int_type current = std::char_traits<char_type>::eof();
+
+    /// the number of characters read
+    std::size_t chars_read = 0;
+
+    /// whether we can assume little endianness
+    const bool is_little_endian = little_endianness();
+
+    /// input format
+    const input_format_t input_format = input_format_t::json;
+
+    /// the SAX parser
+    json_sax_t* sax = nullptr;
+
+    // excluded markers in bjdata optimized type
+#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \
+    make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')
+
+#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \
+    make_array<bjd_type>(                      \
+    bjd_type{'C', "char"},                     \
+    bjd_type{'D', "double"},                   \
+    bjd_type{'I', "int16"},                    \
+    bjd_type{'L', "int64"},                    \
+    bjd_type{'M', "uint64"},                   \
+    bjd_type{'U', "uint8"},                    \
+    bjd_type{'d', "single"},                   \
+    bjd_type{'i', "int8"},                     \
+    bjd_type{'l', "int32"},                    \
+    bjd_type{'m', "uint32"},                   \
+    bjd_type{'u', "uint16"})
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    // lookup tables
+    // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
+    const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =
+        JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;
+
+    using bjd_type = std::pair<char_int_type, string_t>;
+    // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
+    const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =
+        JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;
+
+#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_
+#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_
+};
+
+#ifndef JSON_HAS_CPP_17
+    template<typename BasicJsonType, typename InputAdapterType, typename SAX>
+    constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos;
+#endif
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/input_adapters.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/input_adapters.h
new file mode 100644
index 0000000..49dd812
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/input_adapters.h
@@ -0,0 +1,494 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <array> // array
+#include <cstddef> // size_t
+#include <cstring> // strlen
+#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
+#include <memory> // shared_ptr, make_shared, addressof
+#include <numeric> // accumulate
+#include <string> // string, char_traits
+#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
+#include <utility> // pair, declval
+
+#ifndef JSON_NO_IO
+    #include <cstdio>   // FILE *
+    #include <istream>  // istream
+#endif                  // JSON_NO_IO
+
+#include <wpi/detail/iterators/iterator_traits.h>
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// the supported input formats
+enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };
+
+////////////////////
+// input adapters //
+////////////////////
+
+#ifndef JSON_NO_IO
+/*!
+Input adapter for stdio file access. This adapter read only 1 byte and do not use any
+ buffer. This adapter is a very low level adapter.
+*/
+class file_input_adapter
+{
+  public:
+    using char_type = char;
+
+    JSON_HEDLEY_NON_NULL(2)
+    explicit file_input_adapter(std::FILE* f) noexcept
+        : m_file(f)
+    {
+        JSON_ASSERT(m_file != nullptr);
+    }
+
+    // make class move-only
+    file_input_adapter(const file_input_adapter&) = delete;
+    file_input_adapter(file_input_adapter&&) noexcept = default;
+    file_input_adapter& operator=(const file_input_adapter&) = delete;
+    file_input_adapter& operator=(file_input_adapter&&) = delete;
+    ~file_input_adapter() = default;
+
+    std::char_traits<char>::int_type get_character() noexcept
+    {
+        return std::fgetc(m_file);
+    }
+
+  private:
+    /// the file pointer to read from
+    std::FILE* m_file;
+};
+
+
+/*!
+Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
+beginning of input. Does not support changing the underlying std::streambuf
+in mid-input. Maintains underlying std::istream and std::streambuf to support
+subsequent use of standard std::istream operations to process any input
+characters following those used in parsing the JSON input.  Clears the
+std::istream flags; any input errors (e.g., EOF) will be detected by the first
+subsequent call for input from the std::istream.
+*/
+class input_stream_adapter
+{
+  public:
+    using char_type = char;
+
+    ~input_stream_adapter()
+    {
+        // clear stream flags; we use underlying streambuf I/O, do not
+        // maintain ifstream flags, except eof
+        if (is != nullptr)
+        {
+            is->clear(is->rdstate() & std::ios::eofbit);
+        }
+    }
+
+    explicit input_stream_adapter(std::istream& i)
+        : is(&i), sb(i.rdbuf())
+    {}
+
+    // delete because of pointer members
+    input_stream_adapter(const input_stream_adapter&) = delete;
+    input_stream_adapter& operator=(input_stream_adapter&) = delete;
+    input_stream_adapter& operator=(input_stream_adapter&&) = delete;
+
+    input_stream_adapter(input_stream_adapter&& rhs) noexcept
+        : is(rhs.is), sb(rhs.sb)
+    {
+        rhs.is = nullptr;
+        rhs.sb = nullptr;
+    }
+
+    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
+    // ensure that std::char_traits<char>::eof() and the character 0xFF do not
+    // end up as the same value, e.g. 0xFFFFFFFF.
+    std::char_traits<char>::int_type get_character()
+    {
+        auto res = sb->sbumpc();
+        // set eof manually, as we don't use the istream interface.
+        if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
+        {
+            is->clear(is->rdstate() | std::ios::eofbit);
+        }
+        return res;
+    }
+
+  private:
+    /// the associated input stream
+    std::istream* is = nullptr;
+    std::streambuf* sb = nullptr;
+};
+#endif  // JSON_NO_IO
+
+// General-purpose iterator-based adapter. It might not be as fast as
+// theoretically possible for some containers, but it is extremely versatile.
+template<typename IteratorType>
+class iterator_input_adapter
+{
+  public:
+    using char_type = typename std::iterator_traits<IteratorType>::value_type;
+
+    iterator_input_adapter(IteratorType first, IteratorType last)
+        : current(std::move(first)), end(std::move(last))
+    {}
+
+    typename std::char_traits<char_type>::int_type get_character()
+    {
+        if (JSON_HEDLEY_LIKELY(current != end))
+        {
+            auto result = std::char_traits<char_type>::to_int_type(*current);
+            std::advance(current, 1);
+            return result;
+        }
+
+        return std::char_traits<char_type>::eof();
+    }
+
+  private:
+    IteratorType current;
+    IteratorType end;
+
+    template<typename BaseInputAdapter, size_t T>
+    friend struct wide_string_input_helper;
+
+    bool empty() const
+    {
+        return current == end;
+    }
+};
+
+
+template<typename BaseInputAdapter, size_t T>
+struct wide_string_input_helper;
+
+template<typename BaseInputAdapter>
+struct wide_string_input_helper<BaseInputAdapter, 4>
+{
+    // UTF-32
+    static void fill_buffer(BaseInputAdapter& input,
+                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
+                            size_t& utf8_bytes_index,
+                            size_t& utf8_bytes_filled)
+    {
+        utf8_bytes_index = 0;
+
+        if (JSON_HEDLEY_UNLIKELY(input.empty()))
+        {
+            utf8_bytes[0] = std::char_traits<char>::eof();
+            utf8_bytes_filled = 1;
+        }
+        else
+        {
+            // get the current character
+            const auto wc = input.get_character();
+
+            // UTF-32 to UTF-8 encoding
+            if (wc < 0x80)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                utf8_bytes_filled = 1;
+            }
+            else if (wc <= 0x7FF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 2;
+            }
+            else if (wc <= 0xFFFF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
+                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 3;
+            }
+            else if (wc <= 0x10FFFF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));
+                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
+                utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 4;
+            }
+            else
+            {
+                // unknown character
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                utf8_bytes_filled = 1;
+            }
+        }
+    }
+};
+
+template<typename BaseInputAdapter>
+struct wide_string_input_helper<BaseInputAdapter, 2>
+{
+    // UTF-16
+    static void fill_buffer(BaseInputAdapter& input,
+                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
+                            size_t& utf8_bytes_index,
+                            size_t& utf8_bytes_filled)
+    {
+        utf8_bytes_index = 0;
+
+        if (JSON_HEDLEY_UNLIKELY(input.empty()))
+        {
+            utf8_bytes[0] = std::char_traits<char>::eof();
+            utf8_bytes_filled = 1;
+        }
+        else
+        {
+            // get the current character
+            const auto wc = input.get_character();
+
+            // UTF-16 to UTF-8 encoding
+            if (wc < 0x80)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                utf8_bytes_filled = 1;
+            }
+            else if (wc <= 0x7FF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 2;
+            }
+            else if (0xD800 > wc || wc >= 0xE000)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
+                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 3;
+            }
+            else
+            {
+                if (JSON_HEDLEY_UNLIKELY(!input.empty()))
+                {
+                    const auto wc2 = static_cast<unsigned int>(input.get_character());
+                    const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
+                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
+                    utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
+                    utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
+                    utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
+                    utf8_bytes_filled = 4;
+                }
+                else
+                {
+                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                    utf8_bytes_filled = 1;
+                }
+            }
+        }
+    }
+};
+
+// Wraps another input apdater to convert wide character types into individual bytes.
+template<typename BaseInputAdapter, typename WideCharType>
+class wide_string_input_adapter
+{
+  public:
+    using char_type = char;
+
+    wide_string_input_adapter(BaseInputAdapter base)
+        : base_adapter(base) {}
+
+    typename std::char_traits<char>::int_type get_character() noexcept
+    {
+        // check if buffer needs to be filled
+        if (utf8_bytes_index == utf8_bytes_filled)
+        {
+            fill_buffer<sizeof(WideCharType)>();
+
+            JSON_ASSERT(utf8_bytes_filled > 0);
+            JSON_ASSERT(utf8_bytes_index == 0);
+        }
+
+        // use buffer
+        JSON_ASSERT(utf8_bytes_filled > 0);
+        JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
+        return utf8_bytes[utf8_bytes_index++];
+    }
+
+  private:
+    BaseInputAdapter base_adapter;
+
+    template<size_t T>
+    void fill_buffer()
+    {
+        wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
+    }
+
+    /// a buffer for UTF-8 bytes
+    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
+
+    /// index to the utf8_codes array for the next valid byte
+    std::size_t utf8_bytes_index = 0;
+    /// number of valid bytes in the utf8_codes array
+    std::size_t utf8_bytes_filled = 0;
+};
+
+
+template<typename IteratorType, typename Enable = void>
+struct iterator_input_adapter_factory
+{
+    using iterator_type = IteratorType;
+    using char_type = typename std::iterator_traits<iterator_type>::value_type;
+    using adapter_type = iterator_input_adapter<iterator_type>;
+
+    static adapter_type create(IteratorType first, IteratorType last)
+    {
+        return adapter_type(std::move(first), std::move(last));
+    }
+};
+
+template<typename T>
+struct is_iterator_of_multibyte
+{
+    using value_type = typename std::iterator_traits<T>::value_type;
+    enum
+    {
+        value = sizeof(value_type) > 1
+    };
+};
+
+template<typename IteratorType>
+struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
+{
+    using iterator_type = IteratorType;
+    using char_type = typename std::iterator_traits<iterator_type>::value_type;
+    using base_adapter_type = iterator_input_adapter<iterator_type>;
+    using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
+
+    static adapter_type create(IteratorType first, IteratorType last)
+    {
+        return adapter_type(base_adapter_type(std::move(first), std::move(last)));
+    }
+};
+
+// General purpose iterator-based input
+template<typename IteratorType>
+typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
+{
+    using factory_type = iterator_input_adapter_factory<IteratorType>;
+    return factory_type::create(first, last);
+}
+
+// Convenience shorthand from container to iterator
+// Enables ADL on begin(container) and end(container)
+// Encloses the using declarations in namespace for not to leak them to outside scope
+
+namespace container_input_adapter_factory_impl
+{
+
+using std::begin;
+using std::end;
+
+template<typename ContainerType, typename Enable = void>
+struct container_input_adapter_factory {};
+
+template<typename ContainerType>
+struct container_input_adapter_factory< ContainerType,
+       void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
+       {
+           using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
+
+           static adapter_type create(const ContainerType& container)
+{
+    return input_adapter(begin(container), end(container));
+}
+       };
+
+}  // namespace container_input_adapter_factory_impl
+
+template<typename ContainerType>
+typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
+{
+    return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
+}
+
+#ifndef JSON_NO_IO
+// Special cases with fast paths
+inline file_input_adapter input_adapter(std::FILE* file)
+{
+    return file_input_adapter(file);
+}
+
+inline input_stream_adapter input_adapter(std::istream& stream)
+{
+    return input_stream_adapter(stream);
+}
+
+inline input_stream_adapter input_adapter(std::istream&& stream)
+{
+    return input_stream_adapter(stream);
+}
+#endif  // JSON_NO_IO
+
+using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
+
+// Null-delimited strings, and the like.
+template < typename CharT,
+           typename std::enable_if <
+               std::is_pointer<CharT>::value&&
+               !std::is_array<CharT>::value&&
+               std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
+               sizeof(typename std::remove_pointer<CharT>::type) == 1,
+               int >::type = 0 >
+contiguous_bytes_input_adapter input_adapter(CharT b)
+{
+    auto length = std::strlen(reinterpret_cast<const char*>(b));
+    const auto* ptr = reinterpret_cast<const char*>(b);
+    return input_adapter(ptr, ptr + length);
+}
+
+template<typename T, std::size_t N>
+auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+{
+    return input_adapter(array, array + N);
+}
+
+// This class only handles inputs of input_buffer_adapter type.
+// It's required so that expressions like {ptr, len} can be implicitly cast
+// to the correct adapter.
+class span_input_adapter
+{
+  public:
+    template < typename CharT,
+               typename std::enable_if <
+                   std::is_pointer<CharT>::value&&
+                   std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
+                   sizeof(typename std::remove_pointer<CharT>::type) == 1,
+                   int >::type = 0 >
+    span_input_adapter(CharT b, std::size_t l)
+        : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
+
+    template<class IteratorType,
+             typename std::enable_if<
+                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
+                 int>::type = 0>
+    span_input_adapter(IteratorType first, IteratorType last)
+        : ia(input_adapter(first, last)) {}
+
+    contiguous_bytes_input_adapter&& get()
+    {
+        return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
+    }
+
+  private:
+    contiguous_bytes_input_adapter ia;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/json_sax.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/json_sax.h
new file mode 100644
index 0000000..6e763e7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/json_sax.h
@@ -0,0 +1,728 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstddef>
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/string_concat.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+/*!
+@brief SAX interface
+
+This class describes the SAX interface used by @ref wpi::json::sax_parse.
+Each function is called in different situations while the input is parsed. The
+boolean return value informs the parser whether to continue processing the
+input.
+*/
+template<typename BasicJsonType>
+struct json_sax
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+
+    /*!
+    @brief a null value was read
+    @return whether parsing should proceed
+    */
+    virtual bool null() = 0;
+
+    /*!
+    @brief a boolean value was read
+    @param[in] val  boolean value
+    @return whether parsing should proceed
+    */
+    virtual bool boolean(bool val) = 0;
+
+    /*!
+    @brief an integer number was read
+    @param[in] val  integer value
+    @return whether parsing should proceed
+    */
+    virtual bool number_integer(number_integer_t val) = 0;
+
+    /*!
+    @brief an unsigned integer number was read
+    @param[in] val  unsigned integer value
+    @return whether parsing should proceed
+    */
+    virtual bool number_unsigned(number_unsigned_t val) = 0;
+
+    /*!
+    @brief a floating-point number was read
+    @param[in] val  floating-point value
+    @param[in] s    raw token value
+    @return whether parsing should proceed
+    */
+    virtual bool number_float(number_float_t val, const string_t& s) = 0;
+
+    /*!
+    @brief a string value was read
+    @param[in] val  string value
+    @return whether parsing should proceed
+    @note It is safe to move the passed string value.
+    */
+    virtual bool string(string_t& val) = 0;
+
+    /*!
+    @brief a binary value was read
+    @param[in] val  binary value
+    @return whether parsing should proceed
+    @note It is safe to move the passed binary value.
+    */
+    virtual bool binary(binary_t& val) = 0;
+
+    /*!
+    @brief the beginning of an object was read
+    @param[in] elements  number of object elements or -1 if unknown
+    @return whether parsing should proceed
+    @note binary formats may report the number of elements
+    */
+    virtual bool start_object(std::size_t elements) = 0;
+
+    /*!
+    @brief an object key was read
+    @param[in] val  object key
+    @return whether parsing should proceed
+    @note It is safe to move the passed string.
+    */
+    virtual bool key(string_t& val) = 0;
+
+    /*!
+    @brief the end of an object was read
+    @return whether parsing should proceed
+    */
+    virtual bool end_object() = 0;
+
+    /*!
+    @brief the beginning of an array was read
+    @param[in] elements  number of array elements or -1 if unknown
+    @return whether parsing should proceed
+    @note binary formats may report the number of elements
+    */
+    virtual bool start_array(std::size_t elements) = 0;
+
+    /*!
+    @brief the end of an array was read
+    @return whether parsing should proceed
+    */
+    virtual bool end_array() = 0;
+
+    /*!
+    @brief a parse error occurred
+    @param[in] position    the position in the input where the error occurs
+    @param[in] last_token  the last read token
+    @param[in] ex          an exception object describing the error
+    @return whether parsing should proceed (must return false)
+    */
+    virtual bool parse_error(std::size_t position,
+                             const std::string& last_token,
+                             const detail::exception& ex) = 0;
+
+    json_sax() = default;
+    json_sax(const json_sax&) = default;
+    json_sax(json_sax&&) noexcept = default;
+    json_sax& operator=(const json_sax&) = default;
+    json_sax& operator=(json_sax&&) noexcept = default;
+    virtual ~json_sax() = default;
+};
+
+
+namespace detail
+{
+/*!
+@brief SAX implementation to create a JSON value from SAX events
+
+This class implements the @ref json_sax interface and processes the SAX events
+to create a JSON value which makes it basically a DOM parser. The structure or
+hierarchy of the JSON value is managed by the stack `ref_stack` which contains
+a pointer to the respective array or object for each recursion depth.
+
+After successful parsing, the value that is passed by reference to the
+constructor contains the parsed value.
+
+@tparam BasicJsonType  the JSON type
+*/
+template<typename BasicJsonType>
+class json_sax_dom_parser
+{
+  public:
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+
+    /*!
+    @param[in,out] r  reference to a JSON value that is manipulated while
+                       parsing
+    @param[in] allow_exceptions_  whether parse errors yield exceptions
+    */
+    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
+        : root(r), allow_exceptions(allow_exceptions_)
+    {}
+
+    // make class move-only
+    json_sax_dom_parser(const json_sax_dom_parser&) = delete;
+    json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
+    json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~json_sax_dom_parser() = default;
+
+    bool null()
+    {
+        handle_value(nullptr);
+        return true;
+    }
+
+    bool boolean(bool val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_integer(number_integer_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_unsigned(number_unsigned_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_float(number_float_t val, const string_t& /*unused*/)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool string(string_t& val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool binary(binary_t& val)
+    {
+        handle_value(std::move(val));
+        return true;
+    }
+
+    bool start_object(std::size_t len)
+    {
+        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
+
+        if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool key(string_t& val)
+    {
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(ref_stack.back()->is_object());
+
+        // add null at given key and store the reference for later
+        object_element = &(ref_stack.back()->m_value.object->operator[](val));
+        return true;
+    }
+
+    bool end_object()
+    {
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(ref_stack.back()->is_object());
+
+        ref_stack.back()->set_parents();
+        ref_stack.pop_back();
+        return true;
+    }
+
+    bool start_array(std::size_t len)
+    {
+        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
+
+        if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool end_array()
+    {
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(ref_stack.back()->is_array());
+
+        ref_stack.back()->set_parents();
+        ref_stack.pop_back();
+        return true;
+    }
+
+    template<class Exception>
+    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
+                     const Exception& ex)
+    {
+        errored = true;
+        static_cast<void>(ex);
+        if (allow_exceptions)
+        {
+            JSON_THROW(ex);
+        }
+        return false;
+    }
+
+    constexpr bool is_errored() const
+    {
+        return errored;
+    }
+
+  private:
+    /*!
+    @invariant If the ref stack is empty, then the passed value will be the new
+               root.
+    @invariant If the ref stack contains a value, then it is an array or an
+               object to which we can add elements
+    */
+    template<typename Value>
+    JSON_HEDLEY_RETURNS_NON_NULL
+    BasicJsonType* handle_value(Value&& v)
+    {
+        if (ref_stack.empty())
+        {
+            root = BasicJsonType(std::forward<Value>(v));
+            return &root;
+        }
+
+        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
+
+        if (ref_stack.back()->is_array())
+        {
+            ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
+            return &(ref_stack.back()->m_value.array->back());
+        }
+
+        JSON_ASSERT(ref_stack.back()->is_object());
+        JSON_ASSERT(object_element);
+        *object_element = BasicJsonType(std::forward<Value>(v));
+        return object_element;
+    }
+
+    /// the parsed JSON value
+    BasicJsonType& root;
+    /// stack to model hierarchy of values
+    std::vector<BasicJsonType*> ref_stack {};
+    /// helper to hold the reference for the next object element
+    BasicJsonType* object_element = nullptr;
+    /// whether a syntax error occurred
+    bool errored = false;
+    /// whether to throw exceptions in case of errors
+    const bool allow_exceptions = true;
+};
+
+template<typename BasicJsonType>
+class json_sax_dom_callback_parser
+{
+  public:
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using parser_callback_t = typename BasicJsonType::parser_callback_t;
+    using parse_event_t = typename BasicJsonType::parse_event_t;
+
+    json_sax_dom_callback_parser(BasicJsonType& r,
+                                 const parser_callback_t cb,
+                                 const bool allow_exceptions_ = true)
+        : root(r), callback(cb), allow_exceptions(allow_exceptions_)
+    {
+        keep_stack.push_back(true);
+    }
+
+    // make class move-only
+    json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
+    json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
+    json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~json_sax_dom_callback_parser() = default;
+
+    bool null()
+    {
+        handle_value(nullptr);
+        return true;
+    }
+
+    bool boolean(bool val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_integer(number_integer_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_unsigned(number_unsigned_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_float(number_float_t val, const string_t& /*unused*/)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool string(string_t& val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool binary(binary_t& val)
+    {
+        handle_value(std::move(val));
+        return true;
+    }
+
+    bool start_object(std::size_t len)
+    {
+        // check callback for object start
+        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
+        keep_stack.push_back(keep);
+
+        auto val = handle_value(BasicJsonType::value_t::object, true);
+        ref_stack.push_back(val.second);
+
+        // check object limit
+        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool key(string_t& val)
+    {
+        BasicJsonType k = BasicJsonType(val);
+
+        // check callback for key
+        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
+        key_keep_stack.push_back(keep);
+
+        // add discarded value at given key and store the reference for later
+        if (keep && ref_stack.back())
+        {
+            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
+        }
+
+        return true;
+    }
+
+    bool end_object()
+    {
+        if (ref_stack.back())
+        {
+            if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
+            {
+                // discard object
+                *ref_stack.back() = discarded;
+            }
+            else
+            {
+                ref_stack.back()->set_parents();
+            }
+        }
+
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(!keep_stack.empty());
+        ref_stack.pop_back();
+        keep_stack.pop_back();
+
+        if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
+        {
+            // remove discarded value
+            for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
+            {
+                if (it->is_discarded())
+                {
+                    ref_stack.back()->erase(it);
+                    break;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    bool start_array(std::size_t len)
+    {
+        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
+        keep_stack.push_back(keep);
+
+        auto val = handle_value(BasicJsonType::value_t::array, true);
+        ref_stack.push_back(val.second);
+
+        // check array limit
+        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool end_array()
+    {
+        bool keep = true;
+
+        if (ref_stack.back())
+        {
+            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
+            if (keep)
+            {
+                ref_stack.back()->set_parents();
+            }
+            else
+            {
+                // discard array
+                *ref_stack.back() = discarded;
+            }
+        }
+
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(!keep_stack.empty());
+        ref_stack.pop_back();
+        keep_stack.pop_back();
+
+        // remove discarded value
+        if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
+        {
+            ref_stack.back()->m_value.array->pop_back();
+        }
+
+        return true;
+    }
+
+    template<class Exception>
+    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
+                     const Exception& ex)
+    {
+        errored = true;
+        static_cast<void>(ex);
+        if (allow_exceptions)
+        {
+            JSON_THROW(ex);
+        }
+        return false;
+    }
+
+    constexpr bool is_errored() const
+    {
+        return errored;
+    }
+
+  private:
+    /*!
+    @param[in] v  value to add to the JSON value we build during parsing
+    @param[in] skip_callback  whether we should skip calling the callback
+               function; this is required after start_array() and
+               start_object() SAX events, because otherwise we would call the
+               callback function with an empty array or object, respectively.
+
+    @invariant If the ref stack is empty, then the passed value will be the new
+               root.
+    @invariant If the ref stack contains a value, then it is an array or an
+               object to which we can add elements
+
+    @return pair of boolean (whether value should be kept) and pointer (to the
+            passed value in the ref_stack hierarchy; nullptr if not kept)
+    */
+    template<typename Value>
+    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
+    {
+        JSON_ASSERT(!keep_stack.empty());
+
+        // do not handle this value if we know it would be added to a discarded
+        // container
+        if (!keep_stack.back())
+        {
+            return {false, nullptr};
+        }
+
+        // create value
+        auto value = BasicJsonType(std::forward<Value>(v));
+
+        // check callback
+        const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
+
+        // do not handle this value if we just learnt it shall be discarded
+        if (!keep)
+        {
+            return {false, nullptr};
+        }
+
+        if (ref_stack.empty())
+        {
+            root = std::move(value);
+            return {true, &root};
+        }
+
+        // skip this value if we already decided to skip the parent
+        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
+        if (!ref_stack.back())
+        {
+            return {false, nullptr};
+        }
+
+        // we now only expect arrays and objects
+        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
+
+        // array
+        if (ref_stack.back()->is_array())
+        {
+            ref_stack.back()->m_value.array->emplace_back(std::move(value));
+            return {true, &(ref_stack.back()->m_value.array->back())};
+        }
+
+        // object
+        JSON_ASSERT(ref_stack.back()->is_object());
+        // check if we should store an element for the current key
+        JSON_ASSERT(!key_keep_stack.empty());
+        const bool store_element = key_keep_stack.back();
+        key_keep_stack.pop_back();
+
+        if (!store_element)
+        {
+            return {false, nullptr};
+        }
+
+        JSON_ASSERT(object_element);
+        *object_element = std::move(value);
+        return {true, object_element};
+    }
+
+    /// the parsed JSON value
+    BasicJsonType& root;
+    /// stack to model hierarchy of values
+    std::vector<BasicJsonType*> ref_stack {};
+    /// stack to manage which values to keep
+    std::vector<bool> keep_stack {};
+    /// stack to manage which object keys to keep
+    std::vector<bool> key_keep_stack {};
+    /// helper to hold the reference for the next object element
+    BasicJsonType* object_element = nullptr;
+    /// whether a syntax error occurred
+    bool errored = false;
+    /// callback function
+    const parser_callback_t callback = nullptr;
+    /// whether to throw exceptions in case of errors
+    const bool allow_exceptions = true;
+    /// a discarded value for the callback
+    BasicJsonType discarded = BasicJsonType::value_t::discarded;
+};
+
+template<typename BasicJsonType>
+class json_sax_acceptor
+{
+  public:
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+
+    bool null()
+    {
+        return true;
+    }
+
+    bool boolean(bool /*unused*/)
+    {
+        return true;
+    }
+
+    bool number_integer(number_integer_t /*unused*/)
+    {
+        return true;
+    }
+
+    bool number_unsigned(number_unsigned_t /*unused*/)
+    {
+        return true;
+    }
+
+    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool string(string_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool binary(binary_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
+    {
+        return true;
+    }
+
+    bool key(string_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool end_object()
+    {
+        return true;
+    }
+
+    bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
+    {
+        return true;
+    }
+
+    bool end_array()
+    {
+        return true;
+    }
+
+    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
+    {
+        return false;
+    }
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/lexer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/lexer.h
new file mode 100644
index 0000000..93fd84a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/lexer.h
@@ -0,0 +1,1632 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <array> // array
+#include <clocale> // localeconv
+#include <cstddef> // size_t
+#include <cstdio> // snprintf
+#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
+#include <initializer_list> // initializer_list
+#include <string> // char_traits, string
+#include <utility> // move
+#include <vector> // vector
+
+#include <wpi/detail/input/input_adapters.h>
+#include <wpi/detail/input/position_t.h>
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////
+// lexer //
+///////////
+
+template<typename BasicJsonType>
+class lexer_base
+{
+  public:
+    /// token types for the parser
+    enum class token_type
+    {
+        uninitialized,    ///< indicating the scanner is uninitialized
+        literal_true,     ///< the `true` literal
+        literal_false,    ///< the `false` literal
+        literal_null,     ///< the `null` literal
+        value_string,     ///< a string -- use get_string() for actual value
+        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value
+        value_integer,    ///< a signed integer -- use get_number_integer() for actual value
+        value_float,      ///< an floating point number -- use get_number_float() for actual value
+        begin_array,      ///< the character for array begin `[`
+        begin_object,     ///< the character for object begin `{`
+        end_array,        ///< the character for array end `]`
+        end_object,       ///< the character for object end `}`
+        name_separator,   ///< the name separator `:`
+        value_separator,  ///< the value separator `,`
+        parse_error,      ///< indicating a parse error
+        end_of_input,     ///< indicating the end of the input buffer
+        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)
+    };
+
+    /// return name of values of type token_type (only used for errors)
+    JSON_HEDLEY_RETURNS_NON_NULL
+    JSON_HEDLEY_CONST
+    static const char* token_type_name(const token_type t) noexcept
+    {
+        switch (t)
+        {
+            case token_type::uninitialized:
+                return "<uninitialized>";
+            case token_type::literal_true:
+                return "true literal";
+            case token_type::literal_false:
+                return "false literal";
+            case token_type::literal_null:
+                return "null literal";
+            case token_type::value_string:
+                return "string literal";
+            case token_type::value_unsigned:
+            case token_type::value_integer:
+            case token_type::value_float:
+                return "number literal";
+            case token_type::begin_array:
+                return "'['";
+            case token_type::begin_object:
+                return "'{'";
+            case token_type::end_array:
+                return "']'";
+            case token_type::end_object:
+                return "'}'";
+            case token_type::name_separator:
+                return "':'";
+            case token_type::value_separator:
+                return "','";
+            case token_type::parse_error:
+                return "<parse error>";
+            case token_type::end_of_input:
+                return "end of input";
+            case token_type::literal_or_value:
+                return "'[', '{', or a literal";
+            // LCOV_EXCL_START
+            default: // catch non-enum values
+                return "unknown token";
+                // LCOV_EXCL_STOP
+        }
+    }
+};
+/*!
+@brief lexical analysis
+
+This class organizes the lexical analysis during JSON deserialization.
+*/
+template<typename BasicJsonType, typename InputAdapterType>
+class lexer : public lexer_base<BasicJsonType>
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using char_type = typename InputAdapterType::char_type;
+    using char_int_type = typename std::char_traits<char_type>::int_type;
+
+  public:
+    using token_type = typename lexer_base<BasicJsonType>::token_type;
+
+    explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
+        : ia(std::move(adapter))
+        , ignore_comments(ignore_comments_)
+        , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
+    {}
+
+    // delete because of pointer members
+    lexer(const lexer&) = delete;
+    lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    lexer& operator=(lexer&) = delete;
+    lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~lexer() = default;
+
+  private:
+    /////////////////////
+    // locales
+    /////////////////////
+
+    /// return the locale-dependent decimal point
+    JSON_HEDLEY_PURE
+    static char get_decimal_point() noexcept
+    {
+        const auto* loc = localeconv();
+        JSON_ASSERT(loc != nullptr);
+        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
+    }
+
+    /////////////////////
+    // scan functions
+    /////////////////////
+
+    /*!
+    @brief get codepoint from 4 hex characters following `\u`
+
+    For input "\u c1 c2 c3 c4" the codepoint is:
+      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
+    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
+
+    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
+    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
+    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
+    between the ASCII value of the character and the desired integer value.
+
+    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
+            non-hex character)
+    */
+    int get_codepoint()
+    {
+        // this function only makes sense after reading `\u`
+        JSON_ASSERT(current == 'u');
+        int codepoint = 0;
+
+        const auto factors = { 12u, 8u, 4u, 0u };
+        for (const auto factor : factors)
+        {
+            get();
+
+            if (current >= '0' && current <= '9')
+            {
+                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
+            }
+            else if (current >= 'A' && current <= 'F')
+            {
+                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
+            }
+            else if (current >= 'a' && current <= 'f')
+            {
+                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
+        return codepoint;
+    }
+
+    /*!
+    @brief check if the next byte(s) are inside a given range
+
+    Adds the current byte and, for each passed range, reads a new byte and
+    checks if it is inside the range. If a violation was detected, set up an
+    error message and return false. Otherwise, return true.
+
+    @param[in] ranges  list of integers; interpreted as list of pairs of
+                       inclusive lower and upper bound, respectively
+
+    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
+         1, 2, or 3 pairs. This precondition is enforced by an assertion.
+
+    @return true if and only if no range violation was detected
+    */
+    bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
+    {
+        JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
+        add(current);
+
+        for (auto range = ranges.begin(); range != ranges.end(); ++range)
+        {
+            get();
+            if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))
+            {
+                add(current);
+            }
+            else
+            {
+                error_message = "invalid string: ill-formed UTF-8 byte";
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /*!
+    @brief scan a string literal
+
+    This function scans a string according to Sect. 7 of RFC 8259. While
+    scanning, bytes are escaped and copied into buffer token_buffer. Then the
+    function returns successfully, token_buffer is *not* null-terminated (as it
+    may contain \0 bytes), and token_buffer.size() is the number of bytes in the
+    string.
+
+    @return token_type::value_string if string could be successfully scanned,
+            token_type::parse_error otherwise
+
+    @note In case of errors, variable error_message contains a textual
+          description.
+    */
+    token_type scan_string()
+    {
+        // reset token_buffer (ignore opening quote)
+        reset();
+
+        // we entered the function by reading an open quote
+        JSON_ASSERT(current == '\"');
+
+        while (true)
+        {
+            // get next character
+            switch (get())
+            {
+                // end of file while parsing string
+                case std::char_traits<char_type>::eof():
+                {
+                    error_message = "invalid string: missing closing quote";
+                    return token_type::parse_error;
+                }
+
+                // closing quote
+                case '\"':
+                {
+                    return token_type::value_string;
+                }
+
+                // escapes
+                case '\\':
+                {
+                    switch (get())
+                    {
+                        // quotation mark
+                        case '\"':
+                            add('\"');
+                            break;
+                        // reverse solidus
+                        case '\\':
+                            add('\\');
+                            break;
+                        // solidus
+                        case '/':
+                            add('/');
+                            break;
+                        // backspace
+                        case 'b':
+                            add('\b');
+                            break;
+                        // form feed
+                        case 'f':
+                            add('\f');
+                            break;
+                        // line feed
+                        case 'n':
+                            add('\n');
+                            break;
+                        // carriage return
+                        case 'r':
+                            add('\r');
+                            break;
+                        // tab
+                        case 't':
+                            add('\t');
+                            break;
+
+                        // unicode escapes
+                        case 'u':
+                        {
+                            const int codepoint1 = get_codepoint();
+                            int codepoint = codepoint1; // start with codepoint1
+
+                            if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
+                            {
+                                error_message = "invalid string: '\\u' must be followed by 4 hex digits";
+                                return token_type::parse_error;
+                            }
+
+                            // check if code point is a high surrogate
+                            if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
+                            {
+                                // expect next \uxxxx entry
+                                if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
+                                {
+                                    const int codepoint2 = get_codepoint();
+
+                                    if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))
+                                    {
+                                        error_message = "invalid string: '\\u' must be followed by 4 hex digits";
+                                        return token_type::parse_error;
+                                    }
+
+                                    // check if codepoint2 is a low surrogate
+                                    if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))
+                                    {
+                                        // overwrite codepoint
+                                        codepoint = static_cast<int>(
+                                                        // high surrogate occupies the most significant 22 bits
+                                                        (static_cast<unsigned int>(codepoint1) << 10u)
+                                                        // low surrogate occupies the least significant 15 bits
+                                                        + static_cast<unsigned int>(codepoint2)
+                                                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
+                                                        // in the result, so we have to subtract with:
+                                                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
+                                                        - 0x35FDC00u);
+                                    }
+                                    else
+                                    {
+                                        error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
+                                        return token_type::parse_error;
+                                    }
+                                }
+                                else
+                                {
+                                    error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
+                                    return token_type::parse_error;
+                                }
+                            }
+                            else
+                            {
+                                if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))
+                                {
+                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
+                                    return token_type::parse_error;
+                                }
+                            }
+
+                            // result of the above calculation yields a proper codepoint
+                            JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
+
+                            // translate codepoint into bytes
+                            if (codepoint < 0x80)
+                            {
+                                // 1-byte characters: 0xxxxxxx (ASCII)
+                                add(static_cast<char_int_type>(codepoint));
+                            }
+                            else if (codepoint <= 0x7FF)
+                            {
+                                // 2-byte characters: 110xxxxx 10xxxxxx
+                                add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
+                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
+                            }
+                            else if (codepoint <= 0xFFFF)
+                            {
+                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
+                                add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
+                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
+                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
+                            }
+                            else
+                            {
+                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                                add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
+                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
+                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
+                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
+                            }
+
+                            break;
+                        }
+
+                        // other characters after escape
+                        default:
+                            error_message = "invalid string: forbidden character after backslash";
+                            return token_type::parse_error;
+                    }
+
+                    break;
+                }
+
+                // invalid control characters
+                case 0x00:
+                {
+                    error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
+                    return token_type::parse_error;
+                }
+
+                case 0x01:
+                {
+                    error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
+                    return token_type::parse_error;
+                }
+
+                case 0x02:
+                {
+                    error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
+                    return token_type::parse_error;
+                }
+
+                case 0x03:
+                {
+                    error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
+                    return token_type::parse_error;
+                }
+
+                case 0x04:
+                {
+                    error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
+                    return token_type::parse_error;
+                }
+
+                case 0x05:
+                {
+                    error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
+                    return token_type::parse_error;
+                }
+
+                case 0x06:
+                {
+                    error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
+                    return token_type::parse_error;
+                }
+
+                case 0x07:
+                {
+                    error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
+                    return token_type::parse_error;
+                }
+
+                case 0x08:
+                {
+                    error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
+                    return token_type::parse_error;
+                }
+
+                case 0x09:
+                {
+                    error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
+                    return token_type::parse_error;
+                }
+
+                case 0x0A:
+                {
+                    error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
+                    return token_type::parse_error;
+                }
+
+                case 0x0B:
+                {
+                    error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
+                    return token_type::parse_error;
+                }
+
+                case 0x0C:
+                {
+                    error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
+                    return token_type::parse_error;
+                }
+
+                case 0x0D:
+                {
+                    error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
+                    return token_type::parse_error;
+                }
+
+                case 0x0E:
+                {
+                    error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
+                    return token_type::parse_error;
+                }
+
+                case 0x0F:
+                {
+                    error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
+                    return token_type::parse_error;
+                }
+
+                case 0x10:
+                {
+                    error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
+                    return token_type::parse_error;
+                }
+
+                case 0x11:
+                {
+                    error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
+                    return token_type::parse_error;
+                }
+
+                case 0x12:
+                {
+                    error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
+                    return token_type::parse_error;
+                }
+
+                case 0x13:
+                {
+                    error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
+                    return token_type::parse_error;
+                }
+
+                case 0x14:
+                {
+                    error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
+                    return token_type::parse_error;
+                }
+
+                case 0x15:
+                {
+                    error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
+                    return token_type::parse_error;
+                }
+
+                case 0x16:
+                {
+                    error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
+                    return token_type::parse_error;
+                }
+
+                case 0x17:
+                {
+                    error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
+                    return token_type::parse_error;
+                }
+
+                case 0x18:
+                {
+                    error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
+                    return token_type::parse_error;
+                }
+
+                case 0x19:
+                {
+                    error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
+                    return token_type::parse_error;
+                }
+
+                case 0x1A:
+                {
+                    error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
+                    return token_type::parse_error;
+                }
+
+                case 0x1B:
+                {
+                    error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
+                    return token_type::parse_error;
+                }
+
+                case 0x1C:
+                {
+                    error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
+                    return token_type::parse_error;
+                }
+
+                case 0x1D:
+                {
+                    error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
+                    return token_type::parse_error;
+                }
+
+                case 0x1E:
+                {
+                    error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
+                    return token_type::parse_error;
+                }
+
+                case 0x1F:
+                {
+                    error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
+                    return token_type::parse_error;
+                }
+
+                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
+                case 0x20:
+                case 0x21:
+                case 0x23:
+                case 0x24:
+                case 0x25:
+                case 0x26:
+                case 0x27:
+                case 0x28:
+                case 0x29:
+                case 0x2A:
+                case 0x2B:
+                case 0x2C:
+                case 0x2D:
+                case 0x2E:
+                case 0x2F:
+                case 0x30:
+                case 0x31:
+                case 0x32:
+                case 0x33:
+                case 0x34:
+                case 0x35:
+                case 0x36:
+                case 0x37:
+                case 0x38:
+                case 0x39:
+                case 0x3A:
+                case 0x3B:
+                case 0x3C:
+                case 0x3D:
+                case 0x3E:
+                case 0x3F:
+                case 0x40:
+                case 0x41:
+                case 0x42:
+                case 0x43:
+                case 0x44:
+                case 0x45:
+                case 0x46:
+                case 0x47:
+                case 0x48:
+                case 0x49:
+                case 0x4A:
+                case 0x4B:
+                case 0x4C:
+                case 0x4D:
+                case 0x4E:
+                case 0x4F:
+                case 0x50:
+                case 0x51:
+                case 0x52:
+                case 0x53:
+                case 0x54:
+                case 0x55:
+                case 0x56:
+                case 0x57:
+                case 0x58:
+                case 0x59:
+                case 0x5A:
+                case 0x5B:
+                case 0x5D:
+                case 0x5E:
+                case 0x5F:
+                case 0x60:
+                case 0x61:
+                case 0x62:
+                case 0x63:
+                case 0x64:
+                case 0x65:
+                case 0x66:
+                case 0x67:
+                case 0x68:
+                case 0x69:
+                case 0x6A:
+                case 0x6B:
+                case 0x6C:
+                case 0x6D:
+                case 0x6E:
+                case 0x6F:
+                case 0x70:
+                case 0x71:
+                case 0x72:
+                case 0x73:
+                case 0x74:
+                case 0x75:
+                case 0x76:
+                case 0x77:
+                case 0x78:
+                case 0x79:
+                case 0x7A:
+                case 0x7B:
+                case 0x7C:
+                case 0x7D:
+                case 0x7E:
+                case 0x7F:
+                {
+                    add(current);
+                    break;
+                }
+
+                // U+0080..U+07FF: bytes C2..DF 80..BF
+                case 0xC2:
+                case 0xC3:
+                case 0xC4:
+                case 0xC5:
+                case 0xC6:
+                case 0xC7:
+                case 0xC8:
+                case 0xC9:
+                case 0xCA:
+                case 0xCB:
+                case 0xCC:
+                case 0xCD:
+                case 0xCE:
+                case 0xCF:
+                case 0xD0:
+                case 0xD1:
+                case 0xD2:
+                case 0xD3:
+                case 0xD4:
+                case 0xD5:
+                case 0xD6:
+                case 0xD7:
+                case 0xD8:
+                case 0xD9:
+                case 0xDA:
+                case 0xDB:
+                case 0xDC:
+                case 0xDD:
+                case 0xDE:
+                case 0xDF:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
+                case 0xE0:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
+                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
+                case 0xE1:
+                case 0xE2:
+                case 0xE3:
+                case 0xE4:
+                case 0xE5:
+                case 0xE6:
+                case 0xE7:
+                case 0xE8:
+                case 0xE9:
+                case 0xEA:
+                case 0xEB:
+                case 0xEC:
+                case 0xEE:
+                case 0xEF:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+D000..U+D7FF: bytes ED 80..9F 80..BF
+                case 0xED:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
+                case 0xF0:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
+                case 0xF1:
+                case 0xF2:
+                case 0xF3:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
+                case 0xF4:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // remaining bytes (80..C1 and F5..FF) are ill-formed
+                default:
+                {
+                    error_message = "invalid string: ill-formed UTF-8 byte";
+                    return token_type::parse_error;
+                }
+            }
+        }
+    }
+
+    /*!
+     * @brief scan a comment
+     * @return whether comment could be scanned successfully
+     */
+    bool scan_comment()
+    {
+        switch (get())
+        {
+            // single-line comments skip input until a newline or EOF is read
+            case '/':
+            {
+                while (true)
+                {
+                    switch (get())
+                    {
+                        case '\n':
+                        case '\r':
+                        case std::char_traits<char_type>::eof():
+                        case '\0':
+                            return true;
+
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            // multi-line comments skip input until */ is read
+            case '*':
+            {
+                while (true)
+                {
+                    switch (get())
+                    {
+                        case std::char_traits<char_type>::eof():
+                        case '\0':
+                        {
+                            error_message = "invalid comment; missing closing '*/'";
+                            return false;
+                        }
+
+                        case '*':
+                        {
+                            switch (get())
+                            {
+                                case '/':
+                                    return true;
+
+                                default:
+                                {
+                                    unget();
+                                    continue;
+                                }
+                            }
+                        }
+
+                        default:
+                            continue;
+                    }
+                }
+            }
+
+            // unexpected character after reading '/'
+            default:
+            {
+                error_message = "invalid comment; expecting '/' or '*' after '/'";
+                return false;
+            }
+        }
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    static void strtof(float& f, const char* str, char** endptr) noexcept
+    {
+        f = std::strtof(str, endptr);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    static void strtof(double& f, const char* str, char** endptr) noexcept
+    {
+        f = std::strtod(str, endptr);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    static void strtof(long double& f, const char* str, char** endptr) noexcept
+    {
+        f = std::strtold(str, endptr);
+    }
+
+    /*!
+    @brief scan a number literal
+
+    This function scans a string according to Sect. 6 of RFC 8259.
+
+    The function is realized with a deterministic finite state machine derived
+    from the grammar described in RFC 8259. Starting in state "init", the
+    input is read and used to determined the next state. Only state "done"
+    accepts the number. State "error" is a trap state to model errors. In the
+    table below, "anything" means any character but the ones listed before.
+
+    state    | 0        | 1-9      | e E      | +       | -       | .        | anything
+    ---------|----------|----------|----------|---------|---------|----------|-----------
+    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]
+    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]
+    zero     | done     | done     | exponent | done    | done    | decimal1 | done
+    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done
+    decimal1 | decimal2 | decimal2 | [error]  | [error] | [error] | [error]  | [error]
+    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done
+    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]
+    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]
+    any2     | any2     | any2     | done     | done    | done    | done     | done
+
+    The state machine is realized with one label per state (prefixed with
+    "scan_number_") and `goto` statements between them. The state machine
+    contains cycles, but any cycle can be left when EOF is read. Therefore,
+    the function is guaranteed to terminate.
+
+    During scanning, the read bytes are stored in token_buffer. This string is
+    then converted to a signed integer, an unsigned integer, or a
+    floating-point number.
+
+    @return token_type::value_unsigned, token_type::value_integer, or
+            token_type::value_float if number could be successfully scanned,
+            token_type::parse_error otherwise
+
+    @note The scanner is independent of the current locale. Internally, the
+          locale's decimal point is used instead of `.` to work with the
+          locale-dependent converters.
+    */
+    token_type scan_number()  // lgtm [cpp/use-of-goto]
+    {
+        // reset token_buffer to store the number's bytes
+        reset();
+
+        // the type of the parsed number; initially set to unsigned; will be
+        // changed if minus sign, decimal point or exponent is read
+        token_type number_type = token_type::value_unsigned;
+
+        // state (init): we just found out we need to scan a number
+        switch (current)
+        {
+            case '-':
+            {
+                add(current);
+                goto scan_number_minus;
+            }
+
+            case '0':
+            {
+                add(current);
+                goto scan_number_zero;
+            }
+
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any1;
+            }
+
+            // all other characters are rejected outside scan_number()
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+
+scan_number_minus:
+        // state: we just parsed a leading minus sign
+        number_type = token_type::value_integer;
+        switch (get())
+        {
+            case '0':
+            {
+                add(current);
+                goto scan_number_zero;
+            }
+
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any1;
+            }
+
+            default:
+            {
+                error_message = "invalid number; expected digit after '-'";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_zero:
+        // state: we just parse a zero (maybe with a leading minus sign)
+        switch (get())
+        {
+            case '.':
+            {
+                add(decimal_point_char);
+                goto scan_number_decimal1;
+            }
+
+            case 'e':
+            case 'E':
+            {
+                add(current);
+                goto scan_number_exponent;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_any1:
+        // state: we just parsed a number 0-9 (maybe with a leading minus sign)
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any1;
+            }
+
+            case '.':
+            {
+                add(decimal_point_char);
+                goto scan_number_decimal1;
+            }
+
+            case 'e':
+            case 'E':
+            {
+                add(current);
+                goto scan_number_exponent;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_decimal1:
+        // state: we just parsed a decimal point
+        number_type = token_type::value_float;
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_decimal2;
+            }
+
+            default:
+            {
+                error_message = "invalid number; expected digit after '.'";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_decimal2:
+        // we just parsed at least one number after a decimal point
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_decimal2;
+            }
+
+            case 'e':
+            case 'E':
+            {
+                add(current);
+                goto scan_number_exponent;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_exponent:
+        // we just parsed an exponent
+        number_type = token_type::value_float;
+        switch (get())
+        {
+            case '+':
+            case '-':
+            {
+                add(current);
+                goto scan_number_sign;
+            }
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any2;
+            }
+
+            default:
+            {
+                error_message =
+                    "invalid number; expected '+', '-', or digit after exponent";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_sign:
+        // we just parsed an exponent sign
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any2;
+            }
+
+            default:
+            {
+                error_message = "invalid number; expected digit after exponent sign";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_any2:
+        // we just parsed a number after the exponent or exponent sign
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any2;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_done:
+        // unget the character after the number (we only read it to know that
+        // we are done scanning a number)
+        unget();
+
+        char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+        errno = 0;
+
+        // try to parse integers first and fall back to floats
+        if (number_type == token_type::value_unsigned)
+        {
+            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
+
+            // we checked the number format before
+            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
+
+            if (errno == 0)
+            {
+                value_unsigned = static_cast<number_unsigned_t>(x);
+                if (value_unsigned == x)
+                {
+                    return token_type::value_unsigned;
+                }
+            }
+        }
+        else if (number_type == token_type::value_integer)
+        {
+            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
+
+            // we checked the number format before
+            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
+
+            if (errno == 0)
+            {
+                value_integer = static_cast<number_integer_t>(x);
+                if (value_integer == x)
+                {
+                    return token_type::value_integer;
+                }
+            }
+        }
+
+        // this code is reached if we parse a floating-point number or if an
+        // integer conversion above failed
+        strtof(value_float, token_buffer.data(), &endptr);
+
+        // we checked the number format before
+        JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
+
+        return token_type::value_float;
+    }
+
+    /*!
+    @param[in] literal_text  the literal text to expect
+    @param[in] length        the length of the passed literal text
+    @param[in] return_type   the token type to return on success
+    */
+    JSON_HEDLEY_NON_NULL(2)
+    token_type scan_literal(const char_type* literal_text, const std::size_t length,
+                            token_type return_type)
+    {
+        JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
+        for (std::size_t i = 1; i < length; ++i)
+        {
+            if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
+            {
+                error_message = "invalid literal";
+                return token_type::parse_error;
+            }
+        }
+        return return_type;
+    }
+
+    /////////////////////
+    // input management
+    /////////////////////
+
+    /// reset token_buffer; current character is beginning of token
+    void reset() noexcept
+    {
+        token_buffer.clear();
+        token_string.clear();
+        token_string.push_back(std::char_traits<char_type>::to_char_type(current));
+    }
+
+    /*
+    @brief get next character from the input
+
+    This function provides the interface to the used input adapter. It does
+    not throw in case the input reached EOF, but returns a
+    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters
+    for use in error messages.
+
+    @return character read from the input
+    */
+    char_int_type get()
+    {
+        ++position.chars_read_total;
+        ++position.chars_read_current_line;
+
+        if (next_unget)
+        {
+            // just reset the next_unget variable and work with current
+            next_unget = false;
+        }
+        else
+        {
+            current = ia.get_character();
+        }
+
+        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
+        {
+            token_string.push_back(std::char_traits<char_type>::to_char_type(current));
+        }
+
+        if (current == '\n')
+        {
+            ++position.lines_read;
+            position.chars_read_current_line = 0;
+        }
+
+        return current;
+    }
+
+    /*!
+    @brief unget current character (read it again on next get)
+
+    We implement unget by setting variable next_unget to true. The input is not
+    changed - we just simulate ungetting by modifying chars_read_total,
+    chars_read_current_line, and token_string. The next call to get() will
+    behave as if the unget character is read again.
+    */
+    void unget()
+    {
+        next_unget = true;
+
+        --position.chars_read_total;
+
+        // in case we "unget" a newline, we have to also decrement the lines_read
+        if (position.chars_read_current_line == 0)
+        {
+            if (position.lines_read > 0)
+            {
+                --position.lines_read;
+            }
+        }
+        else
+        {
+            --position.chars_read_current_line;
+        }
+
+        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
+        {
+            JSON_ASSERT(!token_string.empty());
+            token_string.pop_back();
+        }
+    }
+
+    /// add a character to token_buffer
+    void add(char_int_type c)
+    {
+        token_buffer.push_back(static_cast<typename string_t::value_type>(c));
+    }
+
+  public:
+    /////////////////////
+    // value getters
+    /////////////////////
+
+    /// return integer value
+    constexpr number_integer_t get_number_integer() const noexcept
+    {
+        return value_integer;
+    }
+
+    /// return unsigned integer value
+    constexpr number_unsigned_t get_number_unsigned() const noexcept
+    {
+        return value_unsigned;
+    }
+
+    /// return floating-point value
+    constexpr number_float_t get_number_float() const noexcept
+    {
+        return value_float;
+    }
+
+    /// return current string value (implicitly resets the token; useful only once)
+    string_t& get_string()
+    {
+        return token_buffer;
+    }
+
+    /////////////////////
+    // diagnostics
+    /////////////////////
+
+    /// return position of last read token
+    constexpr position_t get_position() const noexcept
+    {
+        return position;
+    }
+
+    /// return the last read token (for errors only).  Will never contain EOF
+    /// (an arbitrary value that is not a valid char value, often -1), because
+    /// 255 may legitimately occur.  May contain NUL, which should be escaped.
+    std::string get_token_string() const
+    {
+        // escape control characters
+        std::string result;
+        for (const auto c : token_string)
+        {
+            if (static_cast<unsigned char>(c) <= '\x1F')
+            {
+                // escape control characters
+                std::array<char, 9> cs{{}};
+                static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                result += cs.data();
+            }
+            else
+            {
+                // add character as is
+                result.push_back(static_cast<std::string::value_type>(c));
+            }
+        }
+
+        return result;
+    }
+
+    /// return syntax error message
+    JSON_HEDLEY_RETURNS_NON_NULL
+    constexpr const char* get_error_message() const noexcept
+    {
+        return error_message;
+    }
+
+    /////////////////////
+    // actual scanner
+    /////////////////////
+
+    /*!
+    @brief skip the UTF-8 byte order mark
+    @return true iff there is no BOM or the correct BOM has been skipped
+    */
+    bool skip_bom()
+    {
+        if (get() == 0xEF)
+        {
+            // check if we completely parse the BOM
+            return get() == 0xBB && get() == 0xBF;
+        }
+
+        // the first character is not the beginning of the BOM; unget it to
+        // process is later
+        unget();
+        return true;
+    }
+
+    void skip_whitespace()
+    {
+        do
+        {
+            get();
+        }
+        while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
+    }
+
+    token_type scan()
+    {
+        // initially, skip the BOM
+        if (position.chars_read_total == 0 && !skip_bom())
+        {
+            error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
+            return token_type::parse_error;
+        }
+
+        // read next character and ignore whitespace
+        skip_whitespace();
+
+        // ignore comments
+        while (ignore_comments && current == '/')
+        {
+            if (!scan_comment())
+            {
+                return token_type::parse_error;
+            }
+
+            // skip following whitespace
+            skip_whitespace();
+        }
+
+        switch (current)
+        {
+            // structural characters
+            case '[':
+                return token_type::begin_array;
+            case ']':
+                return token_type::end_array;
+            case '{':
+                return token_type::begin_object;
+            case '}':
+                return token_type::end_object;
+            case ':':
+                return token_type::name_separator;
+            case ',':
+                return token_type::value_separator;
+
+            // literals
+            case 't':
+            {
+                std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}};
+                return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);
+            }
+            case 'f':
+            {
+                std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}};
+                return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);
+            }
+            case 'n':
+            {
+                std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}};
+                return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);
+            }
+
+            // string
+            case '\"':
+                return scan_string();
+
+            // number
+            case '-':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                return scan_number();
+
+            // end of input (the null byte is needed when parsing from
+            // string literals)
+            case '\0':
+            case std::char_traits<char_type>::eof():
+                return token_type::end_of_input;
+
+            // error
+            default:
+                error_message = "invalid literal";
+                return token_type::parse_error;
+        }
+    }
+
+  private:
+    /// input adapter
+    InputAdapterType ia;
+
+    /// whether comments should be ignored (true) or signaled as errors (false)
+    const bool ignore_comments = false;
+
+    /// the current character
+    char_int_type current = std::char_traits<char_type>::eof();
+
+    /// whether the next get() call should just return current
+    bool next_unget = false;
+
+    /// the start position of the current token
+    position_t position {};
+
+    /// raw input token string (for error messages)
+    std::vector<char_type> token_string {};
+
+    /// buffer for variable-length tokens (numbers, strings)
+    string_t token_buffer {};
+
+    /// a description of occurred lexer errors
+    const char* error_message = "";
+
+    // number values
+    number_integer_t value_integer = 0;
+    number_unsigned_t value_unsigned = 0;
+    number_float_t value_float = 0;
+
+    /// the decimal point
+    const char_int_type decimal_point_char = '.';
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/parser.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/parser.h
new file mode 100644
index 0000000..32011ac
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/parser.h
@@ -0,0 +1,507 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cmath> // isfinite
+#include <cstdint> // uint8_t
+#include <functional> // function
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/input/input_adapters.h>
+#include <wpi/detail/input/json_sax.h>
+#include <wpi/detail/input/lexer.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/is_sax.h>
+#include <wpi/detail/string_concat.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+////////////
+// parser //
+////////////
+
+enum class parse_event_t : std::uint8_t
+{
+    /// the parser read `{` and started to process a JSON object
+    object_start,
+    /// the parser read `}` and finished processing a JSON object
+    object_end,
+    /// the parser read `[` and started to process a JSON array
+    array_start,
+    /// the parser read `]` and finished processing a JSON array
+    array_end,
+    /// the parser read a key of a value in an object
+    key,
+    /// the parser finished reading a JSON value
+    value
+};
+
+template<typename BasicJsonType>
+using parser_callback_t =
+    std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;
+
+/*!
+@brief syntax analysis
+
+This class implements a recursive descent parser.
+*/
+template<typename BasicJsonType, typename InputAdapterType>
+class parser
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using lexer_t = lexer<BasicJsonType, InputAdapterType>;
+    using token_type = typename lexer_t::token_type;
+
+  public:
+    /// a parser reading from an input adapter
+    explicit parser(InputAdapterType&& adapter,
+                    const parser_callback_t<BasicJsonType> cb = nullptr,
+                    const bool allow_exceptions_ = true,
+                    const bool skip_comments = false)
+        : callback(cb)
+        , m_lexer(std::move(adapter), skip_comments)
+        , allow_exceptions(allow_exceptions_)
+    {
+        // read first token
+        get_token();
+    }
+
+    /*!
+    @brief public parser interface
+
+    @param[in] strict      whether to expect the last token to be EOF
+    @param[in,out] result  parsed JSON value
+
+    @throw parse_error.101 in case of an unexpected token
+    @throw parse_error.102 if to_unicode fails or surrogate error
+    @throw parse_error.103 if to_unicode fails
+    */
+    void parse(const bool strict, BasicJsonType& result)
+    {
+        if (callback)
+        {
+            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
+            sax_parse_internal(&sdp);
+
+            // in strict mode, input must be completely read
+            if (strict && (get_token() != token_type::end_of_input))
+            {
+                sdp.parse_error(m_lexer.get_position(),
+                                m_lexer.get_token_string(),
+                                parse_error::create(101, m_lexer.get_position(),
+                                                    exception_message(token_type::end_of_input, "value"), nullptr));
+            }
+
+            // in case of an error, return discarded value
+            if (sdp.is_errored())
+            {
+                result = value_t::discarded;
+                return;
+            }
+
+            // set top-level value to null if it was discarded by the callback
+            // function
+            if (result.is_discarded())
+            {
+                result = nullptr;
+            }
+        }
+        else
+        {
+            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
+            sax_parse_internal(&sdp);
+
+            // in strict mode, input must be completely read
+            if (strict && (get_token() != token_type::end_of_input))
+            {
+                sdp.parse_error(m_lexer.get_position(),
+                                m_lexer.get_token_string(),
+                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
+            }
+
+            // in case of an error, return discarded value
+            if (sdp.is_errored())
+            {
+                result = value_t::discarded;
+                return;
+            }
+        }
+
+        result.assert_invariant();
+    }
+
+    /*!
+    @brief public accept interface
+
+    @param[in] strict  whether to expect the last token to be EOF
+    @return whether the input is a proper JSON text
+    */
+    bool accept(const bool strict = true)
+    {
+        json_sax_acceptor<BasicJsonType> sax_acceptor;
+        return sax_parse(&sax_acceptor, strict);
+    }
+
+    template<typename SAX>
+    JSON_HEDLEY_NON_NULL(2)
+    bool sax_parse(SAX* sax, const bool strict = true)
+    {
+        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
+        const bool result = sax_parse_internal(sax);
+
+        // strict mode: next byte must be EOF
+        if (result && strict && (get_token() != token_type::end_of_input))
+        {
+            return sax->parse_error(m_lexer.get_position(),
+                                    m_lexer.get_token_string(),
+                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
+        }
+
+        return result;
+    }
+
+  private:
+    template<typename SAX>
+    JSON_HEDLEY_NON_NULL(2)
+    bool sax_parse_internal(SAX* sax)
+    {
+        // stack to remember the hierarchy of structured values we are parsing
+        // true = array; false = object
+        std::vector<bool> states;
+        // value to avoid a goto (see comment where set to true)
+        bool skip_to_state_evaluation = false;
+
+        while (true)
+        {
+            if (!skip_to_state_evaluation)
+            {
+                // invariant: get_token() was called before each iteration
+                switch (last_token)
+                {
+                    case token_type::begin_object:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
+                        {
+                            return false;
+                        }
+
+                        // closing } -> we are done
+                        if (get_token() == token_type::end_object)
+                        {
+                            if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
+                            {
+                                return false;
+                            }
+                            break;
+                        }
+
+                        // parse key
+                        if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
+                        {
+                            return sax->parse_error(m_lexer.get_position(),
+                                                    m_lexer.get_token_string(),
+                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
+                        }
+                        if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
+                        {
+                            return false;
+                        }
+
+                        // parse separator (:)
+                        if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
+                        {
+                            return sax->parse_error(m_lexer.get_position(),
+                                                    m_lexer.get_token_string(),
+                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
+                        }
+
+                        // remember we are now inside an object
+                        states.push_back(false);
+
+                        // parse values
+                        get_token();
+                        continue;
+                    }
+
+                    case token_type::begin_array:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
+                        {
+                            return false;
+                        }
+
+                        // closing ] -> we are done
+                        if (get_token() == token_type::end_array)
+                        {
+                            if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
+                            {
+                                return false;
+                            }
+                            break;
+                        }
+
+                        // remember we are now inside an array
+                        states.push_back(true);
+
+                        // parse values (no need to call get_token)
+                        continue;
+                    }
+
+                    case token_type::value_float:
+                    {
+                        const auto res = m_lexer.get_number_float();
+
+                        if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
+                        {
+                            return sax->parse_error(m_lexer.get_position(),
+                                                    m_lexer.get_token_string(),
+                                                    out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
+                        }
+
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
+                        {
+                            return false;
+                        }
+
+                        break;
+                    }
+
+                    case token_type::literal_false:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::literal_null:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->null()))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::literal_true:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::value_integer:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::value_string:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::value_unsigned:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::parse_error:
+                    {
+                        // using "uninitialized" to avoid "expected" message
+                        return sax->parse_error(m_lexer.get_position(),
+                                                m_lexer.get_token_string(),
+                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
+                    }
+
+                    case token_type::uninitialized:
+                    case token_type::end_array:
+                    case token_type::end_object:
+                    case token_type::name_separator:
+                    case token_type::value_separator:
+                    case token_type::end_of_input:
+                    case token_type::literal_or_value:
+                    default: // the last token was unexpected
+                    {
+                        return sax->parse_error(m_lexer.get_position(),
+                                                m_lexer.get_token_string(),
+                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
+                    }
+                }
+            }
+            else
+            {
+                skip_to_state_evaluation = false;
+            }
+
+            // we reached this line after we successfully parsed a value
+            if (states.empty())
+            {
+                // empty stack: we reached the end of the hierarchy: done
+                return true;
+            }
+
+            if (states.back())  // array
+            {
+                // comma -> next value
+                if (get_token() == token_type::value_separator)
+                {
+                    // parse a new value
+                    get_token();
+                    continue;
+                }
+
+                // closing ]
+                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
+                    {
+                        return false;
+                    }
+
+                    // We are done with this array. Before we can parse a
+                    // new value, we need to evaluate the new state first.
+                    // By setting skip_to_state_evaluation to false, we
+                    // are effectively jumping to the beginning of this if.
+                    JSON_ASSERT(!states.empty());
+                    states.pop_back();
+                    skip_to_state_evaluation = true;
+                    continue;
+                }
+
+                return sax->parse_error(m_lexer.get_position(),
+                                        m_lexer.get_token_string(),
+                                        parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
+            }
+
+            // states.back() is false -> object
+
+            // comma -> next value
+            if (get_token() == token_type::value_separator)
+            {
+                // parse key
+                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
+                {
+                    return sax->parse_error(m_lexer.get_position(),
+                                            m_lexer.get_token_string(),
+                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
+                }
+
+                if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
+                {
+                    return false;
+                }
+
+                // parse separator (:)
+                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
+                {
+                    return sax->parse_error(m_lexer.get_position(),
+                                            m_lexer.get_token_string(),
+                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
+                }
+
+                // parse values
+                get_token();
+                continue;
+            }
+
+            // closing }
+            if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
+            {
+                if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
+                {
+                    return false;
+                }
+
+                // We are done with this object. Before we can parse a
+                // new value, we need to evaluate the new state first.
+                // By setting skip_to_state_evaluation to false, we
+                // are effectively jumping to the beginning of this if.
+                JSON_ASSERT(!states.empty());
+                states.pop_back();
+                skip_to_state_evaluation = true;
+                continue;
+            }
+
+            return sax->parse_error(m_lexer.get_position(),
+                                    m_lexer.get_token_string(),
+                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
+        }
+    }
+
+    /// get next token from lexer
+    token_type get_token()
+    {
+        return last_token = m_lexer.scan();
+    }
+
+    std::string exception_message(const token_type expected, const std::string& context)
+    {
+        std::string error_msg = "syntax error ";
+
+        if (!context.empty())
+        {
+            error_msg += concat("while parsing ", context, ' ');
+        }
+
+        error_msg += "- ";
+
+        if (last_token == token_type::parse_error)
+        {
+            error_msg += concat(m_lexer.get_error_message(), "; last read: '",
+                                m_lexer.get_token_string(), '\'');
+        }
+        else
+        {
+            error_msg += concat("unexpected ", lexer_t::token_type_name(last_token));
+        }
+
+        if (expected != token_type::uninitialized)
+        {
+            error_msg += concat("; expected ", lexer_t::token_type_name(expected));
+        }
+
+        return error_msg;
+    }
+
+  private:
+    /// callback function
+    const parser_callback_t<BasicJsonType> callback = nullptr;
+    /// the type of the last read token
+    token_type last_token = token_type::uninitialized;
+    /// the lexer
+    lexer_t m_lexer;
+    /// whether to throw exceptions in case of errors
+    const bool allow_exceptions = true;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/position_t.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/position_t.h
new file mode 100644
index 0000000..1476f55
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/input/position_t.h
@@ -0,0 +1,37 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstddef> // size_t
+
+#include <wpi/detail/abi_macros.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// struct to capture the start position of the current token
+struct position_t
+{
+    /// the total number of characters read
+    std::size_t chars_read_total = 0;
+    /// the number of characters read in the current line
+    std::size_t chars_read_current_line = 0;
+    /// the number of lines read
+    std::size_t lines_read = 0;
+
+    /// conversion to size_t to preserve SAX interface
+    constexpr operator size_t() const
+    {
+        return chars_read_total;
+    }
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/internal_iterator.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/internal_iterator.h
new file mode 100644
index 0000000..a97fb70
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/internal_iterator.h
@@ -0,0 +1,35 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/iterators/primitive_iterator.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief an iterator value
+
+@note This structure could easily be a union, but MSVC currently does not allow
+unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
+*/
+template<typename BasicJsonType> struct internal_iterator
+{
+    /// iterator for JSON objects
+    typename BasicJsonType::object_t::iterator object_iterator {};
+    /// iterator for JSON arrays
+    typename BasicJsonType::array_t::iterator array_iterator {};
+    /// generic iterator for all other types
+    primitive_iterator_t primitive_iterator {};
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iter_impl.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iter_impl.h
new file mode 100644
index 0000000..904a252
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iter_impl.h
@@ -0,0 +1,751 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
+#include <type_traits> // conditional, is_const, remove_const
+
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/iterators/internal_iterator.h>
+#include <wpi/detail/iterators/primitive_iterator.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// forward declare, to be able to friend it later on
+template<typename IteratorType> class iteration_proxy;
+template<typename IteratorType> class iteration_proxy_value;
+
+/*!
+@brief a template for a bidirectional iterator for the @ref basic_json class
+This class implements a both iterators (iterator and const_iterator) for the
+@ref basic_json class.
+@note An iterator is called *initialized* when a pointer to a JSON value has
+      been set (e.g., by a constructor or a copy assignment). If the iterator is
+      default-constructed, it is *uninitialized* and most methods are undefined.
+      **The library uses assertions to detect calls on uninitialized iterators.**
+@requirement The class satisfies the following concept requirements:
+-
+[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
+  The iterator that can be moved can be moved in both directions (i.e.
+  incremented and decremented).
+@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
+       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
+*/
+template<typename BasicJsonType>
+class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
+{
+    /// the iterator with BasicJsonType of different const-ness
+    using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
+    /// allow basic_json to access private members
+    friend other_iter_impl;
+    friend BasicJsonType;
+    friend iteration_proxy<iter_impl>;
+    friend iteration_proxy_value<iter_impl>;
+
+    using object_t = typename BasicJsonType::object_t;
+    using array_t = typename BasicJsonType::array_t;
+    // make sure BasicJsonType is basic_json or const basic_json
+    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
+                  "iter_impl only accepts (const) basic_json");
+    // superficial check for the LegacyBidirectionalIterator named requirement
+    static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
+                  &&  std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
+                  "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
+
+  public:
+    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
+    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
+    /// A user-defined iterator should provide publicly accessible typedefs named
+    /// iterator_category, value_type, difference_type, pointer, and reference.
+    /// Note that value_type is required to be non-const, even for constant iterators.
+    using iterator_category = std::bidirectional_iterator_tag;
+
+    /// the type of the values when the iterator is dereferenced
+    using value_type = typename BasicJsonType::value_type;
+    /// a type to represent differences between iterators
+    using difference_type = typename BasicJsonType::difference_type;
+    /// defines a pointer to the type iterated over (value_type)
+    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
+          typename BasicJsonType::const_pointer,
+          typename BasicJsonType::pointer>::type;
+    /// defines a reference to the type iterated over (value_type)
+    using reference =
+        typename std::conditional<std::is_const<BasicJsonType>::value,
+        typename BasicJsonType::const_reference,
+        typename BasicJsonType::reference>::type;
+
+    iter_impl() = default;
+    ~iter_impl() = default;
+    iter_impl(iter_impl&&) noexcept = default;
+    iter_impl& operator=(iter_impl&&) noexcept = default;
+
+    /*!
+    @brief constructor for a given JSON instance
+    @param[in] object  pointer to a JSON object for this iterator
+    @pre object != nullptr
+    @post The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    explicit iter_impl(pointer object) noexcept : m_object(object)
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                m_it.object_iterator = typename object_t::iterator();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_it.array_iterator = typename array_t::iterator();
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator = primitive_iterator_t();
+                break;
+            }
+        }
+    }
+
+    /*!
+    @note The conventional copy constructor and copy assignment are implicitly
+          defined. Combined with the following converting constructor and
+          assignment, they support: (1) copy from iterator to iterator, (2)
+          copy from const iterator to const iterator, and (3) conversion from
+          iterator to const iterator. However conversion from const iterator
+          to iterator is not defined.
+    */
+
+    /*!
+    @brief const copy constructor
+    @param[in] other const iterator to copy from
+    @note This copy constructor had to be defined explicitly to circumvent a bug
+          occurring on msvc v19.0 compiler (VS 2015) debug build. For more
+          information refer to: https://github.com/nlohmann/json/issues/1608
+    */
+    iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
+        : m_object(other.m_object), m_it(other.m_it)
+    {}
+
+    /*!
+    @brief converting assignment
+    @param[in] other const iterator to copy from
+    @return const/non-const iterator
+    @note It is not checked whether @a other is initialized.
+    */
+    iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
+    {
+        if (&other != this)
+        {
+            m_object = other.m_object;
+            m_it = other.m_it;
+        }
+        return *this;
+    }
+
+    /*!
+    @brief converting constructor
+    @param[in] other  non-const iterator to copy from
+    @note It is not checked whether @a other is initialized.
+    */
+    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
+        : m_object(other.m_object), m_it(other.m_it)
+    {}
+
+    /*!
+    @brief converting assignment
+    @param[in] other  non-const iterator to copy from
+    @return const/non-const iterator
+    @note It is not checked whether @a other is initialized.
+    */
+    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
+    {
+        m_object = other.m_object;
+        m_it = other.m_it;
+        return *this;
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /*!
+    @brief set the iterator to the first value
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    void set_begin() noexcept
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                m_it.object_iterator = m_object->m_value.object->begin();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_it.array_iterator = m_object->m_value.array->begin();
+                break;
+            }
+
+            case value_t::null:
+            {
+                // set to end so begin()==end() is true: null is empty
+                m_it.primitive_iterator.set_end();
+                break;
+            }
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator.set_begin();
+                break;
+            }
+        }
+    }
+
+    /*!
+    @brief set the iterator past the last value
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    void set_end() noexcept
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                m_it.object_iterator = m_object->m_value.object->end();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_it.array_iterator = m_object->m_value.array->end();
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator.set_end();
+                break;
+            }
+        }
+    }
+
+  public:
+    /*!
+    @brief return a reference to the value pointed to by the iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    reference operator*() const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
+                return m_it.object_iterator->second;
+            }
+
+            case value_t::array:
+            {
+                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
+                return *m_it.array_iterator;
+            }
+
+            case value_t::null:
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
+                {
+                    return *m_object;
+                }
+
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+            }
+        }
+    }
+
+    /*!
+    @brief dereference the iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    pointer operator->() const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
+                return &(m_it.object_iterator->second);
+            }
+
+            case value_t::array:
+            {
+                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
+                return &*m_it.array_iterator;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
+                {
+                    return m_object;
+                }
+
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+            }
+        }
+    }
+
+    /*!
+    @brief post-increment (it++)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        ++(*this);
+        return result;
+    }
+
+    /*!
+    @brief pre-increment (++it)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator++()
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                std::advance(m_it.object_iterator, 1);
+                break;
+            }
+
+            case value_t::array:
+            {
+                std::advance(m_it.array_iterator, 1);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                ++m_it.primitive_iterator;
+                break;
+            }
+        }
+
+        return *this;
+    }
+
+    /*!
+    @brief post-decrement (it--)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        --(*this);
+        return result;
+    }
+
+    /*!
+    @brief pre-decrement (--it)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator--()
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                std::advance(m_it.object_iterator, -1);
+                break;
+            }
+
+            case value_t::array:
+            {
+                std::advance(m_it.array_iterator, -1);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                --m_it.primitive_iterator;
+                break;
+            }
+        }
+
+        return *this;
+    }
+
+    /*!
+    @brief comparison: equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
+    bool operator==(const IterImpl& other) const
+    {
+        // if objects are not the same, the comparison is undefined
+        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
+        }
+
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                return (m_it.object_iterator == other.m_it.object_iterator);
+
+            case value_t::array:
+                return (m_it.array_iterator == other.m_it.array_iterator);
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+        }
+    }
+
+    /*!
+    @brief comparison: not equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
+    bool operator!=(const IterImpl& other) const
+    {
+        return !operator==(other);
+    }
+
+    /*!
+    @brief comparison: smaller
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator<(const iter_impl& other) const
+    {
+        // if objects are not the same, the comparison is undefined
+        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
+        }
+
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
+
+            case value_t::array:
+                return (m_it.array_iterator < other.m_it.array_iterator);
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
+        }
+    }
+
+    /*!
+    @brief comparison: less than or equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator<=(const iter_impl& other) const
+    {
+        return !other.operator < (*this);
+    }
+
+    /*!
+    @brief comparison: greater than
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator>(const iter_impl& other) const
+    {
+        return !operator<=(other);
+    }
+
+    /*!
+    @brief comparison: greater than or equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator>=(const iter_impl& other) const
+    {
+        return !operator<(other);
+    }
+
+    /*!
+    @brief add to iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator+=(difference_type i)
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
+
+            case value_t::array:
+            {
+                std::advance(m_it.array_iterator, i);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator += i;
+                break;
+            }
+        }
+
+        return *this;
+    }
+
+    /*!
+    @brief subtract from iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator-=(difference_type i)
+    {
+        return operator+=(-i);
+    }
+
+    /*!
+    @brief add to iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator+(difference_type i) const
+    {
+        auto result = *this;
+        result += i;
+        return result;
+    }
+
+    /*!
+    @brief addition of distance and iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    friend iter_impl operator+(difference_type i, const iter_impl& it)
+    {
+        auto result = it;
+        result += i;
+        return result;
+    }
+
+    /*!
+    @brief subtract from iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator-(difference_type i) const
+    {
+        auto result = *this;
+        result -= i;
+        return result;
+    }
+
+    /*!
+    @brief return difference
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    difference_type operator-(const iter_impl& other) const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
+
+            case value_t::array:
+                return m_it.array_iterator - other.m_it.array_iterator;
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return m_it.primitive_iterator - other.m_it.primitive_iterator;
+        }
+    }
+
+    /*!
+    @brief access to successor
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    reference operator[](difference_type n) const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
+
+            case value_t::array:
+                return *std::next(m_it.array_iterator, n);
+
+            case value_t::null:
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
+                {
+                    return *m_object;
+                }
+
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+            }
+        }
+    }
+
+    /*!
+    @brief return the key of an object iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    const typename object_t::key_type& key() const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        if (JSON_HEDLEY_LIKELY(m_object->is_object()))
+        {
+            return m_it.object_iterator->first;
+        }
+
+        JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
+    }
+
+    /*!
+    @brief return the value of an iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    reference value() const
+    {
+        return operator*();
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /// associated JSON instance
+    pointer m_object = nullptr;
+    /// the actual iterator of the associated instance
+    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iteration_proxy.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iteration_proxy.h
new file mode 100644
index 0000000..7f7492f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iteration_proxy.h
@@ -0,0 +1,242 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstddef> // size_t
+#include <iterator> // input_iterator_tag
+#include <string> // string, to_string
+#include <tuple> // tuple_size, get, tuple_element
+#include <utility> // move
+
+#if JSON_HAS_RANGES
+    #include <ranges> // enable_borrowed_range
+#endif
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename string_type>
+void int_to_string( string_type& target, std::size_t value )
+{
+    // For ADL
+    using std::to_string;
+    target = to_string(value);
+}
+template<typename IteratorType> class iteration_proxy_value
+{
+  public:
+    using difference_type = std::ptrdiff_t;
+    using value_type = iteration_proxy_value;
+    using pointer = value_type *;
+    using reference = value_type &;
+    using iterator_category = std::input_iterator_tag;
+    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
+
+  private:
+    /// the iterator
+    IteratorType anchor{};
+    /// an index for arrays (used to create key names)
+    std::size_t array_index = 0;
+    /// last stringified array index
+    mutable std::size_t array_index_last = 0;
+    /// a string representation of the array index
+    mutable string_type array_index_str = "0";
+    /// an empty string (to return a reference for primitive values)
+    string_type empty_str{};
+
+  public:
+    explicit iteration_proxy_value() = default;
+    explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
+    noexcept(std::is_nothrow_move_constructible<IteratorType>::value
+             && std::is_nothrow_default_constructible<string_type>::value)
+        : anchor(std::move(it))
+        , array_index(array_index_)
+    {}
+
+    iteration_proxy_value(iteration_proxy_value const&) = default;
+    iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
+    // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
+    iteration_proxy_value(iteration_proxy_value&&)
+    noexcept(std::is_nothrow_move_constructible<IteratorType>::value
+             && std::is_nothrow_move_constructible<string_type>::value) = default;
+    iteration_proxy_value& operator=(iteration_proxy_value&&)
+    noexcept(std::is_nothrow_move_assignable<IteratorType>::value
+             && std::is_nothrow_move_assignable<string_type>::value) = default;
+    ~iteration_proxy_value() = default;
+
+    /// dereference operator (needed for range-based for)
+    const iteration_proxy_value& operator*() const
+    {
+        return *this;
+    }
+
+    /// increment operator (needed for range-based for)
+    iteration_proxy_value& operator++()
+    {
+        ++anchor;
+        ++array_index;
+
+        return *this;
+    }
+
+    iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        auto tmp = iteration_proxy_value(anchor, array_index);
+        ++anchor;
+        ++array_index;
+        return tmp;
+    }
+
+    /// equality operator (needed for InputIterator)
+    bool operator==(const iteration_proxy_value& o) const
+    {
+        return anchor == o.anchor;
+    }
+
+    /// inequality operator (needed for range-based for)
+    bool operator!=(const iteration_proxy_value& o) const
+    {
+        return anchor != o.anchor;
+    }
+
+    /// return key of the iterator
+    const string_type& key() const
+    {
+        JSON_ASSERT(anchor.m_object != nullptr);
+
+        switch (anchor.m_object->type())
+        {
+            // use integer array index as key
+            case value_t::array:
+            {
+                if (array_index != array_index_last)
+                {
+                    int_to_string( array_index_str, array_index );
+                    array_index_last = array_index;
+                }
+                return array_index_str;
+            }
+
+            // use key from the object
+            case value_t::object:
+                return anchor.key();
+
+            // use an empty key for all primitive types
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return empty_str;
+        }
+    }
+
+    /// return value of the iterator
+    typename IteratorType::reference value() const
+    {
+        return anchor.value();
+    }
+};
+
+/// proxy class for the items() function
+template<typename IteratorType> class iteration_proxy
+{
+  private:
+    /// the container to iterate
+    typename IteratorType::pointer container = nullptr;
+
+  public:
+    explicit iteration_proxy() = default;
+
+    /// construct iteration proxy from a container
+    explicit iteration_proxy(typename IteratorType::reference cont) noexcept
+        : container(&cont) {}
+
+    iteration_proxy(iteration_proxy const&) = default;
+    iteration_proxy& operator=(iteration_proxy const&) = default;
+    iteration_proxy(iteration_proxy&&) noexcept = default;
+    iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
+    ~iteration_proxy() = default;
+
+    /// return iterator begin (needed for range-based for)
+    iteration_proxy_value<IteratorType> begin() const noexcept
+    {
+        return iteration_proxy_value<IteratorType>(container->begin());
+    }
+
+    /// return iterator end (needed for range-based for)
+    iteration_proxy_value<IteratorType> end() const noexcept
+    {
+        return iteration_proxy_value<IteratorType>(container->end());
+    }
+};
+
+// Structured Bindings Support
+// For further reference see https://blog.tartanllama.xyz/structured-bindings/
+// And see https://github.com/nlohmann/json/pull/1391
+template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
+auto get(const wpi::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
+{
+    return i.key();
+}
+// Structured Bindings Support
+// For further reference see https://blog.tartanllama.xyz/structured-bindings/
+// And see https://github.com/nlohmann/json/pull/1391
+template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
+auto get(const wpi::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
+{
+    return i.value();
+}
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
+
+// The Addition to the STD Namespace is required to add
+// Structured Bindings Support to the iteration_proxy_value class
+// For further reference see https://blog.tartanllama.xyz/structured-bindings/
+// And see https://github.com/nlohmann/json/pull/1391
+namespace std
+{
+
+#if defined(__clang__)
+    // Fix: https://github.com/nlohmann/json/issues/1401
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wmismatched-tags"
+#endif
+template<typename IteratorType>
+class tuple_size<::wpi::detail::iteration_proxy_value<IteratorType>>
+            : public std::integral_constant<std::size_t, 2> {};
+
+template<std::size_t N, typename IteratorType>
+class tuple_element<N, ::wpi::detail::iteration_proxy_value<IteratorType >>
+{
+  public:
+    using type = decltype(
+                     get<N>(std::declval <
+                            ::wpi::detail::iteration_proxy_value<IteratorType >> ()));
+};
+#if defined(__clang__)
+    #pragma clang diagnostic pop
+#endif
+
+}  // namespace std
+
+#if JSON_HAS_RANGES
+    template <typename IteratorType>
+    inline constexpr bool ::std::ranges::enable_borrowed_range<::wpi::detail::iteration_proxy<IteratorType>> = true;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iterator_traits.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iterator_traits.h
new file mode 100644
index 0000000..855872a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/iterator_traits.h
@@ -0,0 +1,61 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <iterator> // random_access_iterator_tag
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/meta/void_t.h>
+#include <wpi/detail/meta/cpp_future.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename It, typename = void>
+struct iterator_types {};
+
+template<typename It>
+struct iterator_types <
+    It,
+    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
+    typename It::reference, typename It::iterator_category >>
+{
+    using difference_type = typename It::difference_type;
+    using value_type = typename It::value_type;
+    using pointer = typename It::pointer;
+    using reference = typename It::reference;
+    using iterator_category = typename It::iterator_category;
+};
+
+// This is required as some compilers implement std::iterator_traits in a way that
+// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
+template<typename T, typename = void>
+struct iterator_traits
+{
+};
+
+template<typename T>
+struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
+            : iterator_types<T>
+{
+};
+
+template<typename T>
+struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
+{
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = T;
+    using difference_type = ptrdiff_t;
+    using pointer = T*;
+    using reference = T&;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/json_reverse_iterator.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/json_reverse_iterator.h
new file mode 100644
index 0000000..ea2740f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/json_reverse_iterator.h
@@ -0,0 +1,130 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstddef> // ptrdiff_t
+#include <iterator> // reverse_iterator
+#include <utility> // declval
+
+#include <wpi/detail/abi_macros.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+//////////////////////
+// reverse_iterator //
+//////////////////////
+
+/*!
+@brief a template for a reverse iterator class
+
+@tparam Base the base iterator type to reverse. Valid types are @ref
+iterator (to create @ref reverse_iterator) and @ref const_iterator (to
+create @ref const_reverse_iterator).
+
+@requirement The class satisfies the following concept requirements:
+-
+[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
+  The iterator that can be moved can be moved in both directions (i.e.
+  incremented and decremented).
+- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
+  It is possible to write to the pointed-to element (only if @a Base is
+  @ref iterator).
+
+@since version 1.0.0
+*/
+template<typename Base>
+class json_reverse_iterator : public std::reverse_iterator<Base>
+{
+  public:
+    using difference_type = std::ptrdiff_t;
+    /// shortcut to the reverse iterator adapter
+    using base_iterator = std::reverse_iterator<Base>;
+    /// the reference type for the pointed-to element
+    using reference = typename Base::reference;
+
+    /// create reverse iterator from iterator
+    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
+        : base_iterator(it) {}
+
+    /// create reverse iterator from base class
+    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
+
+    /// post-increment (it++)
+    json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
+    }
+
+    /// pre-increment (++it)
+    json_reverse_iterator& operator++()
+    {
+        return static_cast<json_reverse_iterator&>(base_iterator::operator++());
+    }
+
+    /// post-decrement (it--)
+    json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
+    }
+
+    /// pre-decrement (--it)
+    json_reverse_iterator& operator--()
+    {
+        return static_cast<json_reverse_iterator&>(base_iterator::operator--());
+    }
+
+    /// add to iterator
+    json_reverse_iterator& operator+=(difference_type i)
+    {
+        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
+    }
+
+    /// add to iterator
+    json_reverse_iterator operator+(difference_type i) const
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
+    }
+
+    /// subtract from iterator
+    json_reverse_iterator operator-(difference_type i) const
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
+    }
+
+    /// return difference
+    difference_type operator-(const json_reverse_iterator& other) const
+    {
+        return base_iterator(*this) - base_iterator(other);
+    }
+
+    /// access to successor
+    reference operator[](difference_type n) const
+    {
+        return *(this->operator+(n));
+    }
+
+    /// return the key of an object iterator
+    auto key() const -> decltype(std::declval<Base>().key())
+    {
+        auto it = --this->base();
+        return it.key();
+    }
+
+    /// return the value of an iterator
+    reference value() const
+    {
+        auto it = --this->base();
+        return it.operator * ();
+    }
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/primitive_iterator.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/primitive_iterator.h
new file mode 100644
index 0000000..914bd5b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/iterators/primitive_iterator.h
@@ -0,0 +1,132 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstddef> // ptrdiff_t
+#include <limits>  // numeric_limits
+
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*
+@brief an iterator for primitive JSON types
+
+This class models an iterator for primitive JSON types (boolean, number,
+string). It's only purpose is to allow the iterator/const_iterator classes
+to "iterate" over primitive values. Internally, the iterator is modeled by
+a `difference_type` variable. Value begin_value (`0`) models the begin,
+end_value (`1`) models past the end.
+*/
+class primitive_iterator_t
+{
+  private:
+    using difference_type = std::ptrdiff_t;
+    static constexpr difference_type begin_value = 0;
+    static constexpr difference_type end_value = begin_value + 1;
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /// iterator as signed integer type
+    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
+
+  public:
+    constexpr difference_type get_value() const noexcept
+    {
+        return m_it;
+    }
+
+    /// set iterator to a defined beginning
+    void set_begin() noexcept
+    {
+        m_it = begin_value;
+    }
+
+    /// set iterator to a defined past the end
+    void set_end() noexcept
+    {
+        m_it = end_value;
+    }
+
+    /// return whether the iterator can be dereferenced
+    constexpr bool is_begin() const noexcept
+    {
+        return m_it == begin_value;
+    }
+
+    /// return whether the iterator is at end
+    constexpr bool is_end() const noexcept
+    {
+        return m_it == end_value;
+    }
+
+    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+    {
+        return lhs.m_it == rhs.m_it;
+    }
+
+    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+    {
+        return lhs.m_it < rhs.m_it;
+    }
+
+    primitive_iterator_t operator+(difference_type n) noexcept
+    {
+        auto result = *this;
+        result += n;
+        return result;
+    }
+
+    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+    {
+        return lhs.m_it - rhs.m_it;
+    }
+
+    primitive_iterator_t& operator++() noexcept
+    {
+        ++m_it;
+        return *this;
+    }
+
+    primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        ++m_it;
+        return result;
+    }
+
+    primitive_iterator_t& operator--() noexcept
+    {
+        --m_it;
+        return *this;
+    }
+
+    primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        --m_it;
+        return result;
+    }
+
+    primitive_iterator_t& operator+=(difference_type n) noexcept
+    {
+        m_it += n;
+        return *this;
+    }
+
+    primitive_iterator_t& operator-=(difference_type n) noexcept
+    {
+        m_it -= n;
+        return *this;
+    }
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/json_pointer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/json_pointer.h
new file mode 100644
index 0000000..b52d914
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/json_pointer.h
@@ -0,0 +1,988 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // all_of
+#include <cctype> // isdigit
+#include <cerrno> // errno, ERANGE
+#include <cstdlib> // strtoull
+#ifndef JSON_NO_IO
+    #include <iosfwd> // ostream
+#endif  // JSON_NO_IO
+#include <limits> // max
+#include <numeric> // accumulate
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/string_concat.h>
+#include <wpi/detail/string_escape.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
+/// @sa https://json.nlohmann.me/api/json_pointer/
+template<typename RefStringType>
+class json_pointer
+{
+    // allow basic_json to access private members
+    WPI_BASIC_JSON_TPL_DECLARATION
+    friend class basic_json;
+
+    template<typename>
+    friend class json_pointer;
+
+    template<typename T>
+    struct string_t_helper
+    {
+        using type = T;
+    };
+
+    WPI_BASIC_JSON_TPL_DECLARATION
+    struct string_t_helper<WPI_BASIC_JSON_TPL>
+    {
+        using type = StringType;
+    };
+
+  public:
+    // for backwards compatibility accept BasicJsonType
+    using string_t = typename string_t_helper<RefStringType>::type;
+
+    /// @brief create JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
+    explicit json_pointer(const string_t& s = "")
+        : reference_tokens(split(s))
+    {}
+
+    /// @brief return a string representation of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/to_string/
+    string_t to_string() const
+    {
+        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
+                               string_t{},
+                               [](const string_t& a, const string_t& b)
+        {
+            return detail::concat(a, '/', detail::escape(b));
+        });
+    }
+
+    /// @brief return a string representation of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
+    operator string_t() const
+    {
+        return to_string();
+    }
+
+#ifndef JSON_NO_IO
+    /// @brief write string representation of the JSON pointer to stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+    friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
+    {
+        o << ptr.to_string();
+        return o;
+    }
+#endif
+
+    /// @brief append another JSON pointer at the end of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
+    json_pointer& operator/=(const json_pointer& ptr)
+    {
+        reference_tokens.insert(reference_tokens.end(),
+                                ptr.reference_tokens.begin(),
+                                ptr.reference_tokens.end());
+        return *this;
+    }
+
+    /// @brief append an unescaped reference token at the end of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
+    json_pointer& operator/=(string_t token)
+    {
+        push_back(std::move(token));
+        return *this;
+    }
+
+    /// @brief append an array index at the end of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
+    json_pointer& operator/=(std::size_t array_idx)
+    {
+        return *this /= std::to_string(array_idx);
+    }
+
+    /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
+    friend json_pointer operator/(const json_pointer& lhs,
+                                  const json_pointer& rhs)
+    {
+        return json_pointer(lhs) /= rhs;
+    }
+
+    /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
+    friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
+    {
+        return json_pointer(lhs) /= std::move(token);
+    }
+
+    /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
+    friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
+    {
+        return json_pointer(lhs) /= array_idx;
+    }
+
+    /// @brief returns the parent of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/
+    json_pointer parent_pointer() const
+    {
+        if (empty())
+        {
+            return *this;
+        }
+
+        json_pointer res = *this;
+        res.pop_back();
+        return res;
+    }
+
+    /// @brief remove last reference token
+    /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/
+    void pop_back()
+    {
+        if (JSON_HEDLEY_UNLIKELY(empty()))
+        {
+            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
+        }
+
+        reference_tokens.pop_back();
+    }
+
+    /// @brief return last reference token
+    /// @sa https://json.nlohmann.me/api/json_pointer/back/
+    const string_t& back() const
+    {
+        if (JSON_HEDLEY_UNLIKELY(empty()))
+        {
+            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
+        }
+
+        return reference_tokens.back();
+    }
+
+    /// @brief append an unescaped token at the end of the reference pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
+    void push_back(const string_t& token)
+    {
+        reference_tokens.push_back(token);
+    }
+
+    /// @brief append an unescaped token at the end of the reference pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
+    void push_back(string_t&& token)
+    {
+        reference_tokens.push_back(std::move(token));
+    }
+
+    /// @brief return whether pointer points to the root document
+    /// @sa https://json.nlohmann.me/api/json_pointer/empty/
+    bool empty() const noexcept
+    {
+        return reference_tokens.empty();
+    }
+
+  private:
+    /*!
+    @param[in] s  reference token to be converted into an array index
+
+    @return integer representation of @a s
+
+    @throw parse_error.106  if an array index begins with '0'
+    @throw parse_error.109  if an array index begins not with a digit
+    @throw out_of_range.404 if string @a s could not be converted to an integer
+    @throw out_of_range.410 if an array index exceeds size_type
+    */
+    template<typename BasicJsonType>
+    static typename BasicJsonType::size_type array_index(const string_t& s)
+    {
+        using size_type = typename BasicJsonType::size_type;
+
+        // error condition (cf. RFC 6901, Sect. 4)
+        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
+        {
+            JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
+        }
+
+        // error condition (cf. RFC 6901, Sect. 4)
+        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
+        {
+            JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
+        }
+
+        const char* p = s.c_str();
+        char* p_end = nullptr;
+        errno = 0; // strtoull doesn't reset errno
+        unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
+        if (p == p_end // invalid input or empty string
+                || errno == ERANGE // out of range
+                || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
+        {
+            JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
+        }
+
+        // only triggered on special platforms (like 32bit), see also
+        // https://github.com/nlohmann/json/pull/2203
+        if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))  // NOLINT(runtime/int)
+        {
+            JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));   // LCOV_EXCL_LINE
+        }
+
+        return static_cast<size_type>(res);
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    json_pointer top() const
+    {
+        if (JSON_HEDLEY_UNLIKELY(empty()))
+        {
+            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
+        }
+
+        json_pointer result = *this;
+        result.reference_tokens = {reference_tokens[0]};
+        return result;
+    }
+
+  private:
+    /*!
+    @brief create and return a reference to the pointed to value
+
+    @complexity Linear in the number of reference tokens.
+
+    @throw parse_error.109 if array index is not a number
+    @throw type_error.313 if value cannot be unflattened
+    */
+    template<typename BasicJsonType>
+    BasicJsonType& get_and_create(BasicJsonType& j) const
+    {
+        auto* result = &j;
+
+        // in case no reference tokens exist, return a reference to the JSON value
+        // j which will be overwritten by a primitive value
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (result->type())
+            {
+                case detail::value_t::null:
+                {
+                    if (reference_token == "0")
+                    {
+                        // start a new array if reference token is 0
+                        result = &result->operator[](0);
+                    }
+                    else
+                    {
+                        // start a new object otherwise
+                        result = &result->operator[](reference_token);
+                    }
+                    break;
+                }
+
+                case detail::value_t::object:
+                {
+                    // create an entry in the object
+                    result = &result->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    // create an entry in the array
+                    result = &result->operator[](array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                /*
+                The following code is only reached if there exists a reference
+                token _and_ the current value is primitive. In this case, we have
+                an error situation, because primitive values may only occur as
+                single value; that is, with an empty list of reference tokens.
+                */
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
+            }
+        }
+
+        return *result;
+    }
+
+    /*!
+    @brief return a reference to the pointed to value
+
+    @note This version does not throw if a value is not present, but tries to
+          create nested values instead. For instance, calling this function
+          with pointer `"/this/that"` on a null value is equivalent to calling
+          `operator[]("this").operator[]("that")` on that value, effectively
+          changing the null value to an object.
+
+    @param[in] ptr  a JSON value
+
+    @return reference to the JSON value pointed to by the JSON pointer
+
+    @complexity Linear in the length of the JSON pointer.
+
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    BasicJsonType& get_unchecked(BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            // convert null values to arrays or objects before continuing
+            if (ptr->is_null())
+            {
+                // check if reference token is a number
+                const bool nums =
+                    std::all_of(reference_token.begin(), reference_token.end(),
+                                [](const unsigned char x)
+                {
+                    return std::isdigit(x);
+                });
+
+                // change value to array for numbers or "-" or to object otherwise
+                *ptr = (nums || reference_token == "-")
+                       ? detail::value_t::array
+                       : detail::value_t::object;
+            }
+
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // use unchecked object access
+                    ptr = &ptr->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (reference_token == "-")
+                    {
+                        // explicitly treat "-" as index beyond the end
+                        ptr = &ptr->operator[](ptr->m_value.array->size());
+                    }
+                    else
+                    {
+                        // convert array index to number; unchecked access
+                        ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
+                    }
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.402  if the array index '-' is used
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    BasicJsonType& get_checked(BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // note: at performs range check
+                    ptr = &ptr->at(reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" always fails the range check
+                        JSON_THROW(detail::out_of_range::create(402, detail::concat(
+                                "array index '-' (", std::to_string(ptr->m_value.array->size()),
+                                ") is out of range"), ptr));
+                    }
+
+                    // note: at performs range check
+                    ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @brief return a const reference to the pointed to value
+
+    @param[in] ptr  a JSON value
+
+    @return const reference to the JSON value pointed to by the JSON
+    pointer
+
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.402  if the array index '-' is used
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // use unchecked object access
+                    ptr = &ptr->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" cannot be used for const access
+                        JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_value.array->size()), ") is out of range"), ptr));
+                    }
+
+                    // use unchecked array access
+                    ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.402  if the array index '-' is used
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    const BasicJsonType& get_checked(const BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // note: at performs range check
+                    ptr = &ptr->at(reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" always fails the range check
+                        JSON_THROW(detail::out_of_range::create(402, detail::concat(
+                                "array index '-' (", std::to_string(ptr->m_value.array->size()),
+                                ") is out of range"), ptr));
+                    }
+
+                    // note: at performs range check
+                    ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    */
+    template<typename BasicJsonType>
+    bool contains(const BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    if (!ptr->contains(reference_token))
+                    {
+                        // we did not find the key in the object
+                        return false;
+                    }
+
+                    ptr = &ptr->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" always fails the range check
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
+                    {
+                        // invalid char
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
+                        {
+                            // first char should be between '1' and '9'
+                            return false;
+                        }
+                        for (std::size_t i = 1; i < reference_token.size(); i++)
+                        {
+                            if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
+                            {
+                                // other char should be between '0' and '9'
+                                return false;
+                            }
+                        }
+                    }
+
+                    const auto idx = array_index<BasicJsonType>(reference_token);
+                    if (idx >= ptr->size())
+                    {
+                        // index out of range
+                        return false;
+                    }
+
+                    ptr = &ptr->operator[](idx);
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                {
+                    // we do not expect primitive values if there is still a
+                    // reference token to process
+                    return false;
+                }
+            }
+        }
+
+        // no reference token left means we found a primitive value
+        return true;
+    }
+
+    /*!
+    @brief split the string input to reference tokens
+
+    @note This function is only called by the json_pointer constructor.
+          All exceptions below are documented there.
+
+    @throw parse_error.107  if the pointer is not empty or begins with '/'
+    @throw parse_error.108  if character '~' is not followed by '0' or '1'
+    */
+    static std::vector<string_t> split(const string_t& reference_string)
+    {
+        std::vector<string_t> result;
+
+        // special case: empty reference string -> no reference tokens
+        if (reference_string.empty())
+        {
+            return result;
+        }
+
+        // check if nonempty reference string begins with slash
+        if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
+        {
+            JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
+        }
+
+        // extract the reference tokens:
+        // - slash: position of the last read slash (or end of string)
+        // - start: position after the previous slash
+        for (
+            // search for the first slash after the first character
+            std::size_t slash = reference_string.find_first_of('/', 1),
+            // set the beginning of the first reference token
+            start = 1;
+            // we can stop if start == 0 (if slash == string_t::npos)
+            start != 0;
+            // set the beginning of the next reference token
+            // (will eventually be 0 if slash == string_t::npos)
+            start = (slash == string_t::npos) ? 0 : slash + 1,
+            // find next slash
+            slash = reference_string.find_first_of('/', start))
+        {
+            // use the text between the beginning of the reference token
+            // (start) and the last slash (slash).
+            auto reference_token = reference_string.substr(start, slash - start);
+
+            // check reference tokens are properly escaped
+            for (std::size_t pos = reference_token.find_first_of('~');
+                    pos != string_t::npos;
+                    pos = reference_token.find_first_of('~', pos + 1))
+            {
+                JSON_ASSERT(reference_token[pos] == '~');
+
+                // ~ must be followed by 0 or 1
+                if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
+                                         (reference_token[pos + 1] != '0' &&
+                                          reference_token[pos + 1] != '1')))
+                {
+                    JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
+                }
+            }
+
+            // finally, store the reference token
+            detail::unescape(reference_token);
+            result.push_back(reference_token);
+        }
+
+        return result;
+    }
+
+  private:
+    /*!
+    @param[in] reference_string  the reference string to the current value
+    @param[in] value             the value to consider
+    @param[in,out] result        the result object to insert values to
+
+    @note Empty objects or arrays are flattened to `null`.
+    */
+    template<typename BasicJsonType>
+    static void flatten(const string_t& reference_string,
+                        const BasicJsonType& value,
+                        BasicJsonType& result)
+    {
+        switch (value.type())
+        {
+            case detail::value_t::array:
+            {
+                if (value.m_value.array->empty())
+                {
+                    // flatten empty array as null
+                    result[reference_string] = nullptr;
+                }
+                else
+                {
+                    // iterate array and use index as reference string
+                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
+                    {
+                        flatten(detail::concat(reference_string, '/', std::to_string(i)),
+                                value.m_value.array->operator[](i), result);
+                    }
+                }
+                break;
+            }
+
+            case detail::value_t::object:
+            {
+                if (value.m_value.object->empty())
+                {
+                    // flatten empty object as null
+                    result[reference_string] = nullptr;
+                }
+                else
+                {
+                    // iterate object and use keys as reference string
+                    for (const auto& element : *value.m_value.object)
+                    {
+                        flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
+                    }
+                }
+                break;
+            }
+
+            case detail::value_t::null:
+            case detail::value_t::string:
+            case detail::value_t::boolean:
+            case detail::value_t::number_integer:
+            case detail::value_t::number_unsigned:
+            case detail::value_t::number_float:
+            case detail::value_t::binary:
+            case detail::value_t::discarded:
+            default:
+            {
+                // add primitive value with its reference string
+                result[reference_string] = value;
+                break;
+            }
+        }
+    }
+
+    /*!
+    @param[in] value  flattened JSON
+
+    @return unflattened JSON
+
+    @throw parse_error.109 if array index is not a number
+    @throw type_error.314  if value is not an object
+    @throw type_error.315  if object values are not primitive
+    @throw type_error.313  if value cannot be unflattened
+    */
+    template<typename BasicJsonType>
+    static BasicJsonType
+    unflatten(const BasicJsonType& value)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
+        {
+            JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
+        }
+
+        BasicJsonType result;
+
+        // iterate the JSON object values
+        for (const auto& element : *value.m_value.object)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
+            {
+                JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
+            }
+
+            // assign value to reference pointed to by JSON pointer; Note that if
+            // the JSON pointer is "" (i.e., points to the whole value), function
+            // get_and_create returns a reference to result itself. An assignment
+            // will then create a primitive value.
+            json_pointer(element.first).get_and_create(result) = element.second;
+        }
+
+        return result;
+    }
+
+    // can't use conversion operator because of ambiguity
+    json_pointer<string_t> convert() const&
+    {
+        json_pointer<string_t> result;
+        result.reference_tokens = reference_tokens;
+        return result;
+    }
+
+    json_pointer<string_t> convert()&&
+    {
+        json_pointer<string_t> result;
+        result.reference_tokens = std::move(reference_tokens);
+        return result;
+    }
+
+  public:
+#if JSON_HAS_THREE_WAY_COMPARISON
+    /// @brief compares two JSON pointers for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeRhs>
+    bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
+    {
+        return reference_tokens == rhs.reference_tokens;
+    }
+
+    /// @brief compares JSON pointer and string for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
+    bool operator==(const string_t& rhs) const
+    {
+        return *this == json_pointer(rhs);
+    }
+
+    /// @brief 3-way compares two JSON pointers
+    template<typename RefStringTypeRhs>
+    std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
+    {
+        return  reference_tokens <=> rhs.reference_tokens; // *NOPAD*
+    }
+#else
+    /// @brief compares two JSON pointers for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;
+
+    /// @brief compares JSON pointer and string for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeLhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                           const StringType& rhs);
+
+    /// @brief compares string and JSON pointer for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeRhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator==(const StringType& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs);
+
+    /// @brief compares two JSON pointers for inequality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
+    template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;
+
+    /// @brief compares JSON pointer and string for inequality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
+    template<typename RefStringTypeLhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                           const StringType& rhs);
+
+    /// @brief compares string and JSON pointer for inequality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
+    template<typename RefStringTypeRhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator!=(const StringType& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs);
+
+    /// @brief compares two JSON pointer for less-than
+    template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
+                          const json_pointer<RefStringTypeRhs>& rhs) noexcept;
+#endif
+
+  private:
+    /// the reference tokens
+    std::vector<string_t> reference_tokens;
+};
+
+#if !JSON_HAS_THREE_WAY_COMPARISON
+// functions cannot be defined inside class due to ODR violations
+template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs) noexcept
+{
+    return lhs.reference_tokens == rhs.reference_tokens;
+}
+
+template<typename RefStringTypeLhs,
+         typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
+inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                       const StringType& rhs)
+{
+    return lhs == json_pointer<RefStringTypeLhs>(rhs);
+}
+
+template<typename RefStringTypeRhs,
+         typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
+inline bool operator==(const StringType& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs)
+{
+    return json_pointer<RefStringTypeRhs>(lhs) == rhs;
+}
+
+template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs) noexcept
+{
+    return !(lhs == rhs);
+}
+
+template<typename RefStringTypeLhs,
+         typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
+inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                       const StringType& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template<typename RefStringTypeRhs,
+         typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
+inline bool operator!=(const StringType& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
+                      const json_pointer<RefStringTypeRhs>& rhs) noexcept
+{
+    return lhs.reference_tokens < rhs.reference_tokens;
+}
+#endif
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/json_ref.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/json_ref.h
new file mode 100644
index 0000000..6bf600b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/json_ref.h
@@ -0,0 +1,78 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <initializer_list>
+#include <utility>
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/meta/type_traits.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename BasicJsonType>
+class json_ref
+{
+  public:
+    using value_type = BasicJsonType;
+
+    json_ref(value_type&& value)
+        : owned_value(std::move(value))
+    {}
+
+    json_ref(const value_type& value)
+        : value_ref(&value)
+    {}
+
+    json_ref(std::initializer_list<json_ref> init)
+        : owned_value(init)
+    {}
+
+    template <
+        class... Args,
+        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
+    json_ref(Args && ... args)
+        : owned_value(std::forward<Args>(args)...)
+    {}
+
+    // class should be movable only
+    json_ref(json_ref&&) noexcept = default;
+    json_ref(const json_ref&) = delete;
+    json_ref& operator=(const json_ref&) = delete;
+    json_ref& operator=(json_ref&&) = delete;
+    ~json_ref() = default;
+
+    value_type moved_or_copied() const
+    {
+        if (value_ref == nullptr)
+        {
+            return std::move(owned_value);
+        }
+        return *value_ref;
+    }
+
+    value_type const& operator*() const
+    {
+        return value_ref ? *value_ref : owned_value;
+    }
+
+    value_type const* operator->() const
+    {
+        return &** this;
+    }
+
+  private:
+    mutable value_type owned_value = nullptr;
+    value_type const* value_ref = nullptr;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/macro_scope.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/macro_scope.h
new file mode 100644
index 0000000..80f18b3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/macro_scope.h
@@ -0,0 +1,468 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <utility> // declval, pair
+#include <wpi/detail/meta/detected.h>
+#include <wpi/thirdparty/hedley/hedley.h>
+
+// This file contains all internal macro definitions (except those affecting ABI)
+// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
+
+#include <wpi/detail/abi_macros.h>
+
+// exclude unsupported compilers
+#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
+    #if defined(__clang__)
+        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
+            #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
+        #endif
+    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
+        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
+            #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
+        #endif
+    #endif
+#endif
+
+// C++ language standard detection
+// if the user manually specified the used c++ version this is skipped
+#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
+    #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
+        #define JSON_HAS_CPP_20
+        #define JSON_HAS_CPP_17
+        #define JSON_HAS_CPP_14
+    #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
+        #define JSON_HAS_CPP_17
+        #define JSON_HAS_CPP_14
+    #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
+        #define JSON_HAS_CPP_14
+    #endif
+    // the cpp 11 flag is always specified because it is the minimal required version
+    #define JSON_HAS_CPP_11
+#endif
+
+#ifdef __has_include
+    #if __has_include(<version>)
+        #include <version>
+    #endif
+#endif
+
+#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
+    #ifdef JSON_HAS_CPP_17
+        #if defined(__cpp_lib_filesystem)
+            #define JSON_HAS_FILESYSTEM 1
+        #elif defined(__cpp_lib_experimental_filesystem)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #elif !defined(__has_include)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #elif __has_include(<filesystem>)
+            #define JSON_HAS_FILESYSTEM 1
+        #elif __has_include(<experimental/filesystem>)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #endif
+
+        // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
+        #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(__clang_major__) && __clang_major__ < 7
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(_MSC_VER) && _MSC_VER < 1914
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before iOS 13
+        #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before macOS Catalina
+        #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+    #endif
+#endif
+
+#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+    #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
+#endif
+
+#ifndef JSON_HAS_FILESYSTEM
+    #define JSON_HAS_FILESYSTEM 0
+#endif
+
+#ifndef JSON_HAS_THREE_WAY_COMPARISON
+    #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
+        && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
+        #define JSON_HAS_THREE_WAY_COMPARISON 1
+    #else
+        #define JSON_HAS_THREE_WAY_COMPARISON 0
+    #endif
+#endif
+
+#ifndef JSON_HAS_RANGES
+    // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
+    #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
+        #define JSON_HAS_RANGES 0
+    #elif defined(__cpp_lib_ranges)
+        #define JSON_HAS_RANGES 1
+    #else
+        #define JSON_HAS_RANGES 0
+    #endif
+#endif
+
+#ifdef JSON_HAS_CPP_17
+    #define JSON_INLINE_VARIABLE inline
+#else
+    #define JSON_INLINE_VARIABLE
+#endif
+
+#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
+    #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#else
+    #define JSON_NO_UNIQUE_ADDRESS
+#endif
+
+// disable documentation warnings on clang
+#if defined(__clang__)
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wdocumentation"
+    #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
+#endif
+
+// allow disabling exceptions
+#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
+    #define JSON_THROW(exception) throw exception
+    #define JSON_TRY try
+    #define JSON_CATCH(exception) catch(exception)
+    #define JSON_INTERNAL_CATCH(exception) catch(exception)
+#else
+    #include <cstdlib>
+    #define JSON_THROW(exception) std::abort()
+    #define JSON_TRY if(true)
+    #define JSON_CATCH(exception) if(false)
+    #define JSON_INTERNAL_CATCH(exception) if(false)
+#endif
+
+// override exception macros
+#if defined(JSON_THROW_USER)
+    #undef JSON_THROW
+    #define JSON_THROW JSON_THROW_USER
+#endif
+#if defined(JSON_TRY_USER)
+    #undef JSON_TRY
+    #define JSON_TRY JSON_TRY_USER
+#endif
+#if defined(JSON_CATCH_USER)
+    #undef JSON_CATCH
+    #define JSON_CATCH JSON_CATCH_USER
+    #undef JSON_INTERNAL_CATCH
+    #define JSON_INTERNAL_CATCH JSON_CATCH_USER
+#endif
+#if defined(JSON_INTERNAL_CATCH_USER)
+    #undef JSON_INTERNAL_CATCH
+    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
+#endif
+
+// allow overriding assert
+#if !defined(JSON_ASSERT)
+    #include <cassert> // assert
+    #define JSON_ASSERT(x) assert(x)
+#endif
+
+// allow to access some private functions (needed by the test suite)
+#if defined(JSON_TESTS_PRIVATE)
+    #define JSON_PRIVATE_UNLESS_TESTED public
+#else
+    #define JSON_PRIVATE_UNLESS_TESTED private
+#endif
+
+/*!
+@brief macro to briefly define a mapping between an enum and JSON
+@def WPI_JSON_SERIALIZE_ENUM
+@since version 3.4.0
+*/
+#define WPI_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                            \
+    template<typename BasicJsonType>                                                            \
+    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                   \
+    {                                                                                           \
+        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!");          \
+        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \
+        auto it = std::find_if(std::begin(m), std::end(m),                                      \
+                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool  \
+        {                                                                                       \
+            return ej_pair.first == e;                                                          \
+        });                                                                                     \
+        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                 \
+    }                                                                                           \
+    template<typename BasicJsonType>                                                            \
+    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                 \
+    {                                                                                           \
+        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!");          \
+        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \
+        auto it = std::find_if(std::begin(m), std::end(m),                                      \
+                               [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
+        {                                                                                       \
+            return ej_pair.second == j;                                                         \
+        });                                                                                     \
+        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                  \
+    }
+
+// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
+// may be removed in the future once the class is split.
+
+#define WPI_BASIC_JSON_TPL_DECLARATION                                \
+    template<template<typename, typename, typename...> class ObjectType,   \
+             template<typename, typename...> class ArrayType,              \
+             class StringType, class BooleanType, class NumberIntegerType, \
+             class NumberUnsignedType, class NumberFloatType,              \
+             template<typename> class AllocatorType,                       \
+             template<typename, typename = void> class JSONSerializer,     \
+             class BinaryType>
+
+#define WPI_BASIC_JSON_TPL                                            \
+    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \
+    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \
+    AllocatorType, JSONSerializer, BinaryType>
+
+// Macros to simplify conversion from/to types
+
+#define WPI_JSON_EXPAND( x ) x
+#define WPI_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
+#define WPI_JSON_PASTE(...) WPI_JSON_EXPAND(WPI_JSON_GET_MACRO(__VA_ARGS__, \
+        WPI_JSON_PASTE64, \
+        WPI_JSON_PASTE63, \
+        WPI_JSON_PASTE62, \
+        WPI_JSON_PASTE61, \
+        WPI_JSON_PASTE60, \
+        WPI_JSON_PASTE59, \
+        WPI_JSON_PASTE58, \
+        WPI_JSON_PASTE57, \
+        WPI_JSON_PASTE56, \
+        WPI_JSON_PASTE55, \
+        WPI_JSON_PASTE54, \
+        WPI_JSON_PASTE53, \
+        WPI_JSON_PASTE52, \
+        WPI_JSON_PASTE51, \
+        WPI_JSON_PASTE50, \
+        WPI_JSON_PASTE49, \
+        WPI_JSON_PASTE48, \
+        WPI_JSON_PASTE47, \
+        WPI_JSON_PASTE46, \
+        WPI_JSON_PASTE45, \
+        WPI_JSON_PASTE44, \
+        WPI_JSON_PASTE43, \
+        WPI_JSON_PASTE42, \
+        WPI_JSON_PASTE41, \
+        WPI_JSON_PASTE40, \
+        WPI_JSON_PASTE39, \
+        WPI_JSON_PASTE38, \
+        WPI_JSON_PASTE37, \
+        WPI_JSON_PASTE36, \
+        WPI_JSON_PASTE35, \
+        WPI_JSON_PASTE34, \
+        WPI_JSON_PASTE33, \
+        WPI_JSON_PASTE32, \
+        WPI_JSON_PASTE31, \
+        WPI_JSON_PASTE30, \
+        WPI_JSON_PASTE29, \
+        WPI_JSON_PASTE28, \
+        WPI_JSON_PASTE27, \
+        WPI_JSON_PASTE26, \
+        WPI_JSON_PASTE25, \
+        WPI_JSON_PASTE24, \
+        WPI_JSON_PASTE23, \
+        WPI_JSON_PASTE22, \
+        WPI_JSON_PASTE21, \
+        WPI_JSON_PASTE20, \
+        WPI_JSON_PASTE19, \
+        WPI_JSON_PASTE18, \
+        WPI_JSON_PASTE17, \
+        WPI_JSON_PASTE16, \
+        WPI_JSON_PASTE15, \
+        WPI_JSON_PASTE14, \
+        WPI_JSON_PASTE13, \
+        WPI_JSON_PASTE12, \
+        WPI_JSON_PASTE11, \
+        WPI_JSON_PASTE10, \
+        WPI_JSON_PASTE9, \
+        WPI_JSON_PASTE8, \
+        WPI_JSON_PASTE7, \
+        WPI_JSON_PASTE6, \
+        WPI_JSON_PASTE5, \
+        WPI_JSON_PASTE4, \
+        WPI_JSON_PASTE3, \
+        WPI_JSON_PASTE2, \
+        WPI_JSON_PASTE1)(__VA_ARGS__))
+#define WPI_JSON_PASTE2(func, v1) func(v1)
+#define WPI_JSON_PASTE3(func, v1, v2) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE2(func, v2)
+#define WPI_JSON_PASTE4(func, v1, v2, v3) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE3(func, v2, v3)
+#define WPI_JSON_PASTE5(func, v1, v2, v3, v4) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE4(func, v2, v3, v4)
+#define WPI_JSON_PASTE6(func, v1, v2, v3, v4, v5) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE5(func, v2, v3, v4, v5)
+#define WPI_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE6(func, v2, v3, v4, v5, v6)
+#define WPI_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
+#define WPI_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
+#define WPI_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
+#define WPI_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
+#define WPI_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
+#define WPI_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
+#define WPI_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
+#define WPI_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
+#define WPI_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
+#define WPI_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
+#define WPI_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
+#define WPI_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
+#define WPI_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
+#define WPI_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
+#define WPI_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
+#define WPI_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
+#define WPI_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
+#define WPI_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
+#define WPI_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
+#define WPI_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
+#define WPI_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
+#define WPI_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
+#define WPI_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
+#define WPI_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
+#define WPI_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
+#define WPI_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
+#define WPI_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
+#define WPI_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
+#define WPI_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
+#define WPI_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
+#define WPI_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
+#define WPI_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
+#define WPI_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
+#define WPI_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
+#define WPI_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
+#define WPI_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
+#define WPI_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
+#define WPI_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
+#define WPI_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
+#define WPI_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
+#define WPI_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
+#define WPI_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
+#define WPI_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
+#define WPI_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
+#define WPI_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
+#define WPI_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
+#define WPI_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
+#define WPI_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
+#define WPI_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
+#define WPI_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
+#define WPI_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
+#define WPI_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
+#define WPI_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
+#define WPI_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
+#define WPI_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
+#define WPI_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
+#define WPI_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) WPI_JSON_PASTE2(func, v1) WPI_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
+
+#define WPI_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
+#define WPI_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
+#define WPI_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1);
+
+/*!
+@brief macro
+@def WPI_DEFINE_TYPE_INTRUSIVE
+@since version 3.9.0
+*/
+#define WPI_DEFINE_TYPE_INTRUSIVE(Type, ...)  \
+    friend void to_json(wpi::json& nlohmann_json_j, const Type& nlohmann_json_t) { WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_TO, __VA_ARGS__)) } \
+    friend void from_json(const wpi::json& nlohmann_json_j, Type& nlohmann_json_t) { WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_FROM, __VA_ARGS__)) }
+
+#define WPI_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
+    friend void to_json(wpi::json& nlohmann_json_j, const Type& nlohmann_json_t) { WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_TO, __VA_ARGS__)) } \
+    friend void from_json(const wpi::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+/*!
+@brief macro
+@def WPI_DEFINE_TYPE_NON_INTRUSIVE
+@since version 3.9.0
+*/
+#define WPI_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \
+    inline void to_json(wpi::json& nlohmann_json_j, const Type& nlohmann_json_t) { WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_TO, __VA_ARGS__)) } \
+    inline void from_json(const wpi::json& nlohmann_json_j, Type& nlohmann_json_t) { WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_FROM, __VA_ARGS__)) }
+
+#define WPI_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
+    inline void to_json(wpi::json& nlohmann_json_j, const Type& nlohmann_json_t) { WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_TO, __VA_ARGS__)) } \
+    inline void from_json(const wpi::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; WPI_JSON_EXPAND(WPI_JSON_PASTE(WPI_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+
+// inspired from https://stackoverflow.com/a/26745591
+// allows to call any std function as if (e.g. with begin):
+// using std::begin; begin(x);
+//
+// it allows using the detected idiom to retrieve the return type
+// of such an expression
+#define WPI_CAN_CALL_STD_FUNC_IMPL(std_name)                                 \
+    namespace detail {                                                            \
+    using std::std_name;                                                          \
+    \
+    template<typename... T>                                                       \
+    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \
+    }                                                                             \
+    \
+    namespace detail2 {                                                           \
+    struct std_name##_tag                                                         \
+    {                                                                             \
+    };                                                                            \
+    \
+    template<typename... T>                                                       \
+    std_name##_tag std_name(T&&...);                                              \
+    \
+    template<typename... T>                                                       \
+    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \
+    \
+    template<typename... T>                                                       \
+    struct would_call_std_##std_name                                              \
+    {                                                                             \
+        static constexpr auto const value = ::wpi::detail::                  \
+                                            is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
+    };                                                                            \
+    } /* namespace detail2 */ \
+    \
+    template<typename... T>                                                       \
+    struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...>   \
+    {                                                                             \
+    }
+
+#ifndef JSON_USE_IMPLICIT_CONVERSIONS
+    #define JSON_USE_IMPLICIT_CONVERSIONS 1
+#endif
+
+#if JSON_USE_IMPLICIT_CONVERSIONS
+    #define JSON_EXPLICIT
+#else
+    #define JSON_EXPLICIT explicit
+#endif
+
+#ifndef JSON_DISABLE_ENUM_SERIALIZATION
+    #define JSON_DISABLE_ENUM_SERIALIZATION 0
+#endif
+
+#ifndef JSON_USE_GLOBAL_UDLS
+    #define JSON_USE_GLOBAL_UDLS 1
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/macro_unscope.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/macro_unscope.h
new file mode 100644
index 0000000..00edbf7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/macro_unscope.h
@@ -0,0 +1,44 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+// restore clang diagnostic settings
+#if defined(__clang__)
+    #pragma clang diagnostic pop
+#endif
+
+// clean up
+#undef JSON_ASSERT
+#undef JSON_INTERNAL_CATCH
+#undef JSON_THROW
+#undef JSON_PRIVATE_UNLESS_TESTED
+#undef WPI_BASIC_JSON_TPL_DECLARATION
+#undef WPI_BASIC_JSON_TPL
+#undef JSON_EXPLICIT
+#undef WPI_CAN_CALL_STD_FUNC_IMPL
+#undef JSON_INLINE_VARIABLE
+#undef JSON_NO_UNIQUE_ADDRESS
+#undef JSON_DISABLE_ENUM_SERIALIZATION
+#undef JSON_USE_GLOBAL_UDLS
+
+#ifndef JSON_TEST_KEEP_MACROS
+    #undef JSON_CATCH
+    #undef JSON_TRY
+    #undef JSON_HAS_CPP_11
+    #undef JSON_HAS_CPP_14
+    #undef JSON_HAS_CPP_17
+    #undef JSON_HAS_CPP_20
+    #undef JSON_HAS_FILESYSTEM
+    #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+    #undef JSON_HAS_THREE_WAY_COMPARISON
+    #undef JSON_HAS_RANGES
+    #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+#endif
+
+#include <wpi/thirdparty/hedley/hedley_undef.h>
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/call_std/begin.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/call_std/begin.h
new file mode 100644
index 0000000..7ef8b07
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/call_std/begin.h
@@ -0,0 +1,17 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+WPI_CAN_CALL_STD_FUNC_IMPL(begin);
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/call_std/end.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/call_std/end.h
new file mode 100644
index 0000000..d727163
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/call_std/end.h
@@ -0,0 +1,17 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+WPI_CAN_CALL_STD_FUNC_IMPL(end);
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/cpp_future.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/cpp_future.h
new file mode 100644
index 0000000..d10f0cd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/cpp_future.h
@@ -0,0 +1,171 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2018 The Abseil Authors
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <array> // array
+#include <cstddef> // size_t
+#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
+#include <utility> // index_sequence, make_index_sequence, index_sequence_for
+
+#include <wpi/detail/macro_scope.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename T>
+using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+#ifdef JSON_HAS_CPP_14
+
+// the following utilities are natively available in C++14
+using std::enable_if_t;
+using std::index_sequence;
+using std::make_index_sequence;
+using std::index_sequence_for;
+
+#else
+
+// alias templates to reduce boilerplate
+template<bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h
+// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.
+
+//// START OF CODE FROM GOOGLE ABSEIL
+
+// integer_sequence
+//
+// Class template representing a compile-time integer sequence. An instantiation
+// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
+// type through its template arguments (which is a common need when
+// working with C++11 variadic templates). `absl::integer_sequence` is designed
+// to be a drop-in replacement for C++14's `std::integer_sequence`.
+//
+// Example:
+//
+//   template< class T, T... Ints >
+//   void user_function(integer_sequence<T, Ints...>);
+//
+//   int main()
+//   {
+//     // user_function's `T` will be deduced to `int` and `Ints...`
+//     // will be deduced to `0, 1, 2, 3, 4`.
+//     user_function(make_integer_sequence<int, 5>());
+//   }
+template <typename T, T... Ints>
+struct integer_sequence
+{
+    using value_type = T;
+    static constexpr std::size_t size() noexcept
+    {
+        return sizeof...(Ints);
+    }
+};
+
+// index_sequence
+//
+// A helper template for an `integer_sequence` of `size_t`,
+// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
+// `std::index_sequence`.
+template <size_t... Ints>
+using index_sequence = integer_sequence<size_t, Ints...>;
+
+namespace utility_internal
+{
+
+template <typename Seq, size_t SeqSize, size_t Rem>
+struct Extend;
+
+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 0>
+{
+    using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;
+};
+
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 1>
+{
+    using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;
+};
+
+// Recursion helper for 'make_integer_sequence<T, N>'.
+// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
+template <typename T, size_t N>
+struct Gen
+{
+    using type =
+        typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;
+};
+
+template <typename T>
+struct Gen<T, 0>
+{
+    using type = integer_sequence<T>;
+};
+
+}  // namespace utility_internal
+
+// Compile-time sequences of integers
+
+// make_integer_sequence
+//
+// This template alias is equivalent to
+// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
+// replacement for C++14's `std::make_integer_sequence`.
+template <typename T, T N>
+using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
+
+// make_index_sequence
+//
+// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
+// and is designed to be a drop-in replacement for C++14's
+// `std::make_index_sequence`.
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
+// index_sequence_for
+//
+// Converts a typename pack into an index sequence of the same length, and
+// is designed to be a drop-in replacement for C++14's
+// `std::index_sequence_for()`
+template <typename... Ts>
+using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
+
+//// END OF CODE FROM GOOGLE ABSEIL
+
+#endif
+
+// dispatch utility (taken from ranges-v3)
+template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
+template<> struct priority_tag<0> {};
+
+// taken from ranges-v3
+template<typename T>
+struct static_const
+{
+    static JSON_INLINE_VARIABLE constexpr T value{};
+};
+
+#ifndef JSON_HAS_CPP_17
+    template<typename T>
+    constexpr T static_const<T>::value;
+#endif
+
+template<typename T, typename... Args>
+inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)
+{
+    return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};
+}
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/detected.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/detected.h
new file mode 100644
index 0000000..7a667f3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/detected.h
@@ -0,0 +1,70 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <type_traits>
+
+#include <wpi/detail/meta/void_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// https://en.cppreference.com/w/cpp/experimental/is_detected
+struct nonesuch
+{
+    nonesuch() = delete;
+    ~nonesuch() = delete;
+    nonesuch(nonesuch const&) = delete;
+    nonesuch(nonesuch const&&) = delete;
+    void operator=(nonesuch const&) = delete;
+    void operator=(nonesuch&&) = delete;
+};
+
+template<class Default,
+         class AlwaysVoid,
+         template<class...> class Op,
+         class... Args>
+struct detector
+{
+    using value_t = std::false_type;
+    using type = Default;
+};
+
+template<class Default, template<class...> class Op, class... Args>
+struct detector<Default, void_t<Op<Args...>>, Op, Args...>
+{
+    using value_t = std::true_type;
+    using type = Op<Args...>;
+};
+
+template<template<class...> class Op, class... Args>
+using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
+
+template<template<class...> class Op, class... Args>
+struct is_detected_lazy : is_detected<Op, Args...> { };
+
+template<template<class...> class Op, class... Args>
+using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
+
+template<class Default, template<class...> class Op, class... Args>
+using detected_or = detector<Default, void, Op, Args...>;
+
+template<class Default, template<class...> class Op, class... Args>
+using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+
+template<class Expected, template<class...> class Op, class... Args>
+using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
+
+template<class To, template<class...> class Op, class... Args>
+using is_detected_convertible =
+    std::is_convertible<detected_t<Op, Args...>, To>;
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/identity_tag.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/identity_tag.h
new file mode 100644
index 0000000..a062264
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/identity_tag.h
@@ -0,0 +1,21 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/abi_macros.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// dispatching helper struct
+template <class T> struct identity_tag {};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/is_sax.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/is_sax.h
new file mode 100644
index 0000000..689bf33
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/is_sax.h
@@ -0,0 +1,159 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstdint> // size_t
+#include <utility> // declval
+#include <string> // string
+
+#include <wpi/detail/abi_macros.h>
+#include <wpi/detail/meta/detected.h>
+#include <wpi/detail/meta/type_traits.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename T>
+using null_function_t = decltype(std::declval<T&>().null());
+
+template<typename T>
+using boolean_function_t =
+    decltype(std::declval<T&>().boolean(std::declval<bool>()));
+
+template<typename T, typename Integer>
+using number_integer_function_t =
+    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
+
+template<typename T, typename Unsigned>
+using number_unsigned_function_t =
+    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
+
+template<typename T, typename Float, typename String>
+using number_float_function_t = decltype(std::declval<T&>().number_float(
+                                    std::declval<Float>(), std::declval<const String&>()));
+
+template<typename T, typename String>
+using string_function_t =
+    decltype(std::declval<T&>().string(std::declval<String&>()));
+
+template<typename T, typename Binary>
+using binary_function_t =
+    decltype(std::declval<T&>().binary(std::declval<Binary&>()));
+
+template<typename T>
+using start_object_function_t =
+    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
+
+template<typename T, typename String>
+using key_function_t =
+    decltype(std::declval<T&>().key(std::declval<String&>()));
+
+template<typename T>
+using end_object_function_t = decltype(std::declval<T&>().end_object());
+
+template<typename T>
+using start_array_function_t =
+    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
+
+template<typename T>
+using end_array_function_t = decltype(std::declval<T&>().end_array());
+
+template<typename T, typename Exception>
+using parse_error_function_t = decltype(std::declval<T&>().parse_error(
+        std::declval<std::size_t>(), std::declval<const std::string&>(),
+        std::declval<const Exception&>()));
+
+template<typename SAX, typename BasicJsonType>
+struct is_sax
+{
+  private:
+    static_assert(is_basic_json<BasicJsonType>::value,
+                  "BasicJsonType must be of type basic_json<...>");
+
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using exception_t = typename BasicJsonType::exception;
+
+  public:
+    static constexpr bool value =
+        is_detected_exact<bool, null_function_t, SAX>::value &&
+        is_detected_exact<bool, boolean_function_t, SAX>::value &&
+        is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
+        is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
+        is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
+        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
+        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
+        is_detected_exact<bool, start_object_function_t, SAX>::value &&
+        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
+        is_detected_exact<bool, end_object_function_t, SAX>::value &&
+        is_detected_exact<bool, start_array_function_t, SAX>::value &&
+        is_detected_exact<bool, end_array_function_t, SAX>::value &&
+        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
+};
+
+template<typename SAX, typename BasicJsonType>
+struct is_sax_static_asserts
+{
+  private:
+    static_assert(is_basic_json<BasicJsonType>::value,
+                  "BasicJsonType must be of type basic_json<...>");
+
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using exception_t = typename BasicJsonType::exception;
+
+  public:
+    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
+                  "Missing/invalid function: bool null()");
+    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
+                  "Missing/invalid function: bool boolean(bool)");
+    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
+                  "Missing/invalid function: bool boolean(bool)");
+    static_assert(
+        is_detected_exact<bool, number_integer_function_t, SAX,
+        number_integer_t>::value,
+        "Missing/invalid function: bool number_integer(number_integer_t)");
+    static_assert(
+        is_detected_exact<bool, number_unsigned_function_t, SAX,
+        number_unsigned_t>::value,
+        "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
+    static_assert(is_detected_exact<bool, number_float_function_t, SAX,
+                  number_float_t, string_t>::value,
+                  "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
+    static_assert(
+        is_detected_exact<bool, string_function_t, SAX, string_t>::value,
+        "Missing/invalid function: bool string(string_t&)");
+    static_assert(
+        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
+        "Missing/invalid function: bool binary(binary_t&)");
+    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
+                  "Missing/invalid function: bool start_object(std::size_t)");
+    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
+                  "Missing/invalid function: bool key(string_t&)");
+    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
+                  "Missing/invalid function: bool end_object()");
+    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
+                  "Missing/invalid function: bool start_array(std::size_t)");
+    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
+                  "Missing/invalid function: bool end_array()");
+    static_assert(
+        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
+        "Missing/invalid function: bool parse_error(std::size_t, const "
+        "std::string&, const exception&)");
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/std_fs.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/std_fs.h
new file mode 100644
index 0000000..c012d27
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/std_fs.h
@@ -0,0 +1,29 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/macro_scope.h>
+
+#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
+#include <experimental/filesystem>
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+namespace std_fs = std::experimental::filesystem;
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
+#elif JSON_HAS_FILESYSTEM
+#include <filesystem>
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+namespace std_fs = std::filesystem;
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/type_traits.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/type_traits.h
new file mode 100644
index 0000000..254f099
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/type_traits.h
@@ -0,0 +1,740 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <limits> // numeric_limits
+#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
+#include <utility> // declval
+#include <tuple> // tuple
+
+#include <wpi/detail/iterators/iterator_traits.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/call_std/begin.h>
+#include <wpi/detail/meta/call_std/end.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/detected.h>
+#include <wpi/json_fwd.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+/*!
+@brief detail namespace with internal helper functions
+
+This namespace collects functions that should not be exposed,
+implementations of some @ref basic_json methods, and meta-programming helpers.
+
+@since version 2.1.0
+*/
+namespace detail
+{
+
+/////////////
+// helpers //
+/////////////
+
+// Note to maintainers:
+//
+// Every trait in this file expects a non CV-qualified type.
+// The only exceptions are in the 'aliases for detected' section
+// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
+//
+// In this case, T has to be properly CV-qualified to constraint the function arguments
+// (e.g. to_json(BasicJsonType&, const T&))
+
+template<typename> struct is_basic_json : std::false_type {};
+
+WPI_BASIC_JSON_TPL_DECLARATION
+struct is_basic_json<WPI_BASIC_JSON_TPL> : std::true_type {};
+
+// used by exceptions create() member functions
+// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
+// false_type otherwise
+template<typename BasicJsonContext>
+struct is_basic_json_context :
+    std::integral_constant < bool,
+    is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
+    || std::is_same<BasicJsonContext, std::nullptr_t>::value >
+{};
+
+//////////////////////
+// json_ref helpers //
+//////////////////////
+
+template<typename>
+class json_ref;
+
+template<typename>
+struct is_json_ref : std::false_type {};
+
+template<typename T>
+struct is_json_ref<json_ref<T>> : std::true_type {};
+
+//////////////////////////
+// aliases for detected //
+//////////////////////////
+
+template<typename T>
+using mapped_type_t = typename T::mapped_type;
+
+template<typename T>
+using key_type_t = typename T::key_type;
+
+template<typename T>
+using value_type_t = typename T::value_type;
+
+template<typename T>
+using difference_type_t = typename T::difference_type;
+
+template<typename T>
+using pointer_t = typename T::pointer;
+
+template<typename T>
+using reference_t = typename T::reference;
+
+template<typename T>
+using iterator_category_t = typename T::iterator_category;
+
+template<typename T, typename... Args>
+using to_json_function = decltype(T::to_json(std::declval<Args>()...));
+
+template<typename T, typename... Args>
+using from_json_function = decltype(T::from_json(std::declval<Args>()...));
+
+template<typename T, typename U>
+using get_template_function = decltype(std::declval<T>().template get<U>());
+
+// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
+template<typename BasicJsonType, typename T, typename = void>
+struct has_from_json : std::false_type {};
+
+// trait checking if j.get<T> is valid
+// use this trait instead of std::is_constructible or std::is_convertible,
+// both rely on, or make use of implicit conversions, and thus fail when T
+// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
+template <typename BasicJsonType, typename T>
+struct is_getable
+{
+    static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
+};
+
+template<typename BasicJsonType, typename T>
+struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer<T, void>;
+
+    static constexpr bool value =
+        is_detected_exact<void, from_json_function, serializer,
+        const BasicJsonType&, T&>::value;
+};
+
+// This trait checks if JSONSerializer<T>::from_json(json const&) exists
+// this overload is used for non-default-constructible user-defined-types
+template<typename BasicJsonType, typename T, typename = void>
+struct has_non_default_from_json : std::false_type {};
+
+template<typename BasicJsonType, typename T>
+struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer<T, void>;
+
+    static constexpr bool value =
+        is_detected_exact<T, from_json_function, serializer,
+        const BasicJsonType&>::value;
+};
+
+// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
+// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
+template<typename BasicJsonType, typename T, typename = void>
+struct has_to_json : std::false_type {};
+
+template<typename BasicJsonType, typename T>
+struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer<T, void>;
+
+    static constexpr bool value =
+        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
+        T>::value;
+};
+
+template<typename T>
+using detect_key_compare = typename T::key_compare;
+
+template<typename T>
+struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
+
+// obtains the actual object key comparator
+template<typename BasicJsonType>
+struct actual_object_comparator
+{
+    using object_t = typename BasicJsonType::object_t;
+    using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
+    using type = typename std::conditional < has_key_compare<object_t>::value,
+          typename object_t::key_compare, object_comparator_t>::type;
+};
+
+template<typename BasicJsonType>
+using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
+
+///////////////////
+// is_ functions //
+///////////////////
+
+// https://en.cppreference.com/w/cpp/types/conjunction
+template<class...> struct conjunction : std::true_type { };
+template<class B> struct conjunction<B> : B { };
+template<class B, class... Bn>
+struct conjunction<B, Bn...>
+: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
+
+// https://en.cppreference.com/w/cpp/types/negation
+template<class B> struct negation : std::integral_constant < bool, !B::value > { };
+
+// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
+// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
+// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
+template <typename T>
+struct is_default_constructible : std::is_default_constructible<T> {};
+
+template <typename T1, typename T2>
+struct is_default_constructible<std::pair<T1, T2>>
+            : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
+
+template <typename T1, typename T2>
+struct is_default_constructible<const std::pair<T1, T2>>
+            : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
+
+template <typename... Ts>
+struct is_default_constructible<std::tuple<Ts...>>
+            : conjunction<is_default_constructible<Ts>...> {};
+
+template <typename... Ts>
+struct is_default_constructible<const std::tuple<Ts...>>
+            : conjunction<is_default_constructible<Ts>...> {};
+
+
+template <typename T, typename... Args>
+struct is_constructible : std::is_constructible<T, Args...> {};
+
+template <typename T1, typename T2>
+struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
+
+template <typename T1, typename T2>
+struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
+
+template <typename... Ts>
+struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
+
+template <typename... Ts>
+struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
+
+
+template<typename T, typename = void>
+struct is_iterator_traits : std::false_type {};
+
+template<typename T>
+struct is_iterator_traits<iterator_traits<T>>
+{
+  private:
+    using traits = iterator_traits<T>;
+
+  public:
+    static constexpr auto value =
+        is_detected<value_type_t, traits>::value &&
+        is_detected<difference_type_t, traits>::value &&
+        is_detected<pointer_t, traits>::value &&
+        is_detected<iterator_category_t, traits>::value &&
+        is_detected<reference_t, traits>::value;
+};
+
+template<typename T>
+struct is_range
+{
+  private:
+    using t_ref = typename std::add_lvalue_reference<T>::type;
+
+    using iterator = detected_t<result_of_begin, t_ref>;
+    using sentinel = detected_t<result_of_end, t_ref>;
+
+    // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
+    // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
+    // but reimplementing these would be too much work, as a lot of other concepts are used underneath
+    static constexpr auto is_iterator_begin =
+        is_iterator_traits<iterator_traits<iterator>>::value;
+
+  public:
+    static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
+};
+
+template<typename R>
+using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
+
+template<typename T>
+using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
+
+// The following implementation of is_complete_type is taken from
+// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
+// and is written by Xiang Fan who agreed to using it in this library.
+
+template<typename T, typename = void>
+struct is_complete_type : std::false_type {};
+
+template<typename T>
+struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
+
+template<typename BasicJsonType, typename CompatibleObjectType,
+         typename = void>
+struct is_compatible_object_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename CompatibleObjectType>
+struct is_compatible_object_type_impl <
+    BasicJsonType, CompatibleObjectType,
+    enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
+    is_detected<key_type_t, CompatibleObjectType>::value >>
+{
+    using object_t = typename BasicJsonType::object_t;
+
+    // macOS's is_constructible does not play well with nonesuch...
+    static constexpr bool value =
+        is_constructible<typename object_t::key_type,
+        typename CompatibleObjectType::key_type>::value &&
+        is_constructible<typename object_t::mapped_type,
+        typename CompatibleObjectType::mapped_type>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleObjectType>
+struct is_compatible_object_type
+    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
+
+template<typename BasicJsonType, typename ConstructibleObjectType,
+         typename = void>
+struct is_constructible_object_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename ConstructibleObjectType>
+struct is_constructible_object_type_impl <
+    BasicJsonType, ConstructibleObjectType,
+    enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
+    is_detected<key_type_t, ConstructibleObjectType>::value >>
+{
+    using object_t = typename BasicJsonType::object_t;
+
+    static constexpr bool value =
+        (is_default_constructible<ConstructibleObjectType>::value &&
+         (std::is_move_assignable<ConstructibleObjectType>::value ||
+          std::is_copy_assignable<ConstructibleObjectType>::value) &&
+         (is_constructible<typename ConstructibleObjectType::key_type,
+          typename object_t::key_type>::value &&
+          std::is_same <
+          typename object_t::mapped_type,
+          typename ConstructibleObjectType::mapped_type >::value)) ||
+        (has_from_json<BasicJsonType,
+         typename ConstructibleObjectType::mapped_type>::value ||
+         has_non_default_from_json <
+         BasicJsonType,
+         typename ConstructibleObjectType::mapped_type >::value);
+};
+
+template<typename BasicJsonType, typename ConstructibleObjectType>
+struct is_constructible_object_type
+    : is_constructible_object_type_impl<BasicJsonType,
+      ConstructibleObjectType> {};
+
+template<typename BasicJsonType, typename CompatibleStringType>
+struct is_compatible_string_type
+{
+    static constexpr auto value =
+        is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
+};
+
+template<typename BasicJsonType, typename ConstructibleStringType>
+struct is_constructible_string_type
+{
+    // launder type through decltype() to fix compilation failure on ICPC
+#ifdef __INTEL_COMPILER
+    using laundered_type = decltype(std::declval<ConstructibleStringType>());
+#else
+    using laundered_type = ConstructibleStringType;
+#endif
+
+    static constexpr auto value =
+        conjunction <
+        is_constructible<laundered_type, typename BasicJsonType::string_t>,
+        is_detected_exact<typename BasicJsonType::string_t::value_type,
+        value_type_t, laundered_type >>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
+struct is_compatible_array_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename CompatibleArrayType>
+struct is_compatible_array_type_impl <
+    BasicJsonType, CompatibleArrayType,
+    enable_if_t <
+    is_detected<iterator_t, CompatibleArrayType>::value&&
+    is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
+// special case for types like std::filesystem::path whose iterator's value_type are themselves
+// c.f. https://github.com/nlohmann/json/pull/3073
+    !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
+{
+    static constexpr bool value =
+        is_constructible<BasicJsonType,
+        range_value_t<CompatibleArrayType>>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleArrayType>
+struct is_compatible_array_type
+    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
+
+template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
+struct is_constructible_array_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename ConstructibleArrayType>
+struct is_constructible_array_type_impl <
+    BasicJsonType, ConstructibleArrayType,
+    enable_if_t<std::is_same<ConstructibleArrayType,
+    typename BasicJsonType::value_type>::value >>
+            : std::true_type {};
+
+template<typename BasicJsonType, typename ConstructibleArrayType>
+struct is_constructible_array_type_impl <
+    BasicJsonType, ConstructibleArrayType,
+    enable_if_t < !std::is_same<ConstructibleArrayType,
+    typename BasicJsonType::value_type>::value&&
+    !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
+    is_default_constructible<ConstructibleArrayType>::value&&
+(std::is_move_assignable<ConstructibleArrayType>::value ||
+ std::is_copy_assignable<ConstructibleArrayType>::value)&&
+is_detected<iterator_t, ConstructibleArrayType>::value&&
+is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
+is_detected<range_value_t, ConstructibleArrayType>::value&&
+// special case for types like std::filesystem::path whose iterator's value_type are themselves
+// c.f. https://github.com/nlohmann/json/pull/3073
+!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
+        is_complete_type <
+        detected_t<range_value_t, ConstructibleArrayType >>::value >>
+{
+    using value_type = range_value_t<ConstructibleArrayType>;
+
+    static constexpr bool value =
+        std::is_same<value_type,
+        typename BasicJsonType::array_t::value_type>::value ||
+        has_from_json<BasicJsonType,
+        value_type>::value ||
+        has_non_default_from_json <
+        BasicJsonType,
+        value_type >::value;
+};
+
+template<typename BasicJsonType, typename ConstructibleArrayType>
+struct is_constructible_array_type
+    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
+
+template<typename RealIntegerType, typename CompatibleNumberIntegerType,
+         typename = void>
+struct is_compatible_integer_type_impl : std::false_type {};
+
+template<typename RealIntegerType, typename CompatibleNumberIntegerType>
+struct is_compatible_integer_type_impl <
+    RealIntegerType, CompatibleNumberIntegerType,
+    enable_if_t < std::is_integral<RealIntegerType>::value&&
+    std::is_integral<CompatibleNumberIntegerType>::value&&
+    !std::is_same<bool, CompatibleNumberIntegerType>::value >>
+{
+    // is there an assert somewhere on overflows?
+    using RealLimits = std::numeric_limits<RealIntegerType>;
+    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
+
+    static constexpr auto value =
+        is_constructible<RealIntegerType,
+        CompatibleNumberIntegerType>::value &&
+        CompatibleLimits::is_integer &&
+        RealLimits::is_signed == CompatibleLimits::is_signed;
+};
+
+template<typename RealIntegerType, typename CompatibleNumberIntegerType>
+struct is_compatible_integer_type
+    : is_compatible_integer_type_impl<RealIntegerType,
+      CompatibleNumberIntegerType> {};
+
+template<typename BasicJsonType, typename CompatibleType, typename = void>
+struct is_compatible_type_impl: std::false_type {};
+
+template<typename BasicJsonType, typename CompatibleType>
+struct is_compatible_type_impl <
+    BasicJsonType, CompatibleType,
+    enable_if_t<is_complete_type<CompatibleType>::value >>
+{
+    static constexpr bool value =
+        has_to_json<BasicJsonType, CompatibleType>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleType>
+struct is_compatible_type
+    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
+
+template<typename T1, typename T2>
+struct is_constructible_tuple : std::false_type {};
+
+template<typename T1, typename... Args>
+struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
+
+template<typename BasicJsonType, typename T>
+struct is_json_iterator_of : std::false_type {};
+
+template<typename BasicJsonType>
+struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
+
+template<typename BasicJsonType>
+struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
+{};
+
+// checks if a given type T is a template specialization of Primary
+template<template <typename...> class Primary, typename T>
+struct is_specialization_of : std::false_type {};
+
+template<template <typename...> class Primary, typename... Args>
+struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
+
+template<typename T>
+using is_json_pointer = is_specialization_of<::wpi::json_pointer, uncvref_t<T>>;
+
+// checks if A and B are comparable using Compare functor
+template<typename Compare, typename A, typename B, typename = void>
+struct is_comparable : std::false_type {};
+
+template<typename Compare, typename A, typename B>
+struct is_comparable<Compare, A, B, void_t<
+decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
+decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
+>> : std::true_type {};
+
+template<typename T>
+using detect_is_transparent = typename T::is_transparent;
+
+// type trait to check if KeyType can be used as object key (without a BasicJsonType)
+// see is_usable_as_basic_json_key_type below
+template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
+         bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
+using is_usable_as_key_type = typename std::conditional <
+                              is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value
+                              && !(ExcludeObjectKeyType && std::is_same<KeyType,
+                                   ObjectKeyType>::value)
+                              && (!RequireTransparentComparator
+                                  || is_detected <detect_is_transparent, Comparator>::value)
+                              && !is_json_pointer<KeyType>::value,
+                              std::true_type,
+                              std::false_type >::type;
+
+// type trait to check if KeyType can be used as object key
+// true if:
+//   - KeyType is comparable with BasicJsonType::object_t::key_type
+//   - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
+//   - the comparator is transparent or RequireTransparentComparator is false
+//   - KeyType is not a JSON iterator or json_pointer
+template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
+         bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
+using is_usable_as_basic_json_key_type = typename std::conditional <
+        is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
+        typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
+        RequireTransparentComparator, ExcludeObjectKeyType>::value
+        && !is_json_iterator_of<BasicJsonType, KeyType>::value,
+        std::true_type,
+        std::false_type >::type;
+
+template<typename ObjectType, typename KeyType>
+using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
+
+// type trait to check if object_t has an erase() member functions accepting KeyType
+template<typename BasicJsonType, typename KeyType>
+using has_erase_with_key_type = typename std::conditional <
+                                is_detected <
+                                detect_erase_with_key_type,
+                                typename BasicJsonType::object_t, KeyType >::value,
+                                std::true_type,
+                                std::false_type >::type;
+
+// a naive helper to check if a type is an ordered_map (exploits the fact that
+// ordered_map inherits capacity() from std::vector)
+template <typename T>
+struct is_ordered_map
+{
+    using one = char;
+
+    struct two
+    {
+        char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+    };
+
+    template <typename C> static one test( decltype(&C::capacity) ) ;
+    template <typename C> static two test(...);
+
+    enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+};
+
+// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
+template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
+T conditional_static_cast(U value)
+{
+    return static_cast<T>(value);
+}
+
+template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
+T conditional_static_cast(U value)
+{
+    return value;
+}
+
+template<typename... Types>
+using all_integral = conjunction<std::is_integral<Types>...>;
+
+template<typename... Types>
+using all_signed = conjunction<std::is_signed<Types>...>;
+
+template<typename... Types>
+using all_unsigned = conjunction<std::is_unsigned<Types>...>;
+
+// there's a disjunction trait in another PR; replace when merged
+template<typename... Types>
+using same_sign = std::integral_constant < bool,
+      all_signed<Types...>::value || all_unsigned<Types...>::value >;
+
+template<typename OfType, typename T>
+using never_out_of_range = std::integral_constant < bool,
+      (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
+      || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
+
+template<typename OfType, typename T,
+         bool OfTypeSigned = std::is_signed<OfType>::value,
+         bool TSigned = std::is_signed<T>::value>
+struct value_in_range_of_impl2;
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, false, false>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, true, false>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, false, true>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, true, true>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())
+               && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+template<typename OfType, typename T,
+         bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
+         typename = detail::enable_if_t<all_integral<OfType, T>::value>>
+struct value_in_range_of_impl1;
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl1<OfType, T, false>
+{
+    static constexpr bool test(T val)
+    {
+        return value_in_range_of_impl2<OfType, T>::test(val);
+    }
+};
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl1<OfType, T, true>
+{
+    static constexpr bool test(T /*val*/)
+    {
+        return true;
+    }
+};
+
+template<typename OfType, typename T>
+inline constexpr bool value_in_range_of(T val)
+{
+    return value_in_range_of_impl1<OfType, T>::test(val);
+}
+
+template<bool Value>
+using bool_constant = std::integral_constant<bool, Value>;
+
+///////////////////////////////////////////////////////////////////////////////
+// is_c_string
+///////////////////////////////////////////////////////////////////////////////
+
+namespace impl
+{
+
+template<typename T>
+inline constexpr bool is_c_string()
+{
+    using TUnExt = typename std::remove_extent<T>::type;
+    using TUnCVExt = typename std::remove_cv<TUnExt>::type;
+    using TUnPtr = typename std::remove_pointer<T>::type;
+    using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
+    return
+        (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
+        || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
+}
+
+}  // namespace impl
+
+// checks whether T is a [cv] char */[cv] char[] C string
+template<typename T>
+struct is_c_string : bool_constant<impl::is_c_string<T>()> {};
+
+template<typename T>
+using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
+
+///////////////////////////////////////////////////////////////////////////////
+// is_transparent
+///////////////////////////////////////////////////////////////////////////////
+
+namespace impl
+{
+
+template<typename T>
+inline constexpr bool is_transparent()
+{
+    return is_detected<detect_is_transparent, T>::value;
+}
+
+}  // namespace impl
+
+// checks whether T has a member named is_transparent
+template<typename T>
+struct is_transparent : bool_constant<impl::is_transparent<T>()> {};
+
+///////////////////////////////////////////////////////////////////////////////
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/void_t.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/void_t.h
new file mode 100644
index 0000000..8198f93
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/meta/void_t.h
@@ -0,0 +1,24 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/abi_macros.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename ...Ts> struct make_void
+{
+    using type = void;
+};
+template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/binary_writer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/binary_writer.h
new file mode 100644
index 0000000..8e80abe
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/binary_writer.h
@@ -0,0 +1,1838 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // reverse
+#include <array> // array
+#include <map> // map
+#include <cmath> // isnan, isinf
+#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
+#include <cstring> // memcpy
+#include <limits> // numeric_limits
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+#include <wpi/detail/input/binary_reader.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/output/output_adapters.h>
+#include <wpi/detail/string_concat.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////
+// binary writer //
+///////////////////
+
+/*!
+@brief serialization to CBOR and MessagePack values
+*/
+template<typename BasicJsonType, typename CharType>
+class binary_writer
+{
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+
+  public:
+    /*!
+    @brief create a binary writer
+
+    @param[in] adapter  output adapter to write to
+    */
+    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))
+    {
+        JSON_ASSERT(oa);
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    @pre       j.type() == value_t::object
+    */
+    void write_bson(const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::object:
+            {
+                write_bson_object(*j.m_value.object);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::array:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
+            }
+        }
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    */
+    void write_cbor(const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+            {
+                oa->write_character(to_char_type(0xF6));
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                oa->write_character(j.m_value.boolean
+                                    ? to_char_type(0xF5)
+                                    : to_char_type(0xF4));
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                if (j.m_value.number_integer >= 0)
+                {
+                    // CBOR does not differentiate between positive signed
+                    // integers and unsigned integers. Therefore, we used the
+                    // code from the value_t::number_unsigned case here.
+                    if (j.m_value.number_integer <= 0x17)
+                    {
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x18));
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x19));
+                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x1A));
+                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+                    }
+                    else
+                    {
+                        oa->write_character(to_char_type(0x1B));
+                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+                    }
+                }
+                else
+                {
+                    // The conversions below encode the sign in the first
+                    // byte, and the value is converted to a positive number.
+                    const auto positive_number = -1 - j.m_value.number_integer;
+                    if (j.m_value.number_integer >= -24)
+                    {
+                        write_number(static_cast<std::uint8_t>(0x20 + positive_number));
+                    }
+                    else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x38));
+                        write_number(static_cast<std::uint8_t>(positive_number));
+                    }
+                    else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x39));
+                        write_number(static_cast<std::uint16_t>(positive_number));
+                    }
+                    else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x3A));
+                        write_number(static_cast<std::uint32_t>(positive_number));
+                    }
+                    else
+                    {
+                        oa->write_character(to_char_type(0x3B));
+                        write_number(static_cast<std::uint64_t>(positive_number));
+                    }
+                }
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x18));
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x19));
+                    write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x1A));
+                    write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
+                }
+                else
+                {
+                    oa->write_character(to_char_type(0x1B));
+                    write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
+                }
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                if (std::isnan(j.m_value.number_float))
+                {
+                    // NaN is 0xf97e00 in CBOR
+                    oa->write_character(to_char_type(0xF9));
+                    oa->write_character(to_char_type(0x7E));
+                    oa->write_character(to_char_type(0x00));
+                }
+                else if (std::isinf(j.m_value.number_float))
+                {
+                    // Infinity is 0xf97c00, -Infinity is 0xf9fc00
+                    oa->write_character(to_char_type(0xf9));
+                    oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
+                    oa->write_character(to_char_type(0x00));
+                }
+                else
+                {
+                    write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
+                }
+                break;
+            }
+
+            case value_t::string:
+            {
+                // step 1: write control byte and the string length
+                const auto N = j.m_value.string->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0x60 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x78));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x79));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x7A));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x7B));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write the string
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
+                    j.m_value.string->size());
+                break;
+            }
+
+            case value_t::array:
+            {
+                // step 1: write control byte and the array size
+                const auto N = j.m_value.array->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0x80 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x98));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x99));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x9A));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x9B));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.array)
+                {
+                    write_cbor(el);
+                }
+                break;
+            }
+
+            case value_t::binary:
+            {
+                if (j.m_value.binary->has_subtype())
+                {
+                    if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xd8));
+                        write_number(static_cast<std::uint8_t>(j.m_value.binary->subtype()));
+                    }
+                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xd9));
+                        write_number(static_cast<std::uint16_t>(j.m_value.binary->subtype()));
+                    }
+                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xda));
+                        write_number(static_cast<std::uint32_t>(j.m_value.binary->subtype()));
+                    }
+                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xdb));
+                        write_number(static_cast<std::uint64_t>(j.m_value.binary->subtype()));
+                    }
+                }
+
+                // step 1: write control byte and the binary array size
+                const auto N = j.m_value.binary->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0x40 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x58));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x59));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x5A));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x5B));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write each element
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+                    N);
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                // step 1: write control byte and the object size
+                const auto N = j.m_value.object->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0xA0 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xB8));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xB9));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xBA));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xBB));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.object)
+                {
+                    write_cbor(el.first);
+                    write_cbor(el.second);
+                }
+                break;
+            }
+
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    */
+    void write_msgpack(const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::null: // nil
+            {
+                oa->write_character(to_char_type(0xC0));
+                break;
+            }
+
+            case value_t::boolean: // true and false
+            {
+                oa->write_character(j.m_value.boolean
+                                    ? to_char_type(0xC3)
+                                    : to_char_type(0xC2));
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                if (j.m_value.number_integer >= 0)
+                {
+                    // MessagePack does not differentiate between positive
+                    // signed integers and unsigned integers. Therefore, we used
+                    // the code from the value_t::number_unsigned case here.
+                    if (j.m_value.number_unsigned < 128)
+                    {
+                        // positive fixnum
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        // uint 8
+                        oa->write_character(to_char_type(0xCC));
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        // uint 16
+                        oa->write_character(to_char_type(0xCD));
+                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        // uint 32
+                        oa->write_character(to_char_type(0xCE));
+                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+                    {
+                        // uint 64
+                        oa->write_character(to_char_type(0xCF));
+                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+                    }
+                }
+                else
+                {
+                    if (j.m_value.number_integer >= -32)
+                    {
+                        // negative fixnum
+                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+                    {
+                        // int 8
+                        oa->write_character(to_char_type(0xD0));
+                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+                    {
+                        // int 16
+                        oa->write_character(to_char_type(0xD1));
+                        write_number(static_cast<std::int16_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+                    {
+                        // int 32
+                        oa->write_character(to_char_type(0xD2));
+                        write_number(static_cast<std::int32_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+                    {
+                        // int 64
+                        oa->write_character(to_char_type(0xD3));
+                        write_number(static_cast<std::int64_t>(j.m_value.number_integer));
+                    }
+                }
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned < 128)
+                {
+                    // positive fixnum
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    // uint 8
+                    oa->write_character(to_char_type(0xCC));
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // uint 16
+                    oa->write_character(to_char_type(0xCD));
+                    write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // uint 32
+                    oa->write_character(to_char_type(0xCE));
+                    write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    // uint 64
+                    oa->write_character(to_char_type(0xCF));
+                    write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+                }
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
+                break;
+            }
+
+            case value_t::string:
+            {
+                // step 1: write control byte and the string length
+                const auto N = j.m_value.string->size();
+                if (N <= 31)
+                {
+                    // fixstr
+                    write_number(static_cast<std::uint8_t>(0xA0 | N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    // str 8
+                    oa->write_character(to_char_type(0xD9));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // str 16
+                    oa->write_character(to_char_type(0xDA));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // str 32
+                    oa->write_character(to_char_type(0xDB));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 2: write the string
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
+                    j.m_value.string->size());
+                break;
+            }
+
+            case value_t::array:
+            {
+                // step 1: write control byte and the array size
+                const auto N = j.m_value.array->size();
+                if (N <= 15)
+                {
+                    // fixarray
+                    write_number(static_cast<std::uint8_t>(0x90 | N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // array 16
+                    oa->write_character(to_char_type(0xDC));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // array 32
+                    oa->write_character(to_char_type(0xDD));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.array)
+                {
+                    write_msgpack(el);
+                }
+                break;
+            }
+
+            case value_t::binary:
+            {
+                // step 0: determine if the binary type has a set subtype to
+                // determine whether or not to use the ext or fixext types
+                const bool use_ext = j.m_value.binary->has_subtype();
+
+                // step 1: write control byte and the byte string length
+                const auto N = j.m_value.binary->size();
+                if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    std::uint8_t output_type{};
+                    bool fixed = true;
+                    if (use_ext)
+                    {
+                        switch (N)
+                        {
+                            case 1:
+                                output_type = 0xD4; // fixext 1
+                                break;
+                            case 2:
+                                output_type = 0xD5; // fixext 2
+                                break;
+                            case 4:
+                                output_type = 0xD6; // fixext 4
+                                break;
+                            case 8:
+                                output_type = 0xD7; // fixext 8
+                                break;
+                            case 16:
+                                output_type = 0xD8; // fixext 16
+                                break;
+                            default:
+                                output_type = 0xC7; // ext 8
+                                fixed = false;
+                                break;
+                        }
+
+                    }
+                    else
+                    {
+                        output_type = 0xC4; // bin 8
+                        fixed = false;
+                    }
+
+                    oa->write_character(to_char_type(output_type));
+                    if (!fixed)
+                    {
+                        write_number(static_cast<std::uint8_t>(N));
+                    }
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    std::uint8_t output_type = use_ext
+                                               ? 0xC8 // ext 16
+                                               : 0xC5; // bin 16
+
+                    oa->write_character(to_char_type(output_type));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    std::uint8_t output_type = use_ext
+                                               ? 0xC9 // ext 32
+                                               : 0xC6; // bin 32
+
+                    oa->write_character(to_char_type(output_type));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 1.5: if this is an ext type, write the subtype
+                if (use_ext)
+                {
+                    write_number(static_cast<std::int8_t>(j.m_value.binary->subtype()));
+                }
+
+                // step 2: write the byte string
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+                    N);
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                // step 1: write control byte and the object size
+                const auto N = j.m_value.object->size();
+                if (N <= 15)
+                {
+                    // fixmap
+                    write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // map 16
+                    oa->write_character(to_char_type(0xDE));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // map 32
+                    oa->write_character(to_char_type(0xDF));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.object)
+                {
+                    write_msgpack(el.first);
+                    write_msgpack(el.second);
+                }
+                break;
+            }
+
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    @param[in] use_count   whether to use '#' prefixes (optimized format)
+    @param[in] use_type    whether to use '$' prefixes (optimized format)
+    @param[in] add_prefix  whether prefixes need to be used for this value
+    @param[in] use_bjdata  whether write in BJData format, default is false
+    */
+    void write_ubjson(const BasicJsonType& j, const bool use_count,
+                      const bool use_type, const bool add_prefix = true,
+                      const bool use_bjdata = false)
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('Z'));
+                }
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(j.m_value.boolean
+                                        ? to_char_type('T')
+                                        : to_char_type('F'));
+                }
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix, use_bjdata);
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix, use_bjdata);
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix, use_bjdata);
+                break;
+            }
+
+            case value_t::string:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('S'));
+                }
+                write_number_with_ubjson_prefix(j.m_value.string->size(), true, use_bjdata);
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
+                    j.m_value.string->size());
+                break;
+            }
+
+            case value_t::array:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('['));
+                }
+
+                bool prefix_required = true;
+                if (use_type && !j.m_value.array->empty())
+                {
+                    JSON_ASSERT(use_count);
+                    const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
+                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
+                                                         [this, first_prefix, use_bjdata](const BasicJsonType & v)
+                    {
+                        return ubjson_prefix(v, use_bjdata) == first_prefix;
+                    });
+
+                    std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
+
+                    if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
+                    {
+                        prefix_required = false;
+                        oa->write_character(to_char_type('$'));
+                        oa->write_character(first_prefix);
+                    }
+                }
+
+                if (use_count)
+                {
+                    oa->write_character(to_char_type('#'));
+                    write_number_with_ubjson_prefix(j.m_value.array->size(), true, use_bjdata);
+                }
+
+                for (const auto& el : *j.m_value.array)
+                {
+                    write_ubjson(el, use_count, use_type, prefix_required, use_bjdata);
+                }
+
+                if (!use_count)
+                {
+                    oa->write_character(to_char_type(']'));
+                }
+
+                break;
+            }
+
+            case value_t::binary:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('['));
+                }
+
+                if (use_type && !j.m_value.binary->empty())
+                {
+                    JSON_ASSERT(use_count);
+                    oa->write_character(to_char_type('$'));
+                    oa->write_character('U');
+                }
+
+                if (use_count)
+                {
+                    oa->write_character(to_char_type('#'));
+                    write_number_with_ubjson_prefix(j.m_value.binary->size(), true, use_bjdata);
+                }
+
+                if (use_type)
+                {
+                    oa->write_characters(
+                        reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+                        j.m_value.binary->size());
+                }
+                else
+                {
+                    for (size_t i = 0; i < j.m_value.binary->size(); ++i)
+                    {
+                        oa->write_character(to_char_type('U'));
+                        oa->write_character(j.m_value.binary->data()[i]);
+                    }
+                }
+
+                if (!use_count)
+                {
+                    oa->write_character(to_char_type(']'));
+                }
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                if (use_bjdata && j.m_value.object->size() == 3 && j.m_value.object->find("_ArrayType_") != j.m_value.object->end() && j.m_value.object->find("_ArraySize_") != j.m_value.object->end() && j.m_value.object->find("_ArrayData_") != j.m_value.object->end())
+                {
+                    if (!write_bjdata_ndarray(*j.m_value.object, use_count, use_type))  // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
+                    {
+                        break;
+                    }
+                }
+
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('{'));
+                }
+
+                bool prefix_required = true;
+                if (use_type && !j.m_value.object->empty())
+                {
+                    JSON_ASSERT(use_count);
+                    const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
+                    const bool same_prefix = std::all_of(j.begin(), j.end(),
+                                                         [this, first_prefix, use_bjdata](const BasicJsonType & v)
+                    {
+                        return ubjson_prefix(v, use_bjdata) == first_prefix;
+                    });
+
+                    std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
+
+                    if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
+                    {
+                        prefix_required = false;
+                        oa->write_character(to_char_type('$'));
+                        oa->write_character(first_prefix);
+                    }
+                }
+
+                if (use_count)
+                {
+                    oa->write_character(to_char_type('#'));
+                    write_number_with_ubjson_prefix(j.m_value.object->size(), true, use_bjdata);
+                }
+
+                for (const auto& el : *j.m_value.object)
+                {
+                    write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
+                    oa->write_characters(
+                        reinterpret_cast<const CharType*>(el.first.c_str()),
+                        el.first.size());
+                    write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata);
+                }
+
+                if (!use_count)
+                {
+                    oa->write_character(to_char_type('}'));
+                }
+
+                break;
+            }
+
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+  private:
+    //////////
+    // BSON //
+    //////////
+
+    /*!
+    @return The size of a BSON document entry header, including the id marker
+            and the entry name size (and its null-terminator).
+    */
+    static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)
+    {
+        const auto it = name.find(static_cast<typename string_t::value_type>(0));
+        if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
+        {
+            JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
+            static_cast<void>(j);
+        }
+
+        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
+    }
+
+    /*!
+    @brief Writes the given @a element_type and @a name to the output adapter
+    */
+    void write_bson_entry_header(const string_t& name,
+                                 const std::uint8_t element_type)
+    {
+        oa->write_character(to_char_type(element_type)); // boolean
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(name.c_str()),
+            name.size() + 1u);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and boolean value @a value
+    */
+    void write_bson_boolean(const string_t& name,
+                            const bool value)
+    {
+        write_bson_entry_header(name, 0x08);
+        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and double value @a value
+    */
+    void write_bson_double(const string_t& name,
+                           const double value)
+    {
+        write_bson_entry_header(name, 0x01);
+        write_number<double>(value, true);
+    }
+
+    /*!
+    @return The size of the BSON-encoded string in @a value
+    */
+    static std::size_t calc_bson_string_size(const string_t& value)
+    {
+        return sizeof(std::int32_t) + value.size() + 1ul;
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and string value @a value
+    */
+    void write_bson_string(const string_t& name,
+                           const string_t& value)
+    {
+        write_bson_entry_header(name, 0x02);
+
+        write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(value.c_str()),
+            value.size() + 1);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and null value
+    */
+    void write_bson_null(const string_t& name)
+    {
+        write_bson_entry_header(name, 0x0A);
+    }
+
+    /*!
+    @return The size of the BSON-encoded integer @a value
+    */
+    static std::size_t calc_bson_integer_size(const std::int64_t value)
+    {
+        return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
+               ? sizeof(std::int32_t)
+               : sizeof(std::int64_t);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and integer @a value
+    */
+    void write_bson_integer(const string_t& name,
+                            const std::int64_t value)
+    {
+        if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
+        {
+            write_bson_entry_header(name, 0x10); // int32
+            write_number<std::int32_t>(static_cast<std::int32_t>(value), true);
+        }
+        else
+        {
+            write_bson_entry_header(name, 0x12); // int64
+            write_number<std::int64_t>(static_cast<std::int64_t>(value), true);
+        }
+    }
+
+    /*!
+    @return The size of the BSON-encoded unsigned integer in @a j
+    */
+    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
+    {
+        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+               ? sizeof(std::int32_t)
+               : sizeof(std::int64_t);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and unsigned @a value
+    */
+    void write_bson_unsigned(const string_t& name,
+                             const BasicJsonType& j)
+    {
+        if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+        {
+            write_bson_entry_header(name, 0x10 /* int32 */);
+            write_number<std::int32_t>(static_cast<std::int32_t>(j.m_value.number_unsigned), true);
+        }
+        else if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+        {
+            write_bson_entry_header(name, 0x12 /* int64 */);
+            write_number<std::int64_t>(static_cast<std::int64_t>(j.m_value.number_unsigned), true);
+        }
+        else
+        {
+            JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
+        }
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and object @a value
+    */
+    void write_bson_object_entry(const string_t& name,
+                                 const typename BasicJsonType::object_t& value)
+    {
+        write_bson_entry_header(name, 0x03); // object
+        write_bson_object(value);
+    }
+
+    /*!
+    @return The size of the BSON-encoded array @a value
+    */
+    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
+    {
+        std::size_t array_index = 0ul;
+
+        const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
+        {
+            return result + calc_bson_element_size(std::to_string(array_index++), el);
+        });
+
+        return sizeof(std::int32_t) + embedded_document_size + 1ul;
+    }
+
+    /*!
+    @return The size of the BSON-encoded binary array @a value
+    */
+    static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
+    {
+        return sizeof(std::int32_t) + value.size() + 1ul;
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and array @a value
+    */
+    void write_bson_array(const string_t& name,
+                          const typename BasicJsonType::array_t& value)
+    {
+        write_bson_entry_header(name, 0x04); // array
+        write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);
+
+        std::size_t array_index = 0ul;
+
+        for (const auto& el : value)
+        {
+            write_bson_element(std::to_string(array_index++), el);
+        }
+
+        oa->write_character(to_char_type(0x00));
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and binary value @a value
+    */
+    void write_bson_binary(const string_t& name,
+                           const binary_t& value)
+    {
+        write_bson_entry_header(name, 0x05);
+
+        write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);
+        write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
+
+        oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
+    }
+
+    /*!
+    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
+    @return The calculated size for the BSON document entry for @a j with the given @a name.
+    */
+    static std::size_t calc_bson_element_size(const string_t& name,
+            const BasicJsonType& j)
+    {
+        const auto header_size = calc_bson_entry_header_size(name, j);
+        switch (j.type())
+        {
+            case value_t::object:
+                return header_size + calc_bson_object_size(*j.m_value.object);
+
+            case value_t::array:
+                return header_size + calc_bson_array_size(*j.m_value.array);
+
+            case value_t::binary:
+                return header_size + calc_bson_binary_size(*j.m_value.binary);
+
+            case value_t::boolean:
+                return header_size + 1ul;
+
+            case value_t::number_float:
+                return header_size + 8ul;
+
+            case value_t::number_integer:
+                return header_size + calc_bson_integer_size(j.m_value.number_integer);
+
+            case value_t::number_unsigned:
+                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
+
+            case value_t::string:
+                return header_size + calc_bson_string_size(*j.m_value.string);
+
+            case value_t::null:
+                return header_size + 0ul;
+
+            // LCOV_EXCL_START
+            case value_t::discarded:
+            default:
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
+                return 0ul;
+                // LCOV_EXCL_STOP
+        }
+    }
+
+    /*!
+    @brief Serializes the JSON value @a j to BSON and associates it with the
+           key @a name.
+    @param name The name to associate with the JSON entity @a j within the
+                current BSON document
+    */
+    void write_bson_element(const string_t& name,
+                            const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::object:
+                return write_bson_object_entry(name, *j.m_value.object);
+
+            case value_t::array:
+                return write_bson_array(name, *j.m_value.array);
+
+            case value_t::binary:
+                return write_bson_binary(name, *j.m_value.binary);
+
+            case value_t::boolean:
+                return write_bson_boolean(name, j.m_value.boolean);
+
+            case value_t::number_float:
+                return write_bson_double(name, j.m_value.number_float);
+
+            case value_t::number_integer:
+                return write_bson_integer(name, j.m_value.number_integer);
+
+            case value_t::number_unsigned:
+                return write_bson_unsigned(name, j);
+
+            case value_t::string:
+                return write_bson_string(name, *j.m_value.string);
+
+            case value_t::null:
+                return write_bson_null(name);
+
+            // LCOV_EXCL_START
+            case value_t::discarded:
+            default:
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
+                return;
+                // LCOV_EXCL_STOP
+        }
+    }
+
+    /*!
+    @brief Calculates the size of the BSON serialization of the given
+           JSON-object @a j.
+    @param[in] value  JSON value to serialize
+    @pre       value.type() == value_t::object
+    */
+    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
+    {
+        std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
+                                    [](size_t result, const typename BasicJsonType::object_t::value_type & el)
+        {
+            return result += calc_bson_element_size(el.first, el.second);
+        });
+
+        return sizeof(std::int32_t) + document_size + 1ul;
+    }
+
+    /*!
+    @param[in] value  JSON value to serialize
+    @pre       value.type() == value_t::object
+    */
+    void write_bson_object(const typename BasicJsonType::object_t& value)
+    {
+        write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true);
+
+        for (const auto& el : value)
+        {
+            write_bson_element(el.first, el.second);
+        }
+
+        oa->write_character(to_char_type(0x00));
+    }
+
+    //////////
+    // CBOR //
+    //////////
+
+    static constexpr CharType get_cbor_float_prefix(float /*unused*/)
+    {
+        return to_char_type(0xFA);  // Single-Precision Float
+    }
+
+    static constexpr CharType get_cbor_float_prefix(double /*unused*/)
+    {
+        return to_char_type(0xFB);  // Double-Precision Float
+    }
+
+    /////////////
+    // MsgPack //
+    /////////////
+
+    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
+    {
+        return to_char_type(0xCA);  // float 32
+    }
+
+    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
+    {
+        return to_char_type(0xCB);  // float 64
+    }
+
+    ////////////
+    // UBJSON //
+    ////////////
+
+    // UBJSON: write number (floating point)
+    template<typename NumberType, typename std::enable_if<
+                 std::is_floating_point<NumberType>::value, int>::type = 0>
+    void write_number_with_ubjson_prefix(const NumberType n,
+                                         const bool add_prefix,
+                                         const bool use_bjdata)
+    {
+        if (add_prefix)
+        {
+            oa->write_character(get_ubjson_float_prefix(n));
+        }
+        write_number(n, use_bjdata);
+    }
+
+    // UBJSON: write number (unsigned integer)
+    template<typename NumberType, typename std::enable_if<
+                 std::is_unsigned<NumberType>::value, int>::type = 0>
+    void write_number_with_ubjson_prefix(const NumberType n,
+                                         const bool add_prefix,
+                                         const bool use_bjdata)
+    {
+        if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('i'));  // int8
+            }
+            write_number(static_cast<std::uint8_t>(n), use_bjdata);
+        }
+        else if (n <= (std::numeric_limits<std::uint8_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('U'));  // uint8
+            }
+            write_number(static_cast<std::uint8_t>(n), use_bjdata);
+        }
+        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('I'));  // int16
+            }
+            write_number(static_cast<std::int16_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('u'));  // uint16 - bjdata only
+            }
+            write_number(static_cast<std::uint16_t>(n), use_bjdata);
+        }
+        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('l'));  // int32
+            }
+            write_number(static_cast<std::int32_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('m'));  // uint32 - bjdata only
+            }
+            write_number(static_cast<std::uint32_t>(n), use_bjdata);
+        }
+        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('L'));  // int64
+            }
+            write_number(static_cast<std::int64_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('M'));  // uint64 - bjdata only
+            }
+            write_number(static_cast<std::uint64_t>(n), use_bjdata);
+        }
+        else
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('H'));  // high-precision number
+            }
+
+            const auto number = BasicJsonType(n).dump();
+            write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
+            for (std::size_t i = 0; i < number.size(); ++i)
+            {
+                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
+            }
+        }
+    }
+
+    // UBJSON: write number (signed integer)
+    template < typename NumberType, typename std::enable_if <
+                   std::is_signed<NumberType>::value&&
+                   !std::is_floating_point<NumberType>::value, int >::type = 0 >
+    void write_number_with_ubjson_prefix(const NumberType n,
+                                         const bool add_prefix,
+                                         const bool use_bjdata)
+    {
+        if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('i'));  // int8
+            }
+            write_number(static_cast<std::int8_t>(n), use_bjdata);
+        }
+        else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('U'));  // uint8
+            }
+            write_number(static_cast<std::uint8_t>(n), use_bjdata);
+        }
+        else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('I'));  // int16
+            }
+            write_number(static_cast<std::int16_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)())))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('u'));  // uint16 - bjdata only
+            }
+            write_number(static_cast<uint16_t>(n), use_bjdata);
+        }
+        else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('l'));  // int32
+            }
+            write_number(static_cast<std::int32_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)())))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('m'));  // uint32 - bjdata only
+            }
+            write_number(static_cast<uint32_t>(n), use_bjdata);
+        }
+        else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('L'));  // int64
+            }
+            write_number(static_cast<std::int64_t>(n), use_bjdata);
+        }
+        // LCOV_EXCL_START
+        else
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('H'));  // high-precision number
+            }
+
+            const auto number = BasicJsonType(n).dump();
+            write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
+            for (std::size_t i = 0; i < number.size(); ++i)
+            {
+                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
+            }
+        }
+        // LCOV_EXCL_STOP
+    }
+
+    /*!
+    @brief determine the type prefix of container values
+    */
+    CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+                return 'Z';
+
+            case value_t::boolean:
+                return j.m_value.boolean ? 'T' : 'F';
+
+            case value_t::number_integer:
+            {
+                if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+                {
+                    return 'i';
+                }
+                if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    return 'U';
+                }
+                if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+                {
+                    return 'I';
+                }
+                if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
+                {
+                    return 'u';
+                }
+                if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+                {
+                    return 'l';
+                }
+                if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
+                {
+                    return 'm';
+                }
+                if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+                {
+                    return 'L';
+                }
+                // anything else is treated as high-precision number
+                return 'H'; // LCOV_EXCL_LINE
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
+                {
+                    return 'i';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
+                {
+                    return 'U';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
+                {
+                    return 'I';
+                }
+                if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
+                {
+                    return 'u';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+                {
+                    return 'l';
+                }
+                if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
+                {
+                    return 'm';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+                {
+                    return 'L';
+                }
+                if (use_bjdata && j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    return 'M';
+                }
+                // anything else is treated as high-precision number
+                return 'H'; // LCOV_EXCL_LINE
+            }
+
+            case value_t::number_float:
+                return get_ubjson_float_prefix(j.m_value.number_float);
+
+            case value_t::string:
+                return 'S';
+
+            case value_t::array: // fallthrough
+            case value_t::binary:
+                return '[';
+
+            case value_t::object:
+                return '{';
+
+            case value_t::discarded:
+            default:  // discarded values
+                return 'N';
+        }
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
+    {
+        return 'd';  // float 32
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
+    {
+        return 'D';  // float 64
+    }
+
+    /*!
+    @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid
+    */
+    bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type)
+    {
+        std::map<string_t, CharType> bjdtype = {{"uint8", 'U'},  {"int8", 'i'},  {"uint16", 'u'}, {"int16", 'I'},
+            {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'}
+        };
+
+        string_t key = "_ArrayType_";
+        auto it = bjdtype.find(static_cast<string_t>(value.at(key)));
+        if (it == bjdtype.end())
+        {
+            return true;
+        }
+        CharType dtype = it->second;
+
+        key = "_ArraySize_";
+        std::size_t len = (value.at(key).empty() ? 0 : 1);
+        for (const auto& el : value.at(key))
+        {
+            len *= static_cast<std::size_t>(el.m_value.number_unsigned);
+        }
+
+        key = "_ArrayData_";
+        if (value.at(key).size() != len)
+        {
+            return true;
+        }
+
+        oa->write_character('[');
+        oa->write_character('$');
+        oa->write_character(dtype);
+        oa->write_character('#');
+
+        key = "_ArraySize_";
+        write_ubjson(value.at(key), use_count, use_type, true,  true);
+
+        key = "_ArrayData_";
+        if (dtype == 'U' || dtype == 'C')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint8_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'i')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int8_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'u')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint16_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'I')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int16_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'm')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint32_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'l')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int32_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'M')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint64_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'L')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int64_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'd')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<float>(el.m_value.number_float), true);
+            }
+        }
+        else if (dtype == 'D')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<double>(el.m_value.number_float), true);
+            }
+        }
+        return false;
+    }
+
+    ///////////////////////
+    // Utility functions //
+    ///////////////////////
+
+    /*
+    @brief write a number to output input
+    @param[in] n number of type @a NumberType
+    @param[in] OutputIsLittleEndian Set to true if output data is
+                                 required to be little endian
+    @tparam NumberType the type of the number
+
+    @note This function needs to respect the system's endianness, because bytes
+          in CBOR, MessagePack, and UBJSON are stored in network order (big
+          endian) and therefore need reordering on little endian systems.
+          On the other hand, BSON and BJData use little endian and should reorder
+          on big endian systems.
+    */
+    template<typename NumberType>
+    void write_number(const NumberType n, const bool OutputIsLittleEndian = false)
+    {
+        // step 1: write number to array of length NumberType
+        std::array<CharType, sizeof(NumberType)> vec{};
+        std::memcpy(vec.data(), &n, sizeof(NumberType));
+
+        // step 2: write array to output (with possible reordering)
+        if (is_little_endian != OutputIsLittleEndian)
+        {
+            // reverse byte order prior to conversion if necessary
+            std::reverse(vec.begin(), vec.end());
+        }
+
+        oa->write_characters(vec.data(), sizeof(NumberType));
+    }
+
+    void write_compact_float(const number_float_t n, detail::input_format_t format)
+    {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+        if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
+                static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
+                static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
+        {
+            oa->write_character(format == detail::input_format_t::cbor
+                                ? get_cbor_float_prefix(static_cast<float>(n))
+                                : get_msgpack_float_prefix(static_cast<float>(n)));
+            write_number(static_cast<float>(n));
+        }
+        else
+        {
+            oa->write_character(format == detail::input_format_t::cbor
+                                ? get_cbor_float_prefix(n)
+                                : get_msgpack_float_prefix(n));
+            write_number(n);
+        }
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+    }
+
+  public:
+    // The following to_char_type functions are implement the conversion
+    // between uint8_t and CharType. In case CharType is not unsigned,
+    // such a conversion is required to allow values greater than 128.
+    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
+    template < typename C = CharType,
+               enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
+    static constexpr CharType to_char_type(std::uint8_t x) noexcept
+    {
+        return *reinterpret_cast<char*>(&x);
+    }
+
+    template < typename C = CharType,
+               enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
+    static CharType to_char_type(std::uint8_t x) noexcept
+    {
+        static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
+        static_assert(std::is_trivial<CharType>::value, "CharType must be trivial");
+        CharType result;
+        std::memcpy(&result, &x, sizeof(x));
+        return result;
+    }
+
+    template<typename C = CharType,
+             enable_if_t<std::is_unsigned<C>::value>* = nullptr>
+    static constexpr CharType to_char_type(std::uint8_t x) noexcept
+    {
+        return x;
+    }
+
+    template < typename InputCharType, typename C = CharType,
+               enable_if_t <
+                   std::is_signed<C>::value &&
+                   std::is_signed<char>::value &&
+                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
+                   > * = nullptr >
+    static constexpr CharType to_char_type(InputCharType x) noexcept
+    {
+        return x;
+    }
+
+  private:
+    /// whether we can assume little endianness
+    const bool is_little_endian = little_endianness();
+
+    /// the output
+    output_adapter_t<CharType> oa = nullptr;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/output_adapters.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/output_adapters.h
new file mode 100644
index 0000000..06cbeb1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/output_adapters.h
@@ -0,0 +1,173 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // copy
+#include <cstddef> // size_t
+#include <iterator> // back_inserter
+#include <memory> // shared_ptr, make_shared
+#include <string> // basic_string
+#include <vector> // vector
+
+#ifndef JSON_NO_IO
+    #include <ios>      // streamsize
+    #include <ostream>  // basic_ostream
+#endif  // JSON_NO_IO
+
+#include <wpi/detail/macro_scope.h>
+
+#include <wpi/raw_ostream.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// abstract output adapter interface
+template<typename CharType> struct output_adapter_protocol
+{
+    virtual void write_character(CharType c) = 0;
+    virtual void write_characters(const CharType* s, std::size_t length) = 0;
+    virtual ~output_adapter_protocol() = default;
+
+    output_adapter_protocol() = default;
+    output_adapter_protocol(const output_adapter_protocol&) = default;
+    output_adapter_protocol(output_adapter_protocol&&) noexcept = default;
+    output_adapter_protocol& operator=(const output_adapter_protocol&) = default;
+    output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;
+};
+
+/// a type to simplify interfaces
+template<typename CharType>
+using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
+
+/// output adapter for byte vectors
+template<typename CharType, typename AllocatorType = std::allocator<CharType>>
+class output_vector_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept
+        : v(vec)
+    {}
+
+    void write_character(CharType c) override
+    {
+        v.push_back(c);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override
+    {
+        v.insert(v.end(), s, s + length);
+    }
+
+  private:
+    std::vector<CharType, AllocatorType>& v;
+};
+
+#ifndef JSON_NO_IO
+/// output adapter for output streams
+template<typename CharType>
+class output_stream_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
+        : stream(s)
+    {}
+
+    void write_character(CharType c) override
+    {
+        stream.put(c);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override
+    {
+        stream.write(s, static_cast<std::streamsize>(length));
+    }
+
+  private:
+    std::basic_ostream<CharType>& stream;
+};
+#endif  // JSON_NO_IO
+
+/// output adapter for basic_string
+template<typename CharType, typename StringType = std::basic_string<CharType>>
+class output_string_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit output_string_adapter(StringType& s) noexcept
+        : str(s)
+    {}
+
+    void write_character(CharType c) override
+    {
+        str.push_back(c);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override
+    {
+        str.append(s, length);
+    }
+
+  private:
+    StringType& str;
+};
+
+template<typename CharType>
+class raw_ostream_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit raw_ostream_adapter(raw_ostream& s) noexcept
+        : os(s) {}
+
+
+    void write_character(CharType c) override {
+        os << c;
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override {
+        os.write(s, length);
+    }
+
+  private:
+    raw_ostream& os;
+};
+
+template<typename CharType, typename StringType = std::basic_string<CharType>>
+class output_adapter
+{
+  public:
+    template<typename AllocatorType = std::allocator<CharType>>
+    output_adapter(std::vector<CharType, AllocatorType>& vec)
+        : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}
+
+#ifndef JSON_NO_IO
+    output_adapter(std::basic_ostream<CharType>& s)
+        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
+#endif  // JSON_NO_IO
+
+    output_adapter(StringType& s)
+        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
+
+    output_adapter(raw_ostream& os)
+        : oa(std::make_shared<raw_ostream_adapter<CharType>>(os)) {}
+
+    operator output_adapter_t<CharType>()
+    {
+        return oa;
+    }
+
+  private:
+    output_adapter_t<CharType> oa = nullptr;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/serializer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/serializer.h
new file mode 100644
index 0000000..4d137a3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/output/serializer.h
@@ -0,0 +1,997 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <algorithm> // reverse, remove, fill, find, none_of
+#include <array> // array
+#include <clocale> // localeconv, lconv
+#include <cmath> // labs, isfinite, isnan, signbit
+#include <cstddef> // size_t, ptrdiff_t
+#include <cstdint> // uint8_t
+#include <cstdio> // snprintf
+#include <limits> // numeric_limits
+#include <string> // string, char_traits
+#include <iomanip> // setfill, setw
+#include <type_traits> // is_same
+#include <utility> // move
+
+#include <wpi/detail/conversions/to_chars.h>
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/output/binary_writer.h>
+#include <wpi/detail/output/output_adapters.h>
+#include <wpi/detail/string_concat.h>
+#include <wpi/detail/value_t.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////
+// serialization //
+///////////////////
+
+/// how to treat decoding errors
+enum class error_handler_t
+{
+    strict,  ///< throw a type_error exception in case of invalid UTF-8
+    replace, ///< replace invalid UTF-8 sequences with U+FFFD
+    ignore   ///< ignore invalid UTF-8 sequences
+};
+
+template<typename BasicJsonType>
+class serializer
+{
+    using string_t = typename BasicJsonType::string_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using binary_char_t = typename BasicJsonType::binary_t::value_type;
+    static constexpr std::uint8_t UTF8_ACCEPT = 0;
+    static constexpr std::uint8_t UTF8_REJECT = 1;
+
+  public:
+    /*!
+    @param[in] s  output stream to serialize to
+    @param[in] ichar  indentation character to use
+    @param[in] error_handler_  how to react on decoding errors
+    */
+    serializer(output_adapter_t<char> s, const char ichar,
+               error_handler_t error_handler_ = error_handler_t::strict,
+               size_t indent_init_len = 512)
+        : o(std::move(s))
+        , loc(std::localeconv())
+        , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
+        , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
+        , indent_char(ichar)
+        , indent_string(indent_init_len, indent_char)
+        , error_handler(error_handler_)
+    {}
+    
+    serializer(raw_ostream& os, const char ichar,
+               size_t indent_init_len = 512,
+               error_handler_t error_handler_ = error_handler_t::strict)
+        : serializer(output_adapter<char>(os), ichar, error_handler_, indent_init_len)
+    {}
+
+    // delete because of pointer members
+    serializer(const serializer&) = delete;
+    serializer& operator=(const serializer&) = delete;
+    serializer(serializer&&) = delete;
+    serializer& operator=(serializer&&) = delete;
+    ~serializer() = default;
+
+    /*!
+    @brief internal implementation of the serialization function
+
+    This function is called by the public member function dump and organizes
+    the serialization internally. The indentation level is propagated as
+    additional parameter. In case of arrays and objects, the function is
+    called recursively.
+
+    - strings and object keys are escaped using `escape_string()`
+    - integer numbers are converted implicitly via `operator<<`
+    - floating-point numbers are converted to a string using `"%g"` format
+    - binary values are serialized as objects containing the subtype and the
+      byte array
+
+    @param[in] val               value to serialize
+    @param[in] pretty_print      whether the output shall be pretty-printed
+    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
+    in the output are escaped with `\uXXXX` sequences, and the result consists
+    of ASCII characters only.
+    @param[in] indent_step       the indent level
+    @param[in] current_indent    the current indent level (only used internally)
+    */
+    void dump(const BasicJsonType& val,
+              const bool pretty_print,
+              const bool ensure_ascii,
+              const unsigned int indent_step,
+              const unsigned int current_indent = 0)
+    {
+        switch (val.m_type)
+        {
+            case value_t::object:
+            {
+                if (val.m_value.object->empty())
+                {
+                    o->write_characters("{}", 2);
+                    return;
+                }
+
+                if (pretty_print)
+                {
+                    o->write_characters("{\n", 2);
+
+                    // variable to hold indentation for recursive calls
+                    const auto new_indent = current_indent + indent_step;
+                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
+                    {
+                        indent_string.resize(indent_string.size() * 2, ' ');
+                    }
+
+                    // first n-1 elements
+                    auto i = val.m_value.object->cbegin();
+                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
+                    {
+                        o->write_characters(indent_string.c_str(), new_indent);
+                        o->write_character('\"');
+                        dump_escaped(i->first, ensure_ascii);
+                        o->write_characters("\": ", 3);
+                        dump(i->second, true, ensure_ascii, indent_step, new_indent);
+                        o->write_characters(",\n", 2);
+                    }
+
+                    // last element
+                    JSON_ASSERT(i != val.m_value.object->cend());
+                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());
+                    o->write_characters(indent_string.c_str(), new_indent);
+                    o->write_character('\"');
+                    dump_escaped(i->first, ensure_ascii);
+                    o->write_characters("\": ", 3);
+                    dump(i->second, true, ensure_ascii, indent_step, new_indent);
+
+                    o->write_character('\n');
+                    o->write_characters(indent_string.c_str(), current_indent);
+                    o->write_character('}');
+                }
+                else
+                {
+                    o->write_character('{');
+
+                    // first n-1 elements
+                    auto i = val.m_value.object->cbegin();
+                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
+                    {
+                        o->write_character('\"');
+                        dump_escaped(i->first, ensure_ascii);
+                        o->write_characters("\":", 2);
+                        dump(i->second, false, ensure_ascii, indent_step, current_indent);
+                        o->write_character(',');
+                    }
+
+                    // last element
+                    JSON_ASSERT(i != val.m_value.object->cend());
+                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());
+                    o->write_character('\"');
+                    dump_escaped(i->first, ensure_ascii);
+                    o->write_characters("\":", 2);
+                    dump(i->second, false, ensure_ascii, indent_step, current_indent);
+
+                    o->write_character('}');
+                }
+
+                return;
+            }
+
+            case value_t::array:
+            {
+                if (val.m_value.array->empty())
+                {
+                    o->write_characters("[]", 2);
+                    return;
+                }
+
+                if (pretty_print)
+                {
+                    o->write_characters("[\n", 2);
+
+                    // variable to hold indentation for recursive calls
+                    const auto new_indent = current_indent + indent_step;
+                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
+                    {
+                        indent_string.resize(indent_string.size() * 2, ' ');
+                    }
+
+                    // first n-1 elements
+                    for (auto i = val.m_value.array->cbegin();
+                            i != val.m_value.array->cend() - 1; ++i)
+                    {
+                        o->write_characters(indent_string.c_str(), new_indent);
+                        dump(*i, true, ensure_ascii, indent_step, new_indent);
+                        o->write_characters(",\n", 2);
+                    }
+
+                    // last element
+                    JSON_ASSERT(!val.m_value.array->empty());
+                    o->write_characters(indent_string.c_str(), new_indent);
+                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
+
+                    o->write_character('\n');
+                    o->write_characters(indent_string.c_str(), current_indent);
+                    o->write_character(']');
+                }
+                else
+                {
+                    o->write_character('[');
+
+                    // first n-1 elements
+                    for (auto i = val.m_value.array->cbegin();
+                            i != val.m_value.array->cend() - 1; ++i)
+                    {
+                        dump(*i, false, ensure_ascii, indent_step, current_indent);
+                        o->write_character(',');
+                    }
+
+                    // last element
+                    JSON_ASSERT(!val.m_value.array->empty());
+                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
+
+                    o->write_character(']');
+                }
+
+                return;
+            }
+
+            case value_t::string:
+            {
+                o->write_character('\"');
+                dump_escaped(*val.m_value.string, ensure_ascii);
+                o->write_character('\"');
+                return;
+            }
+
+            case value_t::binary:
+            {
+                if (pretty_print)
+                {
+                    o->write_characters("{\n", 2);
+
+                    // variable to hold indentation for recursive calls
+                    const auto new_indent = current_indent + indent_step;
+                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
+                    {
+                        indent_string.resize(indent_string.size() * 2, ' ');
+                    }
+
+                    o->write_characters(indent_string.c_str(), new_indent);
+
+                    o->write_characters("\"bytes\": [", 10);
+
+                    if (!val.m_value.binary->empty())
+                    {
+                        for (auto i = val.m_value.binary->cbegin();
+                                i != val.m_value.binary->cend() - 1; ++i)
+                        {
+                            dump_integer(*i);
+                            o->write_characters(", ", 2);
+                        }
+                        dump_integer(val.m_value.binary->back());
+                    }
+
+                    o->write_characters("],\n", 3);
+                    o->write_characters(indent_string.c_str(), new_indent);
+
+                    o->write_characters("\"subtype\": ", 11);
+                    if (val.m_value.binary->has_subtype())
+                    {
+                        dump_integer(val.m_value.binary->subtype());
+                    }
+                    else
+                    {
+                        o->write_characters("null", 4);
+                    }
+                    o->write_character('\n');
+                    o->write_characters(indent_string.c_str(), current_indent);
+                    o->write_character('}');
+                }
+                else
+                {
+                    o->write_characters("{\"bytes\":[", 10);
+
+                    if (!val.m_value.binary->empty())
+                    {
+                        for (auto i = val.m_value.binary->cbegin();
+                                i != val.m_value.binary->cend() - 1; ++i)
+                        {
+                            dump_integer(*i);
+                            o->write_character(',');
+                        }
+                        dump_integer(val.m_value.binary->back());
+                    }
+
+                    o->write_characters("],\"subtype\":", 12);
+                    if (val.m_value.binary->has_subtype())
+                    {
+                        dump_integer(val.m_value.binary->subtype());
+                        o->write_character('}');
+                    }
+                    else
+                    {
+                        o->write_characters("null}", 5);
+                    }
+                }
+                return;
+            }
+
+            case value_t::boolean:
+            {
+                if (val.m_value.boolean)
+                {
+                    o->write_characters("true", 4);
+                }
+                else
+                {
+                    o->write_characters("false", 5);
+                }
+                return;
+            }
+
+            case value_t::number_integer:
+            {
+                dump_integer(val.m_value.number_integer);
+                return;
+            }
+
+            case value_t::number_unsigned:
+            {
+                dump_integer(val.m_value.number_unsigned);
+                return;
+            }
+
+            case value_t::number_float:
+            {
+                dump_float(val.m_value.number_float);
+                return;
+            }
+
+            case value_t::discarded:
+            {
+                o->write_characters("<discarded>", 11);
+                return;
+            }
+
+            case value_t::null:
+            {
+                o->write_characters("null", 4);
+                return;
+            }
+
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+    }
+
+  public:
+    /*!
+    @brief dump escaped string
+
+    Escape a string by replacing certain special characters by a sequence of an
+    escape character (backslash) and another character and other control
+    characters by a sequence of "\u" followed by a four-digit hex
+    representation. The escaped string is written to output stream @a o.
+
+    @param[in] s  the string to escape
+    @param[in] ensure_ascii  whether to escape non-ASCII characters with
+                             \uXXXX sequences
+
+    @complexity Linear in the length of string @a s.
+    */
+    void dump_escaped(std::string_view s, const bool ensure_ascii)
+    {
+        std::uint32_t codepoint{};
+        std::uint8_t state = UTF8_ACCEPT;
+        std::size_t bytes = 0;  // number of bytes written to string_buffer
+
+        // number of bytes written at the point of the last valid byte
+        std::size_t bytes_after_last_accept = 0;
+        std::size_t undumped_chars = 0;
+
+        for (std::size_t i = 0; i < s.size(); ++i)
+        {
+            const auto byte = static_cast<std::uint8_t>(s[i]);
+
+            switch (decode(state, codepoint, byte))
+            {
+                case UTF8_ACCEPT:  // decode found a new code point
+                {
+                    switch (codepoint)
+                    {
+                        case 0x08: // backspace
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'b';
+                            break;
+                        }
+
+                        case 0x09: // horizontal tab
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 't';
+                            break;
+                        }
+
+                        case 0x0A: // newline
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'n';
+                            break;
+                        }
+
+                        case 0x0C: // formfeed
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'f';
+                            break;
+                        }
+
+                        case 0x0D: // carriage return
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'r';
+                            break;
+                        }
+
+                        case 0x22: // quotation mark
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = '\"';
+                            break;
+                        }
+
+                        case 0x5C: // reverse solidus
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = '\\';
+                            break;
+                        }
+
+                        default:
+                        {
+                            // escape control characters (0x00..0x1F) or, if
+                            // ensure_ascii parameter is used, non-ASCII characters
+                            if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
+                            {
+                                if (codepoint <= 0xFFFF)
+                                {
+                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                                    static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
+                                                                      static_cast<std::uint16_t>(codepoint)));
+                                    bytes += 6;
+                                }
+                                else
+                                {
+                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                                    static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
+                                                                      static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
+                                                                      static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
+                                    bytes += 12;
+                                }
+                            }
+                            else
+                            {
+                                // copy byte to buffer (all previous bytes
+                                // been copied have in default case above)
+                                string_buffer[bytes++] = s[i];
+                            }
+                            break;
+                        }
+                    }
+
+                    // write buffer and reset index; there must be 13 bytes
+                    // left, as this is the maximal number of bytes to be
+                    // written ("\uxxxx\uxxxx\0") for one code point
+                    if (string_buffer.size() - bytes < 13)
+                    {
+                        o->write_characters(string_buffer.data(), bytes);
+                        bytes = 0;
+                    }
+
+                    // remember the byte position of this accept
+                    bytes_after_last_accept = bytes;
+                    undumped_chars = 0;
+                    break;
+                }
+
+                case UTF8_REJECT:  // decode found invalid UTF-8 byte
+                {
+                    switch (error_handler)
+                    {
+                        case error_handler_t::strict:
+                        {
+                            JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr));
+                        }
+
+                        case error_handler_t::ignore:
+                        case error_handler_t::replace:
+                        {
+                            // in case we saw this character the first time, we
+                            // would like to read it again, because the byte
+                            // may be OK for itself, but just not OK for the
+                            // previous sequence
+                            if (undumped_chars > 0)
+                            {
+                                --i;
+                            }
+
+                            // reset length buffer to the last accepted index;
+                            // thus removing/ignoring the invalid characters
+                            bytes = bytes_after_last_accept;
+
+                            if (error_handler == error_handler_t::replace)
+                            {
+                                // add a replacement character
+                                if (ensure_ascii)
+                                {
+                                    string_buffer[bytes++] = '\\';
+                                    string_buffer[bytes++] = 'u';
+                                    string_buffer[bytes++] = 'f';
+                                    string_buffer[bytes++] = 'f';
+                                    string_buffer[bytes++] = 'f';
+                                    string_buffer[bytes++] = 'd';
+                                }
+                                else
+                                {
+                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
+                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
+                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
+                                }
+
+                                // write buffer and reset index; there must be 13 bytes
+                                // left, as this is the maximal number of bytes to be
+                                // written ("\uxxxx\uxxxx\0") for one code point
+                                if (string_buffer.size() - bytes < 13)
+                                {
+                                    o->write_characters(string_buffer.data(), bytes);
+                                    bytes = 0;
+                                }
+
+                                bytes_after_last_accept = bytes;
+                            }
+
+                            undumped_chars = 0;
+
+                            // continue processing the string
+                            state = UTF8_ACCEPT;
+                            break;
+                        }
+
+                        default:            // LCOV_EXCL_LINE
+                            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+                    }
+                    break;
+                }
+
+                default:  // decode found yet incomplete multi-byte code point
+                {
+                    if (!ensure_ascii)
+                    {
+                        // code point will not be escaped - copy byte to buffer
+                        string_buffer[bytes++] = s[i];
+                    }
+                    ++undumped_chars;
+                    break;
+                }
+            }
+        }
+
+        // we finished processing the string
+        if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
+        {
+            // write buffer
+            if (bytes > 0)
+            {
+                o->write_characters(string_buffer.data(), bytes);
+            }
+        }
+        else
+        {
+            // we finish reading, but do not accept: string was incomplete
+            switch (error_handler)
+            {
+                case error_handler_t::strict:
+                {
+                    JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));
+                }
+
+                case error_handler_t::ignore:
+                {
+                    // write all accepted bytes
+                    o->write_characters(string_buffer.data(), bytes_after_last_accept);
+                    break;
+                }
+
+                case error_handler_t::replace:
+                {
+                    // write all accepted bytes
+                    o->write_characters(string_buffer.data(), bytes_after_last_accept);
+                    // add a replacement character
+                    if (ensure_ascii)
+                    {
+                        o->write_characters("\\ufffd", 6);
+                    }
+                    else
+                    {
+                        o->write_characters("\xEF\xBF\xBD", 3);
+                    }
+                    break;
+                }
+
+                default:            // LCOV_EXCL_LINE
+                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+            }
+        }
+    }
+
+  private:
+    /*!
+    @brief count digits
+
+    Count the number of decimal (base 10) digits for an input unsigned integer.
+
+    @param[in] x  unsigned integer number to count its digits
+    @return    number of decimal digits
+    */
+    inline unsigned int count_digits(number_unsigned_t x) noexcept
+    {
+        unsigned int n_digits = 1;
+        for (;;)
+        {
+            if (x < 10)
+            {
+                return n_digits;
+            }
+            if (x < 100)
+            {
+                return n_digits + 1;
+            }
+            if (x < 1000)
+            {
+                return n_digits + 2;
+            }
+            if (x < 10000)
+            {
+                return n_digits + 3;
+            }
+            x = x / 10000u;
+            n_digits += 4;
+        }
+    }
+
+    /*!
+     * @brief convert a byte to a uppercase hex representation
+     * @param[in] byte byte to represent
+     * @return representation ("00".."FF")
+     */
+    static std::string hex_bytes(std::uint8_t byte)
+    {
+        std::string result = "FF";
+        constexpr const char* nibble_to_hex = "0123456789ABCDEF";
+        result[0] = nibble_to_hex[byte / 16];
+        result[1] = nibble_to_hex[byte % 16];
+        return result;
+    }
+
+    // templates to avoid warnings about useless casts
+    template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
+    bool is_negative_number(NumberType x)
+    {
+        return x < 0;
+    }
+
+    template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
+    bool is_negative_number(NumberType /*unused*/)
+    {
+        return false;
+    }
+
+  public:
+    /*!
+    @brief dump an integer
+
+    Dump a given integer to output stream @a o. Works internally with
+    @a number_buffer.
+
+    @param[in] x  integer number (signed or unsigned) to dump
+    @tparam NumberType either @a number_integer_t or @a number_unsigned_t
+    */
+    template < typename NumberType, detail::enable_if_t <
+                   std::is_integral<NumberType>::value ||
+                   std::is_same<NumberType, number_unsigned_t>::value ||
+                   std::is_same<NumberType, number_integer_t>::value ||
+                   std::is_same<NumberType, binary_char_t>::value,
+                   int > = 0 >
+    void dump_integer(NumberType x)
+    {
+        static constexpr std::array<std::array<char, 2>, 100> digits_to_99
+        {
+            {
+                {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
+                {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
+                {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
+                {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
+                {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
+                {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
+                {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
+                {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
+                {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
+                {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
+            }
+        };
+
+        // special case for "0"
+        if (x == 0)
+        {
+            o->write_character('0');
+            return;
+        }
+
+        // use a pointer to fill the buffer
+        auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+
+        number_unsigned_t abs_value;
+
+        unsigned int n_chars{};
+
+        if (is_negative_number(x))
+        {
+            *buffer_ptr = '-';
+            abs_value = remove_sign(static_cast<number_integer_t>(x));
+
+            // account one more byte for the minus sign
+            n_chars = 1 + count_digits(abs_value);
+        }
+        else
+        {
+            abs_value = static_cast<number_unsigned_t>(x);
+            n_chars = count_digits(abs_value);
+        }
+
+        // spare 1 byte for '\0'
+        JSON_ASSERT(n_chars < number_buffer.size() - 1);
+
+        // jump to the end to generate the string from backward,
+        // so we later avoid reversing the result
+        buffer_ptr += n_chars;
+
+        // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
+        // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
+        while (abs_value >= 100)
+        {
+            const auto digits_index = static_cast<unsigned>((abs_value % 100));
+            abs_value /= 100;
+            *(--buffer_ptr) = digits_to_99[digits_index][1];
+            *(--buffer_ptr) = digits_to_99[digits_index][0];
+        }
+
+        if (abs_value >= 10)
+        {
+            const auto digits_index = static_cast<unsigned>(abs_value);
+            *(--buffer_ptr) = digits_to_99[digits_index][1];
+            *(--buffer_ptr) = digits_to_99[digits_index][0];
+        }
+        else
+        {
+            *(--buffer_ptr) = static_cast<char>('0' + abs_value);
+        }
+
+        o->write_characters(number_buffer.data(), n_chars);
+    }
+
+    /*!
+    @brief dump a floating-point number
+
+    Dump a given floating-point number to output stream @a o. Works internally
+    with @a number_buffer.
+
+    @param[in] x  floating-point number to dump
+    */
+    void dump_float(number_float_t x)
+    {
+        // NaN / inf
+        if (!std::isfinite(x))
+        {
+            o->write_characters("null", 4);
+            return;
+        }
+
+        // If number_float_t is an IEEE-754 single or double precision number,
+        // use the Grisu2 algorithm to produce short numbers which are
+        // guaranteed to round-trip, using strtof and strtod, resp.
+        //
+        // NB: The test below works if <long double> == <double>.
+        static constexpr bool is_ieee_single_or_double
+            = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
+              (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
+
+        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
+    }
+
+    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
+    {
+        auto* begin = number_buffer.data();
+        auto* end = ::wpi::detail::to_chars(begin, begin + number_buffer.size(), x);
+
+        o->write_characters(begin, static_cast<size_t>(end - begin));
+    }
+
+    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
+    {
+        // get number of digits for a float -> text -> float round-trip
+        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
+
+        // the actual conversion
+        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
+
+        // negative value indicates an error
+        JSON_ASSERT(len > 0);
+        // check if buffer was large enough
+        JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
+
+        // erase thousands separator
+        if (thousands_sep != '\0')
+        {
+            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
+            const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
+            std::fill(end, number_buffer.end(), '\0');
+            JSON_ASSERT((end - number_buffer.begin()) <= len);
+            len = (end - number_buffer.begin());
+        }
+
+        // convert decimal point to '.'
+        if (decimal_point != '\0' && decimal_point != '.')
+        {
+            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
+            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
+            if (dec_pos != number_buffer.end())
+            {
+                *dec_pos = '.';
+            }
+        }
+
+        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
+
+        // determine if we need to append ".0"
+        const bool value_is_int_like =
+            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
+                         [](char c)
+        {
+            return c == '.' || c == 'e';
+        });
+
+        if (value_is_int_like)
+        {
+            o->write_characters(".0", 2);
+        }
+    }
+
+  private:
+    /*!
+    @brief check whether a string is UTF-8 encoded
+
+    The function checks each byte of a string whether it is UTF-8 encoded. The
+    result of the check is stored in the @a state parameter. The function must
+    be called initially with state 0 (accept). State 1 means the string must
+    be rejected, because the current byte is not allowed. If the string is
+    completely processed, but the state is non-zero, the string ended
+    prematurely; that is, the last byte indicated more bytes should have
+    followed.
+
+    @param[in,out] state  the state of the decoding
+    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
+    @param[in] byte       next byte to decode
+    @return               new state
+
+    @note The function has been edited: a std::array is used.
+
+    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+    */
+    static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
+    {
+        static const std::array<std::uint8_t, 400> utf8d =
+        {
+            {
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
+                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
+                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
+                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
+                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
+                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
+                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
+                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
+                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
+                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
+                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
+            }
+        };
+
+        JSON_ASSERT(byte < utf8d.size());
+        const std::uint8_t type = utf8d[byte];
+
+        codep = (state != UTF8_ACCEPT)
+                ? (byte & 0x3fu) | (codep << 6u)
+                : (0xFFu >> type) & (byte);
+
+        std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
+        JSON_ASSERT(index < 400);
+        state = utf8d[index];
+        return state;
+    }
+
+    /*
+     * Overload to make the compiler happy while it is instantiating
+     * dump_integer for number_unsigned_t.
+     * Must never be called.
+     */
+    number_unsigned_t remove_sign(number_unsigned_t x)
+    {
+        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        return x; // LCOV_EXCL_LINE
+    }
+
+    /*
+     * Helper function for dump_integer
+     *
+     * This function takes a negative signed integer and returns its absolute
+     * value as unsigned integer. The plus/minus shuffling is necessary as we can
+     * not directly remove the sign of an arbitrary signed integer as the
+     * absolute values of INT_MIN and INT_MAX are usually not the same. See
+     * #1708 for details.
+     */
+    inline number_unsigned_t remove_sign(number_integer_t x) noexcept
+    {
+        JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
+        return static_cast<number_unsigned_t>(-(x + 1)) + 1;
+    }
+
+  private:
+    /// the output of the serializer
+    output_adapter_t<char> o = nullptr;
+
+    /// a (hopefully) large enough character buffer
+    std::array<char, 64> number_buffer{{}};
+
+    /// the locale
+    const std::lconv* loc = nullptr;
+    /// the locale's thousand separator character
+    const char thousands_sep = '\0';
+    /// the locale's decimal point character
+    const char decimal_point = '\0';
+
+    /// string buffer
+    std::array<char, 512> string_buffer{{}};
+
+    /// the indentation character
+    const char indent_char;
+    /// the indentation string
+    string_t indent_string;
+
+    /// error_handler how to react on decoding errors
+    const error_handler_t error_handler;
+};
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/string_concat.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/string_concat.h
new file mode 100644
index 0000000..972e664
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/string_concat.h
@@ -0,0 +1,146 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <cstring> // strlen
+#include <string> // string
+#include <utility> // forward
+
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/detected.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+inline std::size_t concat_length()
+{
+    return 0;
+}
+
+template<typename... Args>
+inline std::size_t concat_length(const char* cstr, Args&& ... rest);
+
+template<typename StringType, typename... Args>
+inline std::size_t concat_length(const StringType& str, Args&& ... rest);
+
+template<typename... Args>
+inline std::size_t concat_length(const char /*c*/, Args&& ... rest)
+{
+    return 1 + concat_length(std::forward<Args>(rest)...);
+}
+
+template<typename... Args>
+inline std::size_t concat_length(const char* cstr, Args&& ... rest)
+{
+    // cppcheck-suppress ignoredReturnValue
+    return ::strlen(cstr) + concat_length(std::forward<Args>(rest)...);
+}
+
+template<typename StringType, typename... Args>
+inline std::size_t concat_length(const StringType& str, Args&& ... rest)
+{
+    return str.size() + concat_length(std::forward<Args>(rest)...);
+}
+
+template<typename OutStringType>
+inline void concat_into(OutStringType& /*out*/)
+{}
+
+template<typename StringType, typename Arg>
+using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
+
+template<typename StringType, typename Arg>
+using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
+
+template<typename StringType, typename Arg>
+using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
+
+template<typename StringType, typename Arg>
+using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
+
+template<typename StringType, typename Arg>
+using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
+
+template<typename StringType, typename Arg>
+using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
+
+template<typename StringType, typename Arg>
+using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
+
+template<typename StringType, typename Arg>
+using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
+inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
+inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && !detect_string_can_append_iter<OutStringType, Arg>::value
+                         && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
+inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
+
+template<typename OutStringType, typename Arg, typename... Args,
+         enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
+inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
+{
+    out.append(std::forward<Arg>(arg));
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && detect_string_can_append_op<OutStringType, Arg>::value, int > >
+inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
+{
+    out += std::forward<Arg>(arg);
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && detect_string_can_append_iter<OutStringType, Arg>::value, int > >
+inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
+{
+    out.append(arg.begin(), arg.end());
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && !detect_string_can_append_iter<OutStringType, Arg>::value
+                         && detect_string_can_append_data<OutStringType, Arg>::value, int > >
+inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
+{
+    out.append(arg.data(), arg.size());
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template<typename OutStringType = std::string, typename... Args>
+inline OutStringType concat(Args && ... args)
+{
+    OutStringType str;
+    str.reserve(concat_length(std::forward<Args>(args)...));
+    concat_into(str, std::forward<Args>(args)...);
+    return str;
+}
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/string_escape.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/string_escape.h
new file mode 100644
index 0000000..2e508e6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/string_escape.h
@@ -0,0 +1,72 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <wpi/detail/abi_macros.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief replace all occurrences of a substring by another string
+
+@param[in,out] s  the string to manipulate; changed so that all
+               occurrences of @a f are replaced with @a t
+@param[in]     f  the substring to replace with @a t
+@param[in]     t  the string to replace @a f
+
+@pre The search string @a f must not be empty. **This precondition is
+enforced with an assertion.**
+
+@since version 2.0.0
+*/
+template<typename StringType>
+inline void replace_substring(StringType& s, const StringType& f,
+                              const StringType& t)
+{
+    JSON_ASSERT(!f.empty());
+    for (auto pos = s.find(f);                // find first occurrence of f
+            pos != StringType::npos;          // make sure f was found
+            s.replace(pos, f.size(), t),      // replace with t, and
+            pos = s.find(f, pos + t.size()))  // find next occurrence of f
+    {}
+}
+
+/*!
+ * @brief string escaping as described in RFC 6901 (Sect. 4)
+ * @param[in] s string to escape
+ * @return    escaped string
+ *
+ * Note the order of escaping "~" to "~0" and "/" to "~1" is important.
+ */
+template<typename StringType>
+inline StringType escape(StringType s)
+{
+    replace_substring(s, StringType{"~"}, StringType{"~0"});
+    replace_substring(s, StringType{"/"}, StringType{"~1"});
+    return s;
+}
+
+/*!
+ * @brief string unescaping as described in RFC 6901 (Sect. 4)
+ * @param[in] s string to unescape
+ * @return    unescaped string
+ *
+ * Note the order of escaping "~1" to "/" and "~0" to "~" is important.
+ */
+template<typename StringType>
+static void unescape(StringType& s)
+{
+    replace_substring(s, StringType{"~1"}, StringType{"/"});
+    replace_substring(s, StringType{"~0"}, StringType{"~"});
+}
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/value_t.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/value_t.h
new file mode 100644
index 0000000..8366f00
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/detail/value_t.h
@@ -0,0 +1,118 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <array> // array
+#include <cstddef> // size_t
+#include <cstdint> // uint8_t
+#include <string> // string
+
+#include <wpi/detail/macro_scope.h>
+#if JSON_HAS_THREE_WAY_COMPARISON
+    #include <compare> // partial_ordering
+#endif
+
+WPI_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////////////
+// JSON type enumeration //
+///////////////////////////
+
+/*!
+@brief the JSON type enumeration
+
+This enumeration collects the different JSON types. It is internally used to
+distinguish the stored values, and the functions @ref basic_json::is_null(),
+@ref basic_json::is_object(), @ref basic_json::is_array(),
+@ref basic_json::is_string(), @ref basic_json::is_boolean(),
+@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
+@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
+@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
+@ref basic_json::is_structured() rely on it.
+
+@note There are three enumeration entries (number_integer, number_unsigned, and
+number_float), because the library distinguishes these three types for numbers:
+@ref basic_json::number_unsigned_t is used for unsigned integers,
+@ref basic_json::number_integer_t is used for signed integers, and
+@ref basic_json::number_float_t is used for floating-point numbers or to
+approximate integers which do not fit in the limits of their respective type.
+
+@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON
+value with the default value for a given type
+
+@since version 1.0.0
+*/
+enum class value_t : std::uint8_t
+{
+    null,             ///< null value
+    object,           ///< object (unordered set of name/value pairs)
+    array,            ///< array (ordered collection of values)
+    string,           ///< string value
+    boolean,          ///< boolean value
+    number_integer,   ///< number value (signed integer)
+    number_unsigned,  ///< number value (unsigned integer)
+    number_float,     ///< number value (floating-point)
+    binary,           ///< binary array (ordered collection of bytes)
+    discarded         ///< discarded by the parser callback function
+};
+
+/*!
+@brief comparison operator for JSON types
+
+Returns an ordering that is similar to Python:
+- order: null < boolean < number < object < array < string < binary
+- furthermore, each type is not smaller than itself
+- discarded values are not comparable
+- binary is represented as a b"" string in python and directly comparable to a
+  string; however, making a binary array directly comparable with a string would
+  be surprising behavior in a JSON file.
+
+@since version 1.0.0
+*/
+#if JSON_HAS_THREE_WAY_COMPARISON
+    inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
+#else
+    inline bool operator<(const value_t lhs, const value_t rhs) noexcept
+#endif
+{
+    static constexpr std::array<std::uint8_t, 9> order = {{
+            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
+            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,
+            6 /* binary */
+        }
+    };
+
+    const auto l_index = static_cast<std::size_t>(lhs);
+    const auto r_index = static_cast<std::size_t>(rhs);
+#if JSON_HAS_THREE_WAY_COMPARISON
+    if (l_index < order.size() && r_index < order.size())
+    {
+        return order[l_index] <=> order[r_index]; // *NOPAD*
+    }
+    return std::partial_ordering::unordered;
+#else
+    return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
+#endif
+}
+
+// GCC selects the built-in operator< over an operator rewritten from
+// a user-defined spaceship operator
+// Clang, MSVC, and ICC select the rewritten candidate
+// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
+#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
+inline bool operator<(const value_t lhs, const value_t rhs) noexcept
+{
+    return std::is_lt(lhs <=> rhs); // *NOPAD*
+}
+#endif
+
+}  // namespace detail
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/json.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
index 1c07deb..47ff86a 100644
--- a/wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
@@ -1,2638 +1,82 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2019 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
 
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
+/****************************************************************************\
+ * Note on documentation: The source files contain links to the online      *
+ * documentation of the public API at https://json.nlohmann.me. This URL    *
+ * contains the most recent documentation and should also be applicable to  *
+ * previous versions; documentation for deprecated functions is not         *
+ * removed, but marked deprecated. See "Generate documentation" section in  *
+ * file docs/README.md.                                                     *
+\****************************************************************************/
 
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
+#ifndef INCLUDE_WPI_JSON_HPP_
+#define INCLUDE_WPI_JSON_HPP_
 
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#ifndef WPIUTIL_JSON_H
-#define WPIUTIL_JSON_H
-
-#define NLOHMANN_JSON_VERSION_MAJOR 3
-#define NLOHMANN_JSON_VERSION_MINOR 1
-#define NLOHMANN_JSON_VERSION_PATCH 2
-
-
-#include <algorithm> // all_of, copy, find, for_each, generate_n, min, reverse, remove, fill, none_of, transform
-#include <array> // array
-#include <cassert> // assert
+#include <algorithm> // all_of, find, for_each
 #include <cstddef> // nullptr_t, ptrdiff_t, size_t
-#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
-#include <exception> // exception
-#include <functional> // function, hash, less
+#include <functional> // hash, less
 #include <initializer_list> // initializer_list
-#include <iterator>
-#include <limits> // numeric_limits
-#include <memory> // allocator, shared_ptr, make_shared, addressof
-#include <span>
-#include <stdexcept> // runtime_error
-#include <string> // string, char_traits, stoi, to_string
-#include <string_view>
-#include <tuple> // tuple, get, make_tuple
-#include <type_traits>
-#include <utility>
+#ifndef JSON_NO_IO
+    #include <iosfwd> // istream, ostream
+#endif  // JSON_NO_IO
+#include <iterator> // random_access_iterator_tag
+#include <memory> // unique_ptr
+#include <numeric> // accumulate
+#include <string> // string, stoi, to_string
+#include <utility> // declval, forward, move, pair, swap
 #include <vector> // vector
 
-#include "wpi/StringMap.h"
+#include <wpi/adl_serializer.h>
+#include <wpi/byte_container_with_subtype.h>
+#include <wpi/detail/conversions/from_json.h>
+#include <wpi/detail/conversions/to_json.h>
+#include <wpi/detail/exceptions.h>
+#include <wpi/detail/hash.h>
+#include <wpi/detail/input/binary_reader.h>
+#include <wpi/detail/input/input_adapters.h>
+#include <wpi/detail/input/lexer.h>
+#include <wpi/detail/input/parser.h>
+#include <wpi/detail/iterators/internal_iterator.h>
+#include <wpi/detail/iterators/iter_impl.h>
+#include <wpi/detail/iterators/iteration_proxy.h>
+#include <wpi/detail/iterators/json_reverse_iterator.h>
+#include <wpi/detail/iterators/primitive_iterator.h>
+#include <wpi/detail/json_pointer.h>
+#include <wpi/detail/json_ref.h>
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/string_concat.h>
+#include <wpi/detail/string_escape.h>
+#include <wpi/detail/meta/cpp_future.h>
+#include <wpi/detail/meta/type_traits.h>
+#include <wpi/detail/output/binary_writer.h>
+#include <wpi/detail/output/output_adapters.h>
+#include <wpi/detail/output/serializer.h>
+#include <wpi/detail/value_t.h>
+#include <wpi/json_fwd.h>
+#include <wpi/ordered_map.h>
 
-namespace wpi
-{
-
-class raw_istream;
-class raw_ostream;
-
-class JsonTest;
+#if defined(JSON_HAS_CPP_17)
+    #include <any>
+    #include <string_view>
+#endif
 
 /*!
-@brief default JSONSerializer template argument
-
-This serializer ignores the template arguments and uses ADL
-([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl))
-for serialization.
-*/
-template<typename = void, typename = void>
-struct adl_serializer;
-
-/*!
-@brief JSON Pointer
-
-A JSON pointer defines a string syntax for identifying a specific value
-within a JSON document. It can be used with functions `at` and
-`operator[]`. Furthermore, JSON pointers are the base for JSON patches.
-
-@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
-
-@since version 2.0.0
-*/
-class json_pointer;
-
-/*!
-@brief default JSON class
-
-This type is the default specialization of the @ref json class which
-uses the standard template types.
-
+@brief namespace for Niels Lohmann
+@see https://github.com/nlohmann
 @since version 1.0.0
 */
-class json;
-}
-
-// exclude unsupported compilers
-#if defined(__clang__)
-    #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
-        #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
-    #endif
-#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
-    #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
-        #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
-    #endif
-#endif
-
-// disable float-equal warnings on GCC/clang
-#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
-    #pragma GCC diagnostic push
-    #pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-
-// disable documentation warnings on clang
-#if defined(__clang__)
-    #pragma GCC diagnostic push
-    #pragma GCC diagnostic ignored "-Wdocumentation"
-#endif
-
-// allow to disable exceptions
-#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
-    #define JSON_THROW(exception) throw exception
-    #define JSON_TRY try
-    #define JSON_CATCH(exception) catch(exception)
-#else
-    #define JSON_THROW(exception) std::abort()
-    #define JSON_TRY if(true)
-    #define JSON_CATCH(exception) if(false)
-#endif
-
-// override exception macros
-#if defined(JSON_THROW_USER)
-    #undef JSON_THROW
-    #define JSON_THROW JSON_THROW_USER
-#endif
-#if defined(JSON_TRY_USER)
-    #undef JSON_TRY
-    #define JSON_TRY JSON_TRY_USER
-#endif
-#if defined(JSON_CATCH_USER)
-    #undef JSON_CATCH
-    #define JSON_CATCH JSON_CATCH_USER
-#endif
-
-// manual branch prediction
-#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
-    #define JSON_LIKELY(x)      __builtin_expect(!!(x), 1)
-    #define JSON_UNLIKELY(x)    __builtin_expect(!!(x), 0)
-#else
-    #define JSON_LIKELY(x)      x
-    #define JSON_UNLIKELY(x)    x
-#endif
-
-/*!
-@brief Helper to determine whether there's a key_type for T.
-
-This helper is used to tell associative containers apart from other containers
-such as sequence containers. For instance, `std::map` passes the test as it
-contains a `mapped_type`, whereas `std::vector` fails the test.
-
-@sa http://stackoverflow.com/a/7728728/266378
-@since version 1.0.0, overworked in version 2.0.6
-*/
-#define NLOHMANN_JSON_HAS_HELPER(type)                                        \
-    template<typename T> struct has_##type {                                  \
-    private:                                                                  \
-        template<typename U, typename = typename U::type>                     \
-        static int detect(U &&);                                              \
-        static void detect(...);                                              \
-    public:                                                                   \
-        static constexpr bool value =                                         \
-                std::is_integral<decltype(detect(std::declval<T>()))>::value; \
-    }
-
-namespace wpi
-{
-/*!
-@brief detail namespace with internal helper functions
-
-This namespace collects functions that should not be exposed,
-implementations of some @ref json methods, and meta-programming helpers.
-
-@since version 2.1.0
-*/
-namespace detail
-{
-/////////////
-// helpers //
-/////////////
-
-template<typename> struct is_json : std::false_type {};
-
-template<> struct is_json<json> : std::true_type {};
-
-// alias templates to reduce boilerplate
-template<bool B, typename T = void>
-using enable_if_t = typename std::enable_if<B, T>::type;
-
-template<typename T>
-using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
-
-// dispatch utility (taken from ranges-v3)
-template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
-template<> struct priority_tag<0> {};
-
-////////////////////////
-// has_/is_ functions //
-////////////////////////
-
-// source: https://stackoverflow.com/a/37193089/4116453
-
-template <typename T, typename = void>
-struct is_complete_type : std::false_type {};
-
-template <typename T>
-struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
-
-NLOHMANN_JSON_HAS_HELPER(mapped_type);
-NLOHMANN_JSON_HAS_HELPER(key_type);
-NLOHMANN_JSON_HAS_HELPER(value_type);
-NLOHMANN_JSON_HAS_HELPER(iterator);
-
-template<bool B, class RealType, class CompatibleObjectType>
-struct is_compatible_object_type_impl : std::false_type {};
-
-template<class RealType, class CompatibleObjectType>
-struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
-{
-    static constexpr auto value =
-        std::is_constructible<std::string_view, typename CompatibleObjectType::key_type>::value and
-        std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
-};
-
-template<class BasicJsonType, class CompatibleObjectType>
-struct is_compatible_object_type
-{
-    static auto constexpr value = is_compatible_object_type_impl <
-                                  std::conjunction<std::negation<std::is_same<void, CompatibleObjectType>>,
-                                  has_mapped_type<CompatibleObjectType>,
-                                  has_key_type<CompatibleObjectType>>::value,
-                                  typename BasicJsonType::object_t, CompatibleObjectType >::value;
-};
-
-template<typename BasicJsonType, typename T>
-struct is_json_nested_type
-{
-    static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
-                                  std::is_same<T, typename BasicJsonType::const_iterator>::value or
-                                  std::is_same<T, typename BasicJsonType::reverse_iterator>::value or
-                                  std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value;
-};
-
-template<class BasicJsonType, class CompatibleArrayType>
-struct is_compatible_array_type
-{
-    static auto constexpr value =
-        std::conjunction<std::negation<std::is_same<void, CompatibleArrayType>>,
-        std::negation<is_compatible_object_type<
-        BasicJsonType, CompatibleArrayType>>,
-        std::negation<std::is_constructible<std::string_view,
-        CompatibleArrayType>>,
-        std::negation<is_json_nested_type<BasicJsonType, CompatibleArrayType>>,
-        has_value_type<CompatibleArrayType>,
-        has_iterator<CompatibleArrayType>>::value;
-};
-
-template<bool, typename, typename>
-struct is_compatible_integer_type_impl : std::false_type {};
-
-template<typename RealIntegerType, typename CompatibleNumberIntegerType>
-struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
-{
-    // is there an assert somewhere on overflows?
-    using RealLimits = std::numeric_limits<RealIntegerType>;
-    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
-
-    static constexpr auto value =
-        std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and
-        CompatibleLimits::is_integer and
-        RealLimits::is_signed == CompatibleLimits::is_signed;
-};
-
-template<typename RealIntegerType, typename CompatibleNumberIntegerType>
-struct is_compatible_integer_type
-{
-    static constexpr auto value =
-        is_compatible_integer_type_impl <
-        std::is_integral<CompatibleNumberIntegerType>::value and
-        not std::is_same<bool, CompatibleNumberIntegerType>::value,
-        RealIntegerType, CompatibleNumberIntegerType > ::value;
-};
-
-// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
-template<typename BasicJsonType, typename T>
-struct has_from_json
-{
-  private:
-    // also check the return type of from_json
-    template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
-                 std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
-    static int detect(U&&);
-    static void detect(...);
-
-  public:
-    static constexpr bool value = std::is_integral<decltype(
-                                      detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
-};
-
-// This trait checks if JSONSerializer<T>::from_json(json const&) exists
-// this overload is used for non-default-constructible user-defined-types
-template<typename BasicJsonType, typename T>
-struct has_non_default_from_json
-{
-  private:
-    template <
-        typename U,
-        typename = enable_if_t<std::is_same<
-                                   T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >>
-    static int detect(U&&);
-    static void detect(...);
-
-  public:
-    static constexpr bool value = std::is_integral<decltype(detect(
-                                      std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
-};
-
-// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
-template<typename BasicJsonType, typename T>
-struct has_to_json
-{
-  private:
-    template<typename U, typename = decltype(uncvref_t<U>::to_json(
-                 std::declval<BasicJsonType&>(), std::declval<T>()))>
-    static int detect(U&&);
-    static void detect(...);
-
-  public:
-    static constexpr bool value = std::is_integral<decltype(detect(
-                                      std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
-};
-
-template <typename BasicJsonType, typename CompatibleCompleteType>
-struct is_compatible_complete_type
-{
-    static constexpr bool value =
-        not std::is_base_of<std::istream, CompatibleCompleteType>::value and
-        not is_json<CompatibleCompleteType>::value and
-        not is_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
-        has_to_json<BasicJsonType, CompatibleCompleteType>::value;
-};
-
-template <typename BasicJsonType, typename CompatibleType>
-struct is_compatible_type
-    : std::conjunction<is_complete_type<CompatibleType>,
-      is_compatible_complete_type<BasicJsonType, CompatibleType>>
-{
-};
-
-// taken from ranges-v3
-template<typename T>
-struct static_const
-{
-    static constexpr T value{};
-};
-
-template<typename T>
-constexpr T static_const<T>::value;
-
-////////////////
-// exceptions //
-////////////////
-
-/*!
-@brief general exception of the @ref json class
-
-This class is an extension of `std::exception` objects with a member @a id for
-exception ids. It is used as the base class for all exceptions thrown by the
-@ref json class. This class can hence be used as "wildcard" to catch
-exceptions.
-
-Subclasses:
-- @ref parse_error for exceptions indicating a parse error
-- @ref invalid_iterator for exceptions indicating errors with iterators
-- @ref type_error for exceptions indicating executing a member function with
-                  a wrong type
-- @ref out_of_range for exceptions indicating access out of the defined range
-- @ref other_error for exceptions indicating other library errors
-
-@internal
-@note To have nothrow-copy-constructible exceptions, we internally use
-      `std::runtime_error` which can cope with arbitrary-length error messages.
-      Intermediate strings are built with static functions and then passed to
-      the actual constructor.
-@endinternal
-
-@liveexample{The following code shows how arbitrary library exceptions can be
-caught.,exception}
-
-@since version 3.0.0
-*/
-class exception : public std::exception
-{
-  public:
-    /// returns the explanatory string
-    const char* what() const noexcept override
-    {
-        return m.what();
-    }
-
-    /// the id of the exception
-    const int id;
-
-  protected:
-    exception(int id_, std::string_view what_arg);
-
-  private:
-    /// an exception object as storage for error messages
-    std::runtime_error m;
-};
-
-/*!
-@brief exception indicating a parse error
-
-This exception is thrown by the library when a parse error occurs. Parse errors
-can occur during the deserialization of JSON text, CBOR, MessagePack, as well
-as when using JSON Patch.
-
-Member @a byte holds the byte index of the last read character in the input
-file.
-
-Exceptions have ids 1xx.
-
-name / id                      | example message | description
------------------------------- | --------------- | -------------------------
-json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.
-json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.
-json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.
-json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.
-json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors.
-json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.
-json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.
-json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.
-json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.
-json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
-json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
-json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
-
-@note For an input with n bytes, 1 is the index of the first character and n+1
-      is the index of the terminating null byte or the end of file. This also
-      holds true when reading a byte vector (CBOR or MessagePack).
-
-@liveexample{The following code shows how a `parse_error` exception can be
-caught.,parse_error}
-
-@sa @ref exception for the base class of the library exceptions
-@sa @ref invalid_iterator for exceptions indicating errors with iterators
-@sa @ref type_error for exceptions indicating executing a member function with
-                    a wrong type
-@sa @ref out_of_range for exceptions indicating access out of the defined range
-@sa @ref other_error for exceptions indicating other library errors
-
-@since version 3.0.0
-*/
-class parse_error : public exception
-{
-  public:
-    /*!
-    @brief create a parse error exception
-    @param[in] id_       the id of the exception
-    @param[in] byte_     the byte index where the error occurred (or 0 if the
-                         position cannot be determined)
-    @param[in] what_arg  the explanatory string
-    @return parse_error object
-    */
-    static parse_error create(int id_, std::size_t byte_, std::string_view what_arg);
-
-    /*!
-    @brief byte index of the parse error
-
-    The byte index of the last read character in the input file.
-
-    @note For an input with n bytes, 1 is the index of the first character and
-          n+1 is the index of the terminating null byte or the end of file.
-          This also holds true when reading a byte vector (CBOR or MessagePack).
-    */
-    const std::size_t byte;
-
-  private:
-    parse_error(int id_, std::size_t byte_, std::string_view what_arg)
-        : exception(id_, what_arg), byte(byte_) {}
-};
-
-/*!
-@brief exception indicating errors with iterators
-
-This exception is thrown if iterators passed to a library function do not match
-the expected semantics.
-
-Exceptions have ids 2xx.
-
-name / id                           | example message | description
------------------------------------ | --------------- | -------------------------
-json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
-json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
-json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.
-json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.
-json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.
-json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.
-json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.
-json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
-json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
-json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
-json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.
-json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.
-json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.
-json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().
-
-@liveexample{The following code shows how an `invalid_iterator` exception can be
-caught.,invalid_iterator}
-
-@sa @ref exception for the base class of the library exceptions
-@sa @ref parse_error for exceptions indicating a parse error
-@sa @ref type_error for exceptions indicating executing a member function with
-                    a wrong type
-@sa @ref out_of_range for exceptions indicating access out of the defined range
-@sa @ref other_error for exceptions indicating other library errors
-
-@since version 3.0.0
-*/
-class invalid_iterator : public exception
-{
-  public:
-    static invalid_iterator create(int id_, std::string_view what_arg);
-    static invalid_iterator create(int id_, std::string_view what_arg, std::string_view type_info);
-
-  private:
-    invalid_iterator(int id_, std::string_view what_arg)
-        : exception(id_, what_arg) {}
-};
-
-/*!
-@brief exception indicating executing a member function with a wrong type
-
-This exception is thrown in case of a type error; that is, a library function is
-executed on a JSON value whose type does not match the expected semantics.
-
-Exceptions have ids 3xx.
-
-name / id                     | example message | description
------------------------------ | --------------- | -------------------------
-json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
-json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
-json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&.
-json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
-json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
-json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
-json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.
-json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.
-json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.
-json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.
-json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.
-json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.
-json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.
-json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
-json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
-json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |
-
-@liveexample{The following code shows how a `type_error` exception can be
-caught.,type_error}
-
-@sa @ref exception for the base class of the library exceptions
-@sa @ref parse_error for exceptions indicating a parse error
-@sa @ref invalid_iterator for exceptions indicating errors with iterators
-@sa @ref out_of_range for exceptions indicating access out of the defined range
-@sa @ref other_error for exceptions indicating other library errors
-
-@since version 3.0.0
-*/
-class type_error : public exception
-{
-  public:
-    static type_error create(int id_, std::string_view what_arg);
-    static type_error create(int id_, std::string_view what_arg, std::string_view type_info);
-
-  private:
-    type_error(int id_, std::string_view what_arg) : exception(id_, what_arg) {}
-};
-
-/*!
-@brief exception indicating access out of the defined range
-
-This exception is thrown in case a library function is called on an input
-parameter that exceeds the expected range, for instance in case of array
-indices or nonexisting object keys.
-
-Exceptions have ids 4xx.
-
-name / id                       | example message | description
-------------------------------- | --------------- | -------------------------
-json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.
-json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.
-json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.
-json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
-json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
-json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
-json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. |
-json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
-
-@liveexample{The following code shows how an `out_of_range` exception can be
-caught.,out_of_range}
-
-@sa @ref exception for the base class of the library exceptions
-@sa @ref parse_error for exceptions indicating a parse error
-@sa @ref invalid_iterator for exceptions indicating errors with iterators
-@sa @ref type_error for exceptions indicating executing a member function with
-                    a wrong type
-@sa @ref other_error for exceptions indicating other library errors
-
-@since version 3.0.0
-*/
-class out_of_range : public exception
-{
-  public:
-    static out_of_range create(int id_, std::string_view what_arg);
-
-  private:
-    out_of_range(int id_, std::string_view what_arg) : exception(id_, what_arg) {}
-};
-
-/*!
-@brief exception indicating other library errors
-
-This exception is thrown in case of errors that cannot be classified with the
-other exception types.
-
-Exceptions have ids 5xx.
-
-name / id                      | example message | description
------------------------------- | --------------- | -------------------------
-json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
-
-@sa @ref exception for the base class of the library exceptions
-@sa @ref parse_error for exceptions indicating a parse error
-@sa @ref invalid_iterator for exceptions indicating errors with iterators
-@sa @ref type_error for exceptions indicating executing a member function with
-                    a wrong type
-@sa @ref out_of_range for exceptions indicating access out of the defined range
-
-@liveexample{The following code shows how an `other_error` exception can be
-caught.,other_error}
-
-@since version 3.0.0
-*/
-class other_error : public exception
-{
-  public:
-    static other_error create(int id_, std::string_view what_arg);
-
-  private:
-    other_error(int id_, std::string_view what_arg) : exception(id_, what_arg) {}
-};
-
-///////////////////////////
-// JSON type enumeration //
-///////////////////////////
-
-/*!
-@brief the JSON type enumeration
-
-This enumeration collects the different JSON types. It is internally used to
-distinguish the stored values, and the functions @ref json::is_null(),
-@ref json::is_object(), @ref json::is_array(),
-@ref json::is_string(), @ref json::is_boolean(),
-@ref json::is_number() (with @ref json::is_number_integer(),
-@ref json::is_number_unsigned(), and @ref json::is_number_float()),
-@ref json::is_discarded(), @ref json::is_primitive(), and
-@ref json::is_structured() rely on it.
-
-@note There are three enumeration entries (number_integer, number_unsigned, and
-number_float), because the library distinguishes these three types for numbers:
-uint64_t is used for unsigned integers,
-int64_t is used for signed integers, and
-double is used for floating-point numbers or to
-approximate integers which do not fit in the limits of their respective type.
-
-@sa @ref json::json(const value_t value_type) -- create a JSON
-value with the default value for a given type
-
-@since version 1.0.0
-*/
-enum class value_t : std::uint8_t
-{
-    null,             ///< null value
-    object,           ///< object (unordered set of name/value pairs)
-    array,            ///< array (ordered collection of values)
-    string,           ///< string value
-    boolean,          ///< boolean value
-    number_integer,   ///< number value (signed integer)
-    number_unsigned,  ///< number value (unsigned integer)
-    number_float,     ///< number value (floating-point)
-    discarded         ///< discarded by the the parser callback function
-};
-
-/*!
-@brief comparison operator for JSON types
-
-Returns an ordering that is similar to Python:
-- order: null < boolean < number < object < array < string
-- furthermore, each type is not smaller than itself
-- discarded values are not comparable
-
-@since version 1.0.0
-*/
-inline bool operator<(const value_t lhs, const value_t rhs) noexcept
-{
-    static constexpr std::array<std::uint8_t, 8> order = {{
-            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
-            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */
-        }
-    };
-
-    const auto l_index = static_cast<std::size_t>(lhs);
-    const auto r_index = static_cast<std::size_t>(rhs);
-    return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];
-}
-
-// overloads for json template parameters
-template<typename BasicJsonType, typename ArithmeticType,
-         enable_if_t<std::is_arithmetic<ArithmeticType>::value and
-                     not std::is_same<ArithmeticType, bool>::value,
-                     int> = 0>
-void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
-{
-    switch (static_cast<value_t>(j))
-    {
-        case value_t::number_unsigned:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const uint64_t*>());
-            break;
-        }
-        case value_t::number_integer:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const int64_t*>());
-            break;
-        }
-        case value_t::number_float:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const double*>());
-            break;
-        }
-
-        default:
-            JSON_THROW(type_error::create(302, "type must be number, but is", j.type_name()));
-    }
-}
-
-template<typename BasicJsonType>
-void from_json(const BasicJsonType& j, bool& b)
-{
-    if (JSON_UNLIKELY(not j.is_boolean()))
-    {
-        JSON_THROW(type_error::create(302, "type must be boolean, but is", j.type_name()));
-    }
-    b = *j.template get_ptr<const bool*>();
-}
-
-template<typename BasicJsonType>
-void from_json(const BasicJsonType& j, std::string& s)
-{
-    if (JSON_UNLIKELY(not j.is_string()))
-    {
-        JSON_THROW(type_error::create(302, "type must be string, but is", j.type_name()));
-    }
-    s = *j.template get_ptr<const std::string*>();
-}
-
-template<typename BasicJsonType>
-void from_json(const BasicJsonType& j, double& val)
-{
-    get_arithmetic_value(j, val);
-}
-
-template<typename BasicJsonType>
-void from_json(const BasicJsonType& j, uint64_t& val)
-{
-    get_arithmetic_value(j, val);
-}
-
-template<typename BasicJsonType>
-void from_json(const BasicJsonType& j, int64_t& val)
-{
-    get_arithmetic_value(j, val);
-}
-
-template<typename BasicJsonType, typename EnumType,
-         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
-void from_json(const BasicJsonType& j, EnumType& e)
-{
-    typename std::underlying_type<EnumType>::type val;
-    get_arithmetic_value(j, val);
-    e = static_cast<EnumType>(val);
-}
-
-template<typename BasicJsonType>
-void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
-{
-    if (JSON_UNLIKELY(not j.is_array()))
-    {
-        JSON_THROW(type_error::create(302, "type must be array, but is", j.type_name()));
-    }
-    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
-}
-
-template<typename BasicJsonType, typename CompatibleArrayType>
-void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/)
-{
-    using std::end;
-
-    std::transform(j.begin(), j.end(),
-                   std::inserter(arr, end(arr)), [](const BasicJsonType & i)
-    {
-        // get<BasicJsonType>() returns *this, this won't call a from_json
-        // method when value_type is BasicJsonType
-        return i.template get<typename CompatibleArrayType::value_type>();
-    });
-}
-
-template<typename BasicJsonType, typename CompatibleArrayType>
-auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
--> decltype(
-    arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
-    void())
-{
-    using std::end;
-
-    arr.reserve(j.size());
-    std::transform(j.begin(), j.end(),
-                   std::inserter(arr, end(arr)), [](const BasicJsonType & i)
-    {
-        // get<BasicJsonType>() returns *this, this won't call a from_json
-        // method when value_type is BasicJsonType
-        return i.template get<typename CompatibleArrayType::value_type>();
-    });
-}
-
-template<typename BasicJsonType, typename T, std::size_t N>
-void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/)
-{
-    for (std::size_t i = 0; i < N; ++i)
-    {
-        arr[i] = j.at(i).template get<T>();
-    }
-}
-
-template <
-    typename BasicJsonType, typename CompatibleArrayType,
-    enable_if_t <
-        is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
-        not std::is_same<typename BasicJsonType::array_t,
-                         CompatibleArrayType>::value and
-        std::is_constructible <
-            BasicJsonType, typename CompatibleArrayType::value_type >::value,
-        int > = 0 >
-void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
-{
-    if (JSON_UNLIKELY(not j.is_array()))
-    {
-        JSON_THROW(type_error::create(302, "type must be array, but is", j.type_name()));
-    }
-
-    from_json_array_impl(j, arr, priority_tag<2> {});
-}
-
-template<typename BasicJsonType>
-inline
-void from_json(const BasicJsonType& j, typename BasicJsonType::object_t& obj)
-{
-    if (!j.is_object())
-    {
-        JSON_THROW(type_error::create(302, "type must be object, but is", j.type_name()));
-    }
-
-    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
-    for (const auto& i : *inner_object) {
-        obj.try_emplace(i.first(), i.second);
-    }
-}
-
-template<typename BasicJsonType, typename CompatibleObjectType,
-         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and
-                     not std::is_same<typename BasicJsonType::object_t, CompatibleObjectType>::value, int> = 0>
-void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
-{
-    if (JSON_UNLIKELY(not j.is_object()))
-    {
-        JSON_THROW(type_error::create(302, "type must be object, but is", j.type_name()));
-    }
-
-    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
-    using std::begin;
-    using std::end;
-    using value_type = typename CompatibleObjectType::value_type;
-    std::vector<value_type> v;
-    v.reserve(j.size());
-    for (const auto& p : *inner_object)
-    {
-        v.emplace_back(
-            p.first(),
-            p.second
-            .template get<typename CompatibleObjectType::mapped_type>());
-    }
-    // we could avoid the assignment, but this might require a for loop, which
-    // might be less efficient than the container constructor for some
-    // containers (would it?)
-    obj = CompatibleObjectType(std::make_move_iterator(begin(v)),
-                               std::make_move_iterator(end(v)));
-}
-
-// overload for arithmetic types, not chosen for json template arguments
-// (BooleanType, etc..); note: Is it really necessary to provide explicit
-// overloads for bool etc. in case of a custom BooleanType which is not
-// an arithmetic type?
-template<typename BasicJsonType, typename ArithmeticType,
-         enable_if_t <
-             std::is_arithmetic<ArithmeticType>::value and
-             not std::is_same<ArithmeticType, uint64_t>::value and
-             not std::is_same<ArithmeticType, int64_t>::value and
-             not std::is_same<ArithmeticType, double>::value and
-             not std::is_same<ArithmeticType, bool>::value,
-             int> = 0>
-void from_json(const BasicJsonType& j, ArithmeticType& val)
-{
-    switch (static_cast<value_t>(j))
-    {
-        case value_t::number_unsigned:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const uint64_t*>());
-            break;
-        }
-        case value_t::number_integer:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const int64_t*>());
-            break;
-        }
-        case value_t::number_float:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const double*>());
-            break;
-        }
-        case value_t::boolean:
-        {
-            val = static_cast<ArithmeticType>(*j.template get_ptr<const bool*>());
-            break;
-        }
-
-        default:
-            JSON_THROW(type_error::create(302, "type must be number, but is", j.type_name()));
-    }
-}
-
-template<typename BasicJsonType, typename A1, typename A2>
-void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
-{
-    p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
-}
-
-template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
-void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, std::index_sequence<Idx...>)
-{
-    t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
-}
-
-template<typename BasicJsonType, typename... Args>
-void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
-{
-    from_json_tuple_impl(j, t, std::index_sequence_for<Args...> {});
-}
-
-struct from_json_fn
-{
-  private:
-    template<typename BasicJsonType, typename T>
-    auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const
-    noexcept(noexcept(from_json(j, val)))
-    -> decltype(from_json(j, val), void())
-    {
-        return from_json(j, val);
-    }
-
-    template<typename BasicJsonType, typename T>
-    void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept
-    {
-        static_assert(sizeof(BasicJsonType) == 0,
-                      "could not find from_json() method in T's namespace");
-#ifdef _MSC_VER
-        // MSVC does not show a stacktrace for the above assert
-        using decayed = uncvref_t<T>;
-        static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
-                      "forcing MSVC stacktrace to show which T we're talking about.");
-#endif
-    }
-
-  public:
-    template<typename BasicJsonType, typename T>
-    void operator()(const BasicJsonType& j, T& val) const
-    noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
-    {
-        return call(j, val, priority_tag<1> {});
-    }
-};
-}
-
-// namespace to hold default `from_json` function
-// to see why this is required:
-// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
-namespace
-{
-constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
-}
-
-namespace detail
-{
-//////////////////
-// constructors //
-//////////////////
-
-template<value_t> struct external_constructor;
-
-template<>
-struct external_constructor<value_t::boolean>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, bool b) noexcept
-    {
-        j.m_type = value_t::boolean;
-        j.m_value = b;
-        j.assert_invariant();
-    }
-};
-
-template<>
-struct external_constructor<value_t::string>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, std::string_view s)
-    {
-        j.m_type = value_t::string;
-        j.m_value = s;
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType, typename T,
-             enable_if_t<std::is_same<std::string, T>::value, int> = 0>
-    static void construct(BasicJsonType& j, T&& s)
-    {
-        j.m_type = value_t::string;
-        j.m_value = std::move(s);
-        j.assert_invariant();
-    }
-};
-
-template<>
-struct external_constructor<value_t::number_float>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, double val) noexcept
-    {
-        j.m_type = value_t::number_float;
-        j.m_value = val;
-        j.assert_invariant();
-    }
-};
-
-template<>
-struct external_constructor<value_t::number_unsigned>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, uint64_t val) noexcept
-    {
-        j.m_type = value_t::number_unsigned;
-        j.m_value = val;
-        j.assert_invariant();
-    }
-};
-
-template<>
-struct external_constructor<value_t::number_integer>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, int64_t val) noexcept
-    {
-        j.m_type = value_t::number_integer;
-        j.m_value = val;
-        j.assert_invariant();
-    }
-};
-
-template<>
-struct external_constructor<value_t::array>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
-    {
-        j.m_type = value_t::array;
-        j.m_value = arr;
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
-    {
-        j.m_type = value_t::array;
-        j.m_value = std::move(arr);
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType, typename T>
-    static void construct(BasicJsonType& j, std::span<T> arr)
-    {
-        using std::begin;
-        using std::end;
-        j.m_type = value_t::array;
-        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType, typename CompatibleArrayType,
-             enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
-                         int> = 0>
-    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
-    {
-        using std::begin;
-        using std::end;
-        j.m_type = value_t::array;
-        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, const std::vector<bool>& arr)
-    {
-        j.m_type = value_t::array;
-        j.m_value = value_t::array;
-        j.m_value.array->reserve(arr.size());
-        for (const bool x : arr)
-        {
-            j.m_value.array->push_back(x);
-        }
-        j.assert_invariant();
-    }
-};
-
-template<>
-struct external_constructor<value_t::object>
-{
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
-    {
-        j.m_type = value_t::object;
-        j.m_value = obj;
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType>
-    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
-    {
-        j.m_type = value_t::object;
-        j.m_value = std::move(obj);
-        j.assert_invariant();
-    }
-
-    template<typename BasicJsonType, typename CompatibleObjectType,
-             enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>
-    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
-    {
-        j.m_type = value_t::object;
-        j.m_value = value_t::object;
-        for (const auto& x : obj)
-        {
-            j.m_value.object->try_emplace(x.first, x.second);
-        }
-        j.assert_invariant();
-    }
-};
-
-/////////////
-// to_json //
-/////////////
-
-template<typename BasicJsonType, typename T,
-         enable_if_t<std::is_same<T, bool>::value, int> = 0>
-void to_json(BasicJsonType& j, T b) noexcept
-{
-    external_constructor<value_t::boolean>::construct(j, b);
-}
-
-template<typename BasicJsonType, typename CompatibleString,
-         enable_if_t<std::is_constructible<std::string_view, CompatibleString>::value, int> = 0>
-void to_json(BasicJsonType& j, const CompatibleString& s)
-{
-    external_constructor<value_t::string>::construct(j, s);
-}
-
-template<typename BasicJsonType, typename T,
-         enable_if_t<std::is_same<std::string, T>::value, int> = 0>
-void to_json(BasicJsonType& j, T&& s)
-{
-    external_constructor<value_t::string>::construct(j, std::move(s));
-}
-
-template<typename BasicJsonType, typename FloatType,
-         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
-void to_json(BasicJsonType& j, FloatType val) noexcept
-{
-    external_constructor<value_t::number_float>::construct(j, static_cast<double>(val));
-}
-
-template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
-         enable_if_t<is_compatible_integer_type<uint64_t, CompatibleNumberUnsignedType>::value, int> = 0>
-void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
-{
-    external_constructor<value_t::number_unsigned>::construct(j, static_cast<uint64_t>(val));
-}
-
-template<typename BasicJsonType, typename CompatibleNumberIntegerType,
-         enable_if_t<is_compatible_integer_type<int64_t, CompatibleNumberIntegerType>::value, int> = 0>
-void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
-{
-    external_constructor<value_t::number_integer>::construct(j, static_cast<int64_t>(val));
-}
-
-template<typename BasicJsonType, typename EnumType,
-         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
-void to_json(BasicJsonType& j, EnumType e) noexcept
-{
-    using underlying_type = typename std::underlying_type<EnumType>::type;
-    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
-}
-
-template<typename BasicJsonType>
-void to_json(BasicJsonType& j, const std::vector<bool>& e)
-{
-    external_constructor<value_t::array>::construct(j, e);
-}
-
-template<typename BasicJsonType, typename CompatibleArrayType,
-         enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or
-                     std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value,
-                     int> = 0>
-void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
-{
-    external_constructor<value_t::array>::construct(j, arr);
-}
-
-template<typename BasicJsonType>
-void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
-{
-    external_constructor<value_t::array>::construct(j, std::move(arr));
-}
-
-template<typename BasicJsonType, typename CompatibleObjectType,
-         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
-void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
-{
-    external_constructor<value_t::object>::construct(j, obj);
-}
-
-template<typename BasicJsonType>
-void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
-{
-    external_constructor<value_t::object>::construct(j, std::move(obj));
-}
-
-template<typename BasicJsonType, typename T, std::size_t N,
-         enable_if_t<not std::is_constructible<std::string_view, T (&)[N]>::value, int> = 0>
-void to_json(BasicJsonType& j, T (&arr)[N])
-{
-    external_constructor<value_t::array>::construct(j, arr);
-}
-
-template<typename BasicJsonType, typename... Args>
-void to_json(BasicJsonType& j, const std::pair<Args...>& p)
-{
-    j = {p.first, p.second};
-}
-
-template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
-void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, std::index_sequence<Idx...>)
-{
-    j = {std::get<Idx>(t)...};
-}
-
-template<typename BasicJsonType, typename... Args>
-void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
-{
-    to_json_tuple_impl(j, t, std::index_sequence_for<Args...> {});
-}
-
-struct to_json_fn
-{
-  private:
-    template<typename BasicJsonType, typename T>
-    auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
-    -> decltype(to_json(j, std::forward<T>(val)), void())
-    {
-        return to_json(j, std::forward<T>(val));
-    }
-
-    template<typename BasicJsonType, typename T>
-    void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept
-    {
-        static_assert(sizeof(BasicJsonType) == 0,
-                      "could not find to_json() method in T's namespace");
-
-#ifdef _MSC_VER
-        // MSVC does not show a stacktrace for the above assert
-        using decayed = uncvref_t<T>;
-        static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
-                      "forcing MSVC stacktrace to show which T we're talking about.");
-#endif
-    }
-
-  public:
-    template<typename BasicJsonType, typename T>
-    void operator()(BasicJsonType& j, T&& val) const
-    noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
-    {
-        return call(j, std::forward<T>(val), priority_tag<1> {});
-    }
-};
-}
-
-// namespace to hold default `to_json` function
-namespace
-{
-constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
-}
-
-namespace detail
-{
-/*
-@brief an iterator for primitive JSON types
-
-This class models an iterator for primitive JSON types (boolean, number,
-string). It's only purpose is to allow the iterator/const_iterator classes
-to "iterate" over primitive values. Internally, the iterator is modeled by
-a `difference_type` variable. Value begin_value (`0`) models the begin,
-end_value (`1`) models past the end.
-*/
-class primitive_iterator_t
-{
-  private:
-    using difference_type = std::ptrdiff_t;
-    static constexpr difference_type begin_value = 0;
-    static constexpr difference_type end_value = begin_value + 1;
-
-    /// iterator as signed integer type
-    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
-
-  public:
-    constexpr difference_type get_value() const noexcept
-    {
-        return m_it;
-    }
-
-    /// set iterator to a defined beginning
-    void set_begin() noexcept
-    {
-        m_it = begin_value;
-    }
-
-    /// set iterator to a defined past the end
-    void set_end() noexcept
-    {
-        m_it = end_value;
-    }
-
-    /// return whether the iterator can be dereferenced
-    constexpr bool is_begin() const noexcept
-    {
-        return m_it == begin_value;
-    }
-
-    /// return whether the iterator is at end
-    constexpr bool is_end() const noexcept
-    {
-        return m_it == end_value;
-    }
-
-    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it == rhs.m_it;
-    }
-
-    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it < rhs.m_it;
-    }
-
-    primitive_iterator_t operator+(difference_type n) noexcept
-    {
-        auto result = *this;
-        result += n;
-        return result;
-    }
-
-    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it - rhs.m_it;
-    }
-
-    primitive_iterator_t& operator++() noexcept
-    {
-        ++m_it;
-        return *this;
-    }
-
-    primitive_iterator_t const operator++(int) noexcept
-    {
-        auto result = *this;
-        m_it++;
-        return result;
-    }
-
-    primitive_iterator_t& operator--() noexcept
-    {
-        --m_it;
-        return *this;
-    }
-
-    primitive_iterator_t const operator--(int) noexcept
-    {
-        auto result = *this;
-        m_it--;
-        return result;
-    }
-
-    primitive_iterator_t& operator+=(difference_type n) noexcept
-    {
-        m_it += n;
-        return *this;
-    }
-
-    primitive_iterator_t& operator-=(difference_type n) noexcept
-    {
-        m_it -= n;
-        return *this;
-    }
-};
-
-/*!
-@brief an iterator value
-
-@note This structure could easily be a union, but MSVC currently does not allow
-unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
-*/
-template<typename BasicJsonType> struct internal_iterator
-{
-    /// iterator for JSON objects
-    typename BasicJsonType::object_t::iterator object_iterator {};
-    /// iterator for JSON arrays
-    typename BasicJsonType::array_t::iterator array_iterator {};
-    /// generic iterator for all other types
-    primitive_iterator_t primitive_iterator {};
-};
-
-// forward declare, to be able to friend it later on
-template<typename IteratorType> class iteration_proxy;
-
-/*!
-@brief a template for a bidirectional iterator for the @ref json class
-
-This class implements a both iterators (iterator and const_iterator) for the
-@ref json class.
-
-@note An iterator is called *initialized* when a pointer to a JSON value has
-      been set (e.g., by a constructor or a copy assignment). If the iterator is
-      default-constructed, it is *uninitialized* and most methods are undefined.
-      **The library uses assertions to detect calls on uninitialized iterators.**
-
-@requirement The class satisfies the following concept requirements:
--
-[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator):
-  The iterator that can be moved can be moved in both directions (i.e.
-  incremented and decremented).
-
-@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
-       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
-*/
-template<typename BasicJsonType>
-class iter_impl
-{
-    /// allow json to access private members
-    friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
-    friend BasicJsonType;
-    friend iteration_proxy<iter_impl>;
-    friend class ::wpi::JsonTest;
-
-    using object_t = typename BasicJsonType::object_t;
-    using array_t = typename BasicJsonType::array_t;
-    // make sure BasicJsonType is json or const json
-    static_assert(is_json<typename std::remove_const<BasicJsonType>::type>::value,
-                  "iter_impl only accepts (const) json");
-
-  public:
-
-    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
-    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
-    /// A user-defined iterator should provide publicly accessible typedefs named
-    /// iterator_category, value_type, difference_type, pointer, and reference.
-    /// Note that value_type is required to be non-const, even for constant iterators.
-    using iterator_category = std::bidirectional_iterator_tag;
-
-    /// the type of the values when the iterator is dereferenced
-    using value_type = typename BasicJsonType::value_type;
-    /// a type to represent differences between iterators
-    using difference_type = typename BasicJsonType::difference_type;
-    /// defines a pointer to the type iterated over (value_type)
-    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
-          typename BasicJsonType::const_pointer,
-          typename BasicJsonType::pointer>::type;
-    /// defines a reference to the type iterated over (value_type)
-    using reference =
-        typename std::conditional<std::is_const<BasicJsonType>::value,
-        typename BasicJsonType::const_reference,
-        typename BasicJsonType::reference>::type;
-
-    /// default constructor
-    iter_impl() = default;
-
-    /*!
-    @brief constructor for a given JSON instance
-    @param[in] object  pointer to a JSON object for this iterator
-    @pre object != nullptr
-    @post The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    explicit iter_impl(pointer object) noexcept : m_object(object)
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                m_it.object_iterator = typename object_t::iterator();
-                break;
-            }
-
-            case value_t::array:
-            {
-                m_it.array_iterator = typename array_t::iterator();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator = primitive_iterator_t();
-                break;
-            }
-        }
-    }
-
-    /*!
-    @note The conventional copy constructor and copy assignment are implicitly
-          defined. Combined with the following converting constructor and
-          assignment, they support: (1) copy from iterator to iterator, (2)
-          copy from const iterator to const iterator, and (3) conversion from
-          iterator to const iterator. However conversion from const iterator
-          to iterator is not defined.
-    */
-
-    /*!
-    @brief converting constructor
-    @param[in] other  non-const iterator to copy from
-    @note It is not checked whether @a other is initialized.
-    */
-    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
-        : m_object(other.m_object), m_it(other.m_it) {}
-
-    /*!
-    @brief converting assignment
-    @param[in,out] other  non-const iterator to copy from
-    @return const/non-const iterator
-    @note It is not checked whether @a other is initialized.
-    */
-    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
-    {
-        m_object = other.m_object;
-        m_it = other.m_it;
-        return *this;
-    }
-
-  private:
-    /*!
-    @brief set the iterator to the first value
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    void set_begin() noexcept
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                m_it.object_iterator = m_object->m_value.object->begin();
-                break;
-            }
-
-            case value_t::array:
-            {
-                m_it.array_iterator = m_object->m_value.array->begin();
-                break;
-            }
-
-            case value_t::null:
-            {
-                // set to end so begin()==end() is true: null is empty
-                m_it.primitive_iterator.set_end();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator.set_begin();
-                break;
-            }
-        }
-    }
-
-    /*!
-    @brief set the iterator past the last value
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    void set_end() noexcept
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                m_it.object_iterator = m_object->m_value.object->end();
-                break;
-            }
-
-            case value_t::array:
-            {
-                m_it.array_iterator = m_object->m_value.array->end();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator.set_end();
-                break;
-            }
-        }
-    }
-
-  public:
-    /*!
-    @brief return a reference to the value pointed to by the iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference operator*() const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                assert(m_it.object_iterator != m_object->m_value.object->end());
-                return m_it.object_iterator->second;
-            }
-
-            case value_t::array:
-            {
-                assert(m_it.array_iterator != m_object->m_value.array->end());
-                return *m_it.array_iterator;
-            }
-
-            case value_t::null:
-                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
-
-            default:
-            {
-                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
-                {
-                    return *m_object;
-                }
-
-                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
-            }
-        }
-    }
-
-    /*!
-    @brief dereference the iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    pointer operator->() const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                assert(m_it.object_iterator != m_object->m_value.object->end());
-                return &(m_it.object_iterator->second);
-            }
-
-            case value_t::array:
-            {
-                assert(m_it.array_iterator != m_object->m_value.array->end());
-                return &*m_it.array_iterator;
-            }
-
-            default:
-            {
-                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
-                {
-                    return m_object;
-                }
-
-                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
-            }
-        }
-    }
-
-    /*!
-    @brief post-increment (it++)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl const operator++(int)
-    {
-        auto result = *this;
-        ++(*this);
-        return result;
-    }
-
-    /*!
-    @brief pre-increment (++it)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator++()
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                ++m_it.object_iterator;
-                break;
-            }
-
-            case value_t::array:
-            {
-                std::advance(m_it.array_iterator, 1);
-                break;
-            }
-
-            default:
-            {
-                ++m_it.primitive_iterator;
-                break;
-            }
-        }
-
-        return *this;
-    }
-
-    /*!
-    @brief post-decrement (it--)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl const operator--(int)
-    {
-        auto result = *this;
-        --(*this);
-        return result;
-    }
-
-    /*!
-    @brief pre-decrement (--it)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator--()
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-            {
-                --m_it.object_iterator;
-                break;
-            }
-
-            case value_t::array:
-            {
-                std::advance(m_it.array_iterator, -1);
-                break;
-            }
-
-            default:
-            {
-                --m_it.primitive_iterator;
-                break;
-            }
-        }
-
-        return *this;
-    }
-
-    /*!
-    @brief  comparison: equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator==(const iter_impl& other) const
-    {
-        // if objects are not the same, the comparison is undefined
-        if (JSON_UNLIKELY(m_object != other.m_object))
-        {
-            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
-        }
-
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-                return (m_it.object_iterator == other.m_it.object_iterator);
-
-            case value_t::array:
-                return (m_it.array_iterator == other.m_it.array_iterator);
-
-            default:
-                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
-        }
-    }
-
-    /*!
-    @brief  comparison: not equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator!=(const iter_impl& other) const
-    {
-        return not operator==(other);
-    }
-
-    /*!
-    @brief  comparison: smaller
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator<(const iter_impl& other) const
-    {
-        // if objects are not the same, the comparison is undefined
-        if (JSON_UNLIKELY(m_object != other.m_object))
-        {
-            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
-        }
-
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-                JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
-
-            case value_t::array:
-                return (m_it.array_iterator < other.m_it.array_iterator);
-
-            default:
-                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
-        }
-    }
-
-    /*!
-    @brief  comparison: less than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator<=(const iter_impl& other) const
-    {
-        return not other.operator < (*this);
-    }
-
-    /*!
-    @brief  comparison: greater than
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator>(const iter_impl& other) const
-    {
-        return not operator<=(other);
-    }
-
-    /*!
-    @brief  comparison: greater than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator>=(const iter_impl& other) const
-    {
-        return not operator<(other);
-    }
-
-    /*!
-    @brief  add to iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator+=(difference_type i)
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
-
-            case value_t::array:
-            {
-                std::advance(m_it.array_iterator, i);
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator += i;
-                break;
-            }
-        }
-
-        return *this;
-    }
-
-    /*!
-    @brief  subtract from iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator-=(difference_type i)
-    {
-        return operator+=(-i);
-    }
-
-    /*!
-    @brief  add to iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator+(difference_type i) const
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
-
-    /*!
-    @brief  addition of distance and iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    friend iter_impl operator+(difference_type i, const iter_impl& it)
-    {
-        auto result = it;
-        result += i;
-        return result;
-    }
-
-    /*!
-    @brief  subtract from iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator-(difference_type i) const
-    {
-        auto result = *this;
-        result -= i;
-        return result;
-    }
-
-    /*!
-    @brief  return difference
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    difference_type operator-(const iter_impl& other) const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
-
-            case value_t::array:
-                return m_it.array_iterator - other.m_it.array_iterator;
-
-            default:
-                return m_it.primitive_iterator - other.m_it.primitive_iterator;
-        }
-    }
-
-    /*!
-    @brief  access to successor
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference operator[](difference_type n) const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case value_t::object:
-                JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
-
-            case value_t::array:
-                return *std::next(m_it.array_iterator, n);
-
-            case value_t::null:
-                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
-
-            default:
-            {
-                if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))
-                {
-                    return *m_object;
-                }
-
-                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
-            }
-        }
-    }
-
-    /*!
-    @brief  return the key of an object iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    std::string_view key() const
-    {
-        assert(m_object != nullptr);
-
-        if (JSON_LIKELY(m_object->is_object()))
-        {
-            return m_it.object_iterator->first();
-        }
-
-        JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
-    }
-
-    /*!
-    @brief  return the value of an iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference value() const
-    {
-        return operator*();
-    }
-
-  private:
-    /// associated JSON instance
-    pointer m_object = nullptr;
-    /// the actual iterator of the associated instance
-    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;
-};
-
-/// proxy class for the items() function
-template<typename IteratorType> class iteration_proxy
-{
-  private:
-    /// helper class for iteration
-    class iteration_proxy_internal
-    {
-      private:
-        /// the iterator
-        IteratorType anchor;
-        /// an index for arrays (used to create key names)
-        std::size_t array_index = 0;
-
-      public:
-        explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
-
-        /// dereference operator (needed for range-based for)
-        iteration_proxy_internal& operator*()
-        {
-            return *this;
-        }
-
-        /// increment operator (needed for range-based for)
-        iteration_proxy_internal& operator++()
-        {
-            ++anchor;
-            ++array_index;
-
-            return *this;
-        }
-
-        /// inequality operator (needed for range-based for)
-        bool operator!=(const iteration_proxy_internal& o) const noexcept
-        {
-            return anchor != o.anchor;
-        }
-
-        /// return key of the iterator
-        std::string key() const
-        {
-            assert(anchor.m_object != nullptr);
-
-            switch (anchor.m_object->type())
-            {
-                // use integer array index as key
-                case value_t::array:
-                    return std::to_string(array_index);
-
-                // use key from the object
-                case value_t::object:
-                    return std::string{anchor.key()};
-
-                // use an empty key for all primitive types
-                default:
-                    return "";
-            }
-        }
-
-        /// return value of the iterator
-        typename IteratorType::reference value() const
-        {
-            return anchor.value();
-        }
-    };
-
-    /// the container to iterate
-    typename IteratorType::reference container;
-
-  public:
-    /// construct iteration proxy from a container
-    explicit iteration_proxy(typename IteratorType::reference cont) noexcept
-        : container(cont) {}
-
-    /// return iterator begin (needed for range-based for)
-    iteration_proxy_internal begin() noexcept
-    {
-        return iteration_proxy_internal(container.begin());
-    }
-
-    /// return iterator end (needed for range-based for)
-    iteration_proxy_internal end() noexcept
-    {
-        return iteration_proxy_internal(container.end());
-    }
-};
-
-//////////////////////
-// reverse_iterator //
-//////////////////////
-
-/*!
-@brief a template for a reverse iterator class
-
-@tparam Base the base iterator type to reverse. Valid types are @ref
-iterator (to create @ref reverse_iterator) and @ref const_iterator (to
-create @ref const_reverse_iterator).
-
-@requirement The class satisfies the following concept requirements:
--
-[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator):
-  The iterator that can be moved can be moved in both directions (i.e.
-  incremented and decremented).
-- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
-  It is possible to write to the pointed-to element (only if @a Base is
-  @ref iterator).
-
-@since version 1.0.0
-*/
-template<typename Base>
-class json_reverse_iterator : public std::reverse_iterator<Base>
-{
-  public:
-    using difference_type = std::ptrdiff_t;
-    /// shortcut to the reverse iterator adapter
-    using base_iterator = std::reverse_iterator<Base>;
-    /// the reference type for the pointed-to element
-    using reference = typename Base::reference;
-
-    /// create reverse iterator from iterator
-    json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
-        : base_iterator(it) {}
-
-    /// create reverse iterator from base class
-    json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
-
-    /// post-increment (it++)
-    json_reverse_iterator const operator++(int)
-    {
-        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
-    }
-
-    /// pre-increment (++it)
-    json_reverse_iterator& operator++()
-    {
-        return static_cast<json_reverse_iterator&>(base_iterator::operator++());
-    }
-
-    /// post-decrement (it--)
-    json_reverse_iterator const operator--(int)
-    {
-        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
-    }
-
-    /// pre-decrement (--it)
-    json_reverse_iterator& operator--()
-    {
-        return static_cast<json_reverse_iterator&>(base_iterator::operator--());
-    }
-
-    /// add to iterator
-    json_reverse_iterator& operator+=(difference_type i)
-    {
-        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
-    }
-
-    /// add to iterator
-    json_reverse_iterator operator+(difference_type i) const
-    {
-        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
-    }
-
-    /// subtract from iterator
-    json_reverse_iterator operator-(difference_type i) const
-    {
-        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
-    }
-
-    /// return difference
-    difference_type operator-(const json_reverse_iterator& other) const
-    {
-        return base_iterator(*this) - base_iterator(other);
-    }
-
-    /// access to successor
-    reference operator[](difference_type n) const
-    {
-        return *(this->operator+(n));
-    }
-
-    /// return the key of an object iterator
-    auto key() const -> decltype(std::declval<Base>().key())
-    {
-        auto it = --this->base();
-        return it.key();
-    }
-
-    /// return the value of an iterator
-    reference value() const
-    {
-        auto it = --this->base();
-        return it.operator * ();
-    }
-};
-
-template<typename BasicJsonType>
-class json_ref
-{
-  public:
-    using value_type = BasicJsonType;
-
-    json_ref(value_type&& value)
-        : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)
-    {}
-
-    json_ref(const value_type& value)
-        : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)
-    {}
-
-    json_ref(std::initializer_list<json_ref> init)
-        : owned_value(init), value_ref(&owned_value), is_rvalue(true)
-    {}
-
-    template<class... Args>
-    json_ref(Args&& ... args)
-        : owned_value(std::forward<Args>(args)...), value_ref(&owned_value), is_rvalue(true)
-    {}
-
-    // class should be movable only
-    json_ref(json_ref&&) = default;
-    json_ref(const json_ref&) = delete;
-    json_ref& operator=(const json_ref&) = delete;
-
-    value_type moved_or_copied() const
-    {
-        if (is_rvalue)
-        {
-            return std::move(*value_ref);
-        }
-        return *value_ref;
-    }
-
-    value_type const& operator*() const
-    {
-        return *static_cast<value_type const*>(value_ref);
-    }
-
-    value_type const* operator->() const
-    {
-        return static_cast<value_type const*>(value_ref);
-    }
-
-  private:
-    mutable value_type owned_value = nullptr;
-    value_type* value_ref = nullptr;
-    const bool is_rvalue;
-};
-}  // namespace detail
-
-class json_pointer
-{
-    // allow json to access private members
-    friend class json;
-    friend class JsonTest;
-
-  public:
-    /*!
-    @brief create JSON pointer
-
-    Create a JSON pointer according to the syntax described in
-    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
-
-    @param[in] s  string representing the JSON pointer; if omitted, the empty
-                  string is assumed which references the whole JSON value
-
-    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does
-                           not begin with a slash (`/`); see example below
-
-    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is
-    not followed by `0` (representing `~`) or `1` (representing `/`); see
-    example below
-
-    @liveexample{The example shows the construction several valid JSON pointers
-    as well as the exceptional behavior.,json_pointer}
-
-    @since version 2.0.0
-    */
-    explicit json_pointer(std::string_view s = {})
-        : reference_tokens(split(s))
-    {}
-
-    /*!
-    @brief return a string representation of the JSON pointer
-
-    @invariant For each JSON pointer `ptr`, it holds:
-    @code {.cpp}
-    ptr == json_pointer(ptr.to_string());
-    @endcode
-
-    @return a string representation of the JSON pointer
-
-    @liveexample{The example shows the result of `to_string`.,
-    json_pointer__to_string}
-
-    @since version 2.0.0
-    */
-    std::string to_string() const noexcept;
-
-    /// @copydoc to_string()
-    operator std::string() const
-    {
-        return to_string();
-    }
-
-    /*!
-    @param[in] s  reference token to be converted into an array index
-
-    @return integer representation of @a s
-
-    @throw out_of_range.404 if string @a s could not be converted to an integer
-    */
-    static int array_index(std::string_view s);
-
-  private:
-    /*!
-    @brief remove and return last reference pointer
-    @throw out_of_range.405 if JSON pointer has no parent
-    */
-    std::string pop_back()
-    {
-        if (JSON_UNLIKELY(is_root()))
-        {
-            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
-        }
-
-        auto last = reference_tokens.back();
-        reference_tokens.pop_back();
-        return last;
-    }
-
-    /// return whether pointer points to the root document
-    bool is_root() const
-    {
-        return reference_tokens.empty();
-    }
-
-    json_pointer top() const
-    {
-        if (JSON_UNLIKELY(is_root()))
-        {
-            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
-        }
-
-        json_pointer result = *this;
-        result.reference_tokens = {reference_tokens[0]};
-        return result;
-    }
-
-    /*!
-    @brief create and return a reference to the pointed to value
-
-    @complexity Linear in the number of reference tokens.
-
-    @throw parse_error.109 if array index is not a number
-    @throw type_error.313 if value cannot be unflattened
-    */
-    json& get_and_create(json& j) const;
-
-    /*!
-    @brief return a reference to the pointed to value
-
-    @note This version does not throw if a value is not present, but tries to
-          create nested values instead. For instance, calling this function
-          with pointer `"/this/that"` on a null value is equivalent to calling
-          `operator[]("this").operator[]("that")` on that value, effectively
-          changing the null value to an object.
-
-    @param[in] ptr  a JSON value
-
-    @return reference to the JSON value pointed to by the JSON pointer
-
-    @complexity Linear in the length of the JSON pointer.
-
-    @throw parse_error.106   if an array index begins with '0'
-    @throw parse_error.109   if an array index was not a number
-    @throw out_of_range.404  if the JSON pointer can not be resolved
-    */
-    json& get_unchecked(json* ptr) const;
-
-    /*!
-    @throw parse_error.106   if an array index begins with '0'
-    @throw parse_error.109   if an array index was not a number
-    @throw out_of_range.402  if the array index '-' is used
-    @throw out_of_range.404  if the JSON pointer can not be resolved
-    */
-    json& get_checked(json* ptr) const;
-
-    /*!
-    @brief return a const reference to the pointed to value
-
-    @param[in] ptr  a JSON value
-
-    @return const reference to the JSON value pointed to by the JSON
-    pointer
-
-    @throw parse_error.106   if an array index begins with '0'
-    @throw parse_error.109   if an array index was not a number
-    @throw out_of_range.402  if the array index '-' is used
-    @throw out_of_range.404  if the JSON pointer can not be resolved
-    */
-    const json& get_unchecked(const json* ptr) const;
-
-    /*!
-    @throw parse_error.106   if an array index begins with '0'
-    @throw parse_error.109   if an array index was not a number
-    @throw out_of_range.402  if the array index '-' is used
-    @throw out_of_range.404  if the JSON pointer can not be resolved
-    */
-    const json& get_checked(const json* ptr) const;
-
-    /*!
-    @brief split the string input to reference tokens
-
-    @note This function is only called by the json_pointer constructor.
-          All exceptions below are documented there.
-
-    @throw parse_error.107  if the pointer is not empty or begins with '/'
-    @throw parse_error.108  if character '~' is not followed by '0' or '1'
-    */
-    static std::vector<std::string> split(std::string_view reference_string);
-
-    /*!
-    @brief replace all occurrences of a substring by another string
-
-    @param[in,out] s  the string to manipulate; changed so that all
-                   occurrences of @a f are replaced with @a t
-    @param[in]     f  the substring to replace with @a t
-    @param[in]     t  the string to replace @a f
-
-    @pre The search string @a f must not be empty. **This precondition is
-    enforced with an assertion.**
-
-    @since version 2.0.0
-    */
-    static void replace_substring(std::string& s, const std::string& f,
-                                  const std::string& t);
-
-    /// escape "~"" to "~0" and "/" to "~1"
-    static std::string escape(std::string s);
-
-    /// unescape "~1" to tilde and "~0" to slash (order is important!)
-    static void unescape(std::string& s);
-
-    /*!
-    @param[in] reference_string  the reference string to the current value
-    @param[in] value             the value to consider
-    @param[in,out] result        the result object to insert values to
-
-    @note Empty objects or arrays are flattened to `null`.
-    */
-    static void flatten(std::string_view reference_string,
-                        const json& value,
-                        json& result);
-
-    /*!
-    @param[in] value  flattened JSON
-
-    @return unflattened JSON
-
-    @throw parse_error.109 if array index is not a number
-    @throw type_error.314  if value is not an object
-    @throw type_error.315  if object values are not primitive
-    @throw type_error.313  if value cannot be unflattened
-    */
-    static json
-    unflatten(const json& value);
-
-    friend bool operator==(json_pointer const& lhs,
-                           json_pointer const& rhs) noexcept
-    {
-        return (lhs.reference_tokens == rhs.reference_tokens);
-    }
-
-    friend bool operator!=(json_pointer const& lhs,
-                           json_pointer const& rhs) noexcept
-    {
-        return not (lhs == rhs);
-    }
-
-    /// the reference tokens
-    std::vector<std::string> reference_tokens;
-};
-
-template<typename, typename>
-struct adl_serializer
-{
-    /*!
-    @brief convert a JSON value to any value type
-
-    This function is usually called by the `get()` function of the
-    @ref json class (either explicit or via conversion operators).
-
-    @param[in] j         JSON value to read from
-    @param[in,out] val  value to write to
-    */
-    template<typename BasicJsonType, typename ValueType>
-    static void from_json(BasicJsonType&& j, ValueType& val) noexcept(
-        noexcept(::wpi::from_json(std::forward<BasicJsonType>(j), val)))
-    {
-        ::wpi::from_json(std::forward<BasicJsonType>(j), val);
-    }
-
-    /*!
-    @brief convert any value type to a JSON value
-
-    This function is usually called by the constructors of the @ref json
-    class.
-
-    @param[in,out] j  JSON value to write to
-    @param[in] val     value to read from
-    */
-    template<typename BasicJsonType, typename ValueType>
-    static void to_json(BasicJsonType& j, ValueType&& val) noexcept(
-        noexcept(::wpi::to_json(j, std::forward<ValueType>(val))))
-    {
-        ::wpi::to_json(j, std::forward<ValueType>(val));
-    }
-};
+WPI_JSON_NAMESPACE_BEGIN
 
 /*!
 @brief a class to store JSON values
 
-@requirement The class satisfies the following concept requirements:
-- Basic
- - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
-   JSON values can be default constructed. The result will be a JSON null
-   value.
- - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
-   A JSON value can be constructed from an rvalue argument.
- - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
-   A JSON value can be copy-constructed from an lvalue expression.
- - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
-   A JSON value van be assigned from an rvalue argument.
- - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
-   A JSON value can be copy-assigned from an lvalue expression.
- - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
-   JSON values can be destructed.
-- Layout
- - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
-   JSON values have
-   [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
-   All non-static data members are private and standard layout types, the
-   class has no virtual functions or (virtual) base classes.
-- Library-wide
- - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
-   JSON values can be compared with `==`, see @ref
-   operator==(const_reference,const_reference).
- - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
-   JSON values can be compared with `<`, see @ref
-   operator<(const_reference,const_reference).
- - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
-   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
-   other compatible types, using unqualified function call @ref swap().
- - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
-   JSON values can be compared against `std::nullptr_t` objects which are used
-   to model the `null` value.
-- Container
- - [Container](http://en.cppreference.com/w/cpp/concept/Container):
-   JSON values can be used like STL containers and provide iterator access.
- - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
-   JSON values can be used like STL containers and provide reverse iterator
-   access.
-
+@internal
 @invariant The member variables @a m_value and @a m_type have the following
 relationship:
 - If `m_type == value_t::object`, then `m_value.object != nullptr`.
@@ -2640,30 +84,59 @@
 - If `m_type == value_t::string`, then `m_value.string != nullptr`.
 The invariants are checked by member function assert_invariant().
 
-@internal
-@note ObjectType trick from http://stackoverflow.com/a/9860911
+@note ObjectType trick from https://stackoverflow.com/a/9860911
 @endinternal
 
-@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
-Format](http://rfc7159.net/rfc7159)
-
 @since version 1.0.0
 
 @nosubgrouping
 */
-class json
+WPI_BASIC_JSON_TPL_DECLARATION
+class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
 {
   private:
     template<detail::value_t> friend struct detail::external_constructor;
-    friend ::wpi::json_pointer;
+
+    template<typename>
+    friend class ::wpi::json_pointer;
+    // can be restored when json_pointer backwards compatibility is removed
+    // friend ::wpi::json_pointer<StringType>;
+
+    template<typename BasicJsonType, typename InputType>
+    friend class ::wpi::detail::parser;
+    friend ::wpi::detail::serializer<basic_json>;
     template<typename BasicJsonType>
     friend class ::wpi::detail::iter_impl;
-    friend class JsonTest;
+    template<typename BasicJsonType, typename CharType>
+    friend class ::wpi::detail::binary_writer;
+    template<typename BasicJsonType, typename InputType, typename SAX>
+    friend class ::wpi::detail::binary_reader;
+    template<typename BasicJsonType>
+    friend class ::wpi::detail::json_sax_dom_parser;
+    template<typename BasicJsonType>
+    friend class ::wpi::detail::json_sax_dom_callback_parser;
+    friend class ::wpi::detail::exception;
 
     /// workaround type for MSVC
-    using json_t = json;
+    using basic_json_t = WPI_BASIC_JSON_TPL;
 
+  JSON_PRIVATE_UNLESS_TESTED:
     // convenience aliases for types residing in namespace detail;
+    using lexer = ::wpi::detail::lexer_base<basic_json>;
+
+    template<typename InputAdapterType>
+    static ::wpi::detail::parser<basic_json, InputAdapterType> parser(
+        InputAdapterType adapter,
+        detail::parser_callback_t<basic_json>cb = nullptr,
+        const bool allow_exceptions = true,
+        const bool ignore_comments = false
+    )
+    {
+        return ::wpi::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
+                std::move(cb), allow_exceptions, ignore_comments);
+    }
+
+  private:
     using primitive_iterator_t = ::wpi::detail::primitive_iterator_t;
     template<typename BasicJsonType>
     using internal_iterator = ::wpi::detail::internal_iterator<BasicJsonType>;
@@ -2673,21 +146,31 @@
     using iteration_proxy = ::wpi::detail::iteration_proxy<Iterator>;
     template<typename Base> using json_reverse_iterator = ::wpi::detail::json_reverse_iterator<Base>;
 
-    class binary_reader;
-    class binary_writer;
-    class lexer;
-    class parser;
+    template<typename CharType>
+    using output_adapter_t = ::wpi::detail::output_adapter_t<CharType>;
+
+    template<typename InputType>
+    using binary_reader = ::wpi::detail::binary_reader<basic_json, InputType>;
+    template<typename CharType> using binary_writer = ::wpi::detail::binary_writer<basic_json, CharType>;
 
   public:
-    class serializer;
+    using serializer = ::wpi::detail::serializer<basic_json>;
 
     using value_t = detail::value_t;
-    /// @copydoc wpi::json_pointer
-    using json_pointer = ::wpi::json_pointer;
+    /// JSON Pointer, see @ref wpi::json_pointer
+    using json_pointer = ::wpi::json_pointer<StringType>;
     template<typename T, typename SFINAE>
-    using json_serializer = adl_serializer<T, SFINAE>;
-    /// helper type for initializer lists of json values
-    using initializer_list_t = std::initializer_list<detail::json_ref<json>>;
+    using json_serializer = JSONSerializer<T, SFINAE>;
+    /// how to treat decoding errors
+    using error_handler_t = detail::error_handler_t;
+    /// how to treat CBOR tags
+    using cbor_tag_handler_t = detail::cbor_tag_handler_t;
+    /// helper type for initializer lists of basic_json values
+    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
+
+    using input_format_t = detail::input_format_t;
+    /// SAX interface type, see @ref wpi::json_sax
+    using json_sax_t = json_sax<basic_json>;
 
     ////////////////
     // exceptions //
@@ -2697,17 +180,11 @@
     /// Classes to implement user-defined exceptions.
     /// @{
 
-    /// @copydoc detail::exception
     using exception = detail::exception;
-    /// @copydoc detail::parse_error
     using parse_error = detail::parse_error;
-    /// @copydoc detail::invalid_iterator
     using invalid_iterator = detail::invalid_iterator;
-    /// @copydoc detail::type_error
     using type_error = detail::type_error;
-    /// @copydoc detail::out_of_range
     using out_of_range = detail::out_of_range;
-    /// @copydoc detail::other_error
     using other_error = detail::other_error;
 
     /// @}
@@ -2718,12 +195,12 @@
     /////////////////////
 
     /// @name container types
-    /// The canonic container types to use @ref json like any other STL
+    /// The canonic container types to use @ref basic_json like any other STL
     /// container.
     /// @{
 
-    /// the type of elements in a json container
-    using value_type = json;
+    /// the type of elements in a basic_json container
+    using value_type = basic_json;
 
     /// the type of an element reference
     using reference = value_type&;
@@ -2736,60 +213,97 @@
     using size_type = std::size_t;
 
     /// the allocator type
-    using allocator_type = std::allocator<json>;
+    using allocator_type = AllocatorType<basic_json>;
 
     /// the type of an element pointer
-    using pointer = json*;
+    using pointer = typename std::allocator_traits<allocator_type>::pointer;
     /// the type of an element const pointer
-    using const_pointer = const json*;
+    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
 
-    /// an iterator for a json container
-    using iterator = iter_impl<json>;
-    /// a const iterator for a json container
-    using const_iterator = iter_impl<const json>;
-    /// a reverse iterator for a json container
-    using reverse_iterator = json_reverse_iterator<typename json::iterator>;
-    /// a const reverse iterator for a json container
-    using const_reverse_iterator = json_reverse_iterator<typename json::const_iterator>;
+    /// an iterator for a basic_json container
+    using iterator = iter_impl<basic_json>;
+    /// a const iterator for a basic_json container
+    using const_iterator = iter_impl<const basic_json>;
+    /// a reverse iterator for a basic_json container
+    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
+    /// a const reverse iterator for a basic_json container
+    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
 
     /// @}
 
 
-    /*!
-    @brief returns the allocator associated with the container
-    */
+    /// @brief returns the allocator associated with the container
+    /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
     static allocator_type get_allocator()
     {
         return allocator_type();
     }
 
-    /*!
-    @brief returns version information on the library
+    /// @brief returns version information on the library
+    /// @sa https://json.nlohmann.me/api/basic_json/meta/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json meta()
+    {
+        basic_json result;
 
-    This function returns a JSON object with information about the library,
-    including the version number and information on the platform and compiler.
+        result["copyright"] = "(C) 2013-2022 Niels Lohmann";
+        result["name"] = "JSON for Modern C++";
+        result["url"] = "https://github.com/nlohmann/json";
+        result["version"]["string"] =
+            detail::concat(std::to_string(WPI_JSON_VERSION_MAJOR), '.',
+                           std::to_string(WPI_JSON_VERSION_MINOR), '.',
+                           std::to_string(WPI_JSON_VERSION_PATCH));
+        result["version"]["major"] = WPI_JSON_VERSION_MAJOR;
+        result["version"]["minor"] = WPI_JSON_VERSION_MINOR;
+        result["version"]["patch"] = WPI_JSON_VERSION_PATCH;
 
-    @return JSON object holding version information
-    key         | description
-    ----------- | ---------------
-    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).
-    `copyright` | The copyright line for the library as string.
-    `name`      | The name of the library as string.
-    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.
-    `url`       | The URL of the project as string.
-    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).
+#ifdef _WIN32
+        result["platform"] = "win32";
+#elif defined __linux__
+        result["platform"] = "linux";
+#elif defined __APPLE__
+        result["platform"] = "apple";
+#elif defined __unix__
+        result["platform"] = "unix";
+#else
+        result["platform"] = "unknown";
+#endif
 
-    @liveexample{The following code shows an example output of the `meta()`
-    function.,meta}
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+        result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
+#elif defined(__clang__)
+        result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
+#elif defined(__GNUC__) || defined(__GNUG__)
+        result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
+                    std::to_string(__GNUC__), '.',
+                    std::to_string(__GNUC_MINOR__), '.',
+                    std::to_string(__GNUC_PATCHLEVEL__))
+            }
+        };
+#elif defined(__HP_cc) || defined(__HP_aCC)
+        result["compiler"] = "hp"
+#elif defined(__IBMCPP__)
+        result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
+#elif defined(_MSC_VER)
+        result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
+#elif defined(__PGI)
+        result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
+#elif defined(__SUNPRO_CC)
+        result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
+#else
+        result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
+#endif
 
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
 
-    @complexity Constant.
-
-    @since 2.1.0
-    */
-    static json meta();
+#if defined(_MSVC_LANG)
+        result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
+#elif defined(__cplusplus)
+        result["compiler"]["c++"] = std::to_string(__cplusplus);
+#else
+        result["compiler"]["c++"] = "unknown";
+#endif
+        return result;
+    }
 
 
     ///////////////////////////
@@ -2798,96 +312,60 @@
 
     /// @name JSON value data types
     /// The data types to store a JSON value. These types are derived from
-    /// the template arguments passed to class @ref json.
+    /// the template arguments passed to class @ref basic_json.
     /// @{
 
-    // Use transparent comparator if possible, combined with perfect forwarding
-    // on find() and count() calls prevents unnecessary string construction.
-    using object_comparator_t = std::less<>;
+    /// @brief default object key comparator type
+    /// The actual object key comparator type (@ref object_comparator_t) may be
+    /// different.
+    /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
+#if defined(JSON_HAS_CPP_14)
+    // use of transparent comparator avoids unnecessary repeated construction of temporaries
+    // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
+    using default_object_comparator_t = std::less<>;
+#else
+    using default_object_comparator_t = std::less<StringType>;
+#endif
 
-    /*!
-    @brief a type for an object
+    /// @brief a type for an object
+    /// @sa https://json.nlohmann.me/api/basic_json/object_t/
+    using object_t = ObjectType<StringType,
+          basic_json,
+          default_object_comparator_t,
+          AllocatorType<std::pair<const StringType,
+          basic_json>>>;
 
-    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
-    > An object is an unordered collection of zero or more name/value pairs,
-    > where a name is a string and a value is a string, number, boolean, null,
-    > object, or array.
+    /// @brief a type for an array
+    /// @sa https://json.nlohmann.me/api/basic_json/array_t/
+    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
 
-    #### Behavior
+    /// @brief a type for a string
+    /// @sa https://json.nlohmann.me/api/basic_json/string_t/
+    using string_t = StringType;
 
-    The choice of @a object_t influences the behavior of the JSON class. With
-    the default type, objects have the following behavior:
+    /// @brief a type for a boolean
+    /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/
+    using boolean_t = BooleanType;
 
-    - When all names are unique, objects will be interoperable in the sense
-      that all software implementations receiving that object will agree on
-      the name-value mappings.
-    - When the names within an object are not unique, it is unspecified which
-      one of the values for a given key will be chosen. For instance,
-      `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or
-      `{"key": 2}`.
-    - Internally, name/value pairs are stored in lexicographical order of the
-      names. Objects will also be serialized (see @ref dump) in this order.
-      For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
-      and serialized as `{"a": 2, "b": 1}`.
-    - When comparing objects, the order of the name/value pairs is irrelevant.
-      This makes objects interoperable in the sense that they will not be
-      affected by these differences. For instance, `{"b": 1, "a": 2}` and
-      `{"a": 2, "b": 1}` will be treated as equal.
+    /// @brief a type for a number (integer)
+    /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/
+    using number_integer_t = NumberIntegerType;
 
-    #### Limits
+    /// @brief a type for a number (unsigned)
+    /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/
+    using number_unsigned_t = NumberUnsignedType;
 
-    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
-    > An implementation may set limits on the maximum depth of nesting.
+    /// @brief a type for a number (floating-point)
+    /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/
+    using number_float_t = NumberFloatType;
 
-    In this class, the object's limit of nesting is not explicitly constrained.
-    However, a maximum depth of nesting may be introduced by the compiler or
-    runtime environment. A theoretical limit can be queried by calling the
-    @ref max_size function of a JSON object.
+    /// @brief a type for a packed binary type
+    /// @sa https://json.nlohmann.me/api/basic_json/binary_t/
+    using binary_t = wpi::byte_container_with_subtype<BinaryType>;
 
-    #### Storage
-
-    Objects are stored as pointers in a @ref json type. That is, for any
-    access to object values, a pointer of type `object_t*` must be
-    dereferenced.
-
-    @since version 1.0.0
-
-    @note The order name/value pairs are added to the object is *not*
-    preserved by the library. Therefore, iterating an object may return
-    name/value pairs in a different order than they were originally stored. In
-    fact, keys will be traversed in alphabetical order as `std::map` with
-    `std::less` is used by default. Please note this behavior conforms to [RFC
-    7159](http://rfc7159.net/rfc7159), because any order implements the
-    specified "unordered" nature of JSON objects.
-    */
-    using object_t = StringMap<json>;
-
-    /*!
-    @brief a type for an array
-
-    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
-    > An array is an ordered sequence of zero or more values.
-
-    #### Limits
-
-    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
-    > An implementation may set limits on the maximum depth of nesting.
-
-    In this class, the array's limit of nesting is not explicitly constrained.
-    However, a maximum depth of nesting may be introduced by the compiler or
-    runtime environment. A theoretical limit can be queried by calling the
-    @ref max_size function of a JSON array.
-
-    #### Storage
-
-    Arrays are stored as pointers in a @ref json type. That is, for any
-    access to array values, a pointer of type `array_t*` must be dereferenced.
-
-    @sa @ref object_t -- type for an object value
-
-    @since version 1.0.0
-    */
-    using array_t = std::vector<json>;
+    /// @brief object key comparator type
+    /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
+    using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
 
     /// @}
 
@@ -2895,30 +373,31 @@
 
     /// helper for exception-safe object creation
     template<typename T, typename... Args>
+    JSON_HEDLEY_RETURNS_NON_NULL
     static T* create(Args&& ... args)
     {
-        std::allocator<T> alloc;
+        AllocatorType<T> alloc;
+        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
 
-		using AllocatorTraits = std::allocator_traits<std::allocator<T>>;
-
-		auto deleter = [&](T * object)
-		{
-			AllocatorTraits::deallocate(alloc, object, 1);
-		};
-		std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
-		AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
-        assert(object != nullptr);
-        return object.release();
+        auto deleter = [&](T * obj)
+        {
+            AllocatorTraits::deallocate(alloc, obj, 1);
+        };
+        std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
+        AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
+        JSON_ASSERT(obj != nullptr);
+        return obj.release();
     }
 
     ////////////////////////
     // JSON value storage //
     ////////////////////////
 
+  JSON_PRIVATE_UNLESS_TESTED:
     /*!
     @brief a JSON value
 
-    The actual storage for a JSON value of the @ref json class. This
+    The actual storage for a JSON value of the @ref basic_json class. This
     union combines the different storage types for the JSON value types
     defined in @ref value_t.
 
@@ -2926,11 +405,12 @@
     --------- | --------------- | ------------------------
     object    | object          | pointer to @ref object_t
     array     | array           | pointer to @ref array_t
-    string    | string          | pointer to std::string
-    boolean   | boolean         | bool
-    number    | number_integer  | int64_t
-    number    | number_unsigned | uint64_t
-    number    | number_float    | double
+    string    | string          | pointer to @ref string_t
+    boolean   | boolean         | @ref boolean_t
+    number    | number_integer  | @ref number_integer_t
+    number    | number_unsigned | @ref number_unsigned_t
+    number    | number_float    | @ref number_float_t
+    binary    | binary          | pointer to @ref binary_t
     null      | null            | *no value is stored*
 
     @note Variable-length types (objects, arrays, and strings) are stored as
@@ -2946,74 +426,230 @@
         /// array (stored with pointer to save storage)
         array_t* array;
         /// string (stored with pointer to save storage)
-        std::string* string;
+        string_t* string;
+        /// binary (stored with pointer to save storage)
+        binary_t* binary;
         /// boolean
-        bool boolean;
+        boolean_t boolean;
         /// number (integer)
-        int64_t number_integer;
+        number_integer_t number_integer;
         /// number (unsigned integer)
-        uint64_t number_unsigned;
+        number_unsigned_t number_unsigned;
         /// number (floating-point)
-        double number_float;
+        number_float_t number_float;
 
         /// default constructor (for null values)
         json_value() = default;
         /// constructor for booleans
-        json_value(bool v) noexcept : boolean(v) {}
+        json_value(boolean_t v) noexcept : boolean(v) {}
         /// constructor for numbers (integer)
-        json_value(int64_t v) noexcept : number_integer(v) {}
+        json_value(number_integer_t v) noexcept : number_integer(v) {}
         /// constructor for numbers (unsigned)
-        json_value(uint64_t v) noexcept : number_unsigned(v) {}
+        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
         /// constructor for numbers (floating-point)
-        json_value(double v) noexcept : number_float(v) {}
+        json_value(number_float_t v) noexcept : number_float(v) {}
         /// constructor for empty values of a given type
-        json_value(value_t t);
-
-        /// constructor for strings
-        json_value(std::string_view value)
+        json_value(value_t t)
         {
-            string = create<std::string>(value);
+            switch (t)
+            {
+                case value_t::object:
+                {
+                    object = create<object_t>();
+                    break;
+                }
+
+                case value_t::array:
+                {
+                    array = create<array_t>();
+                    break;
+                }
+
+                case value_t::string:
+                {
+                    string = create<string_t>("");
+                    break;
+                }
+
+                case value_t::binary:
+                {
+                    binary = create<binary_t>();
+                    break;
+                }
+
+                case value_t::boolean:
+                {
+                    boolean = static_cast<boolean_t>(false);
+                    break;
+                }
+
+                case value_t::number_integer:
+                {
+                    number_integer = static_cast<number_integer_t>(0);
+                    break;
+                }
+
+                case value_t::number_unsigned:
+                {
+                    number_unsigned = static_cast<number_unsigned_t>(0);
+                    break;
+                }
+
+                case value_t::number_float:
+                {
+                    number_float = static_cast<number_float_t>(0.0);
+                    break;
+                }
+
+                case value_t::null:
+                {
+                    object = nullptr;  // silence warning, see #821
+                    break;
+                }
+
+                case value_t::discarded:
+                default:
+                {
+                    object = nullptr;  // silence warning, see #821
+                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
+                    {
+                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.2", nullptr)); // LCOV_EXCL_LINE
+                    }
+                    break;
+                }
+            }
         }
 
         /// constructor for strings
-        json_value(const std::string& value)
-        {
-            string = create<std::string>(value);
-        }
+        json_value(const string_t& value) : string(create<string_t>(value)) {}
 
         /// constructor for rvalue strings
-        json_value(std::string&& value)
-        {
-            string = create<std::string>(std::move(value));
-        }
+        json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
 
         /// constructor for objects
-        json_value(const object_t& value)
-        {
-            object = create<object_t>(value);
-        }
+        json_value(const object_t& value) : object(create<object_t>(value)) {}
 
         /// constructor for rvalue objects
-        json_value(object_t&& value)
-        {
-            object = create<object_t>(std::move(value));
-        }
+        json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
 
         /// constructor for arrays
-        json_value(const array_t& value)
-        {
-            array = create<array_t>(value);
-        }
+        json_value(const array_t& value) : array(create<array_t>(value)) {}
 
         /// constructor for rvalue arrays
-        json_value(array_t&& value)
-        {
-            array = create<array_t>(std::move(value));
-        }
+        json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
 
-        void destroy(value_t t) noexcept;
+        /// constructor for binary arrays
+        json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
+
+        /// constructor for rvalue binary arrays
+        json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
+
+        /// constructor for binary arrays (internal type)
+        json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
+
+        /// constructor for rvalue binary arrays (internal type)
+        json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
+
+        void destroy(value_t t)
+        {
+            if (t == value_t::array || t == value_t::object)
+            {
+                // flatten the current json_value to a heap-allocated stack
+                std::vector<basic_json> stack;
+
+                // move the top-level items to stack
+                if (t == value_t::array)
+                {
+                    stack.reserve(array->size());
+                    std::move(array->begin(), array->end(), std::back_inserter(stack));
+                }
+                else
+                {
+                    stack.reserve(object->size());
+                    for (auto&& it : *object)
+                    {
+                        stack.push_back(std::move(it.second));
+                    }
+                }
+
+                while (!stack.empty())
+                {
+                    // move the last item to local variable to be processed
+                    basic_json current_item(std::move(stack.back()));
+                    stack.pop_back();
+
+                    // if current_item is array/object, move
+                    // its children to the stack to be processed later
+                    if (current_item.is_array())
+                    {
+                        std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack));
+
+                        current_item.m_value.array->clear();
+                    }
+                    else if (current_item.is_object())
+                    {
+                        for (auto&& it : *current_item.m_value.object)
+                        {
+                            stack.push_back(std::move(it.second));
+                        }
+
+                        current_item.m_value.object->clear();
+                    }
+
+                    // it's now safe that current_item get destructed
+                    // since it doesn't have any children
+                }
+            }
+
+            switch (t)
+            {
+                case value_t::object:
+                {
+                    AllocatorType<object_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
+                    break;
+                }
+
+                case value_t::array:
+                {
+                    AllocatorType<array_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
+                    break;
+                }
+
+                case value_t::string:
+                {
+                    AllocatorType<string_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
+                    break;
+                }
+
+                case value_t::binary:
+                {
+                    AllocatorType<binary_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
+                    break;
+                }
+
+                case value_t::null:
+                case value_t::boolean:
+                case value_t::number_integer:
+                case value_t::number_unsigned:
+                case value_t::number_float:
+                case value_t::discarded:
+                default:
+                {
+                    break;
+                }
+            }
+        }
     };
 
+  private:
     /*!
     @brief checks the class invariants
 
@@ -3022,12 +658,123 @@
     invariant. Furthermore, it has to be called each time the type of a JSON
     value is changed, because the invariant expresses a relationship between
     @a m_type and @a m_value.
+
+    Furthermore, the parent relation is checked for arrays and objects: If
+    @a check_parents true and the value is an array or object, then the
+    container's elements must have the current value as parent.
+
+    @param[in] check_parents  whether the parent relation should be checked.
+               The value is true by default and should only be set to false
+               during destruction of objects when the invariant does not
+               need to hold.
     */
-    void assert_invariant() const noexcept
+    void assert_invariant(bool check_parents = true) const noexcept
     {
-        assert(m_type != value_t::object or m_value.object != nullptr);
-        assert(m_type != value_t::array or m_value.array != nullptr);
-        assert(m_type != value_t::string or m_value.string != nullptr);
+        JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
+        JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
+        JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
+        JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
+
+#if JSON_DIAGNOSTICS
+        JSON_TRY
+        {
+            // cppcheck-suppress assertWithSideEffect
+            JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
+            {
+                return j.m_parent == this;
+            }));
+        }
+        JSON_CATCH(...) {} // LCOV_EXCL_LINE
+#endif
+        static_cast<void>(check_parents);
+    }
+
+    void set_parents()
+    {
+#if JSON_DIAGNOSTICS
+        switch (m_type)
+        {
+            case value_t::array:
+            {
+                for (auto& element : *m_value.array)
+                {
+                    element.m_parent = this;
+                }
+                break;
+            }
+
+            case value_t::object:
+            {
+                for (auto& element : *m_value.object)
+                {
+                    element.second.m_parent = this;
+                }
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                break;
+        }
+#endif
+    }
+
+    iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
+    {
+#if JSON_DIAGNOSTICS
+        for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
+        {
+            (it + i)->m_parent = this;
+        }
+#else
+        static_cast<void>(count_set_parents);
+#endif
+        return it;
+    }
+
+    reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1))
+    {
+#if JSON_DIAGNOSTICS
+        if (old_capacity != static_cast<std::size_t>(-1))
+        {
+            // see https://github.com/nlohmann/json/issues/2838
+            JSON_ASSERT(type() == value_t::array);
+            if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
+            {
+                // capacity has changed: update all parents
+                set_parents();
+                return j;
+            }
+        }
+
+        // ordered_json uses a vector internally, so pointers could have
+        // been invalidated; see https://github.com/nlohmann/json/issues/2962
+#ifdef JSON_HEDLEY_MSVC_VERSION
+#pragma warning(push )
+#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
+#endif
+        if (detail::is_ordered_map<object_t>::value)
+        {
+            set_parents();
+            return j;
+        }
+#ifdef JSON_HEDLEY_MSVC_VERSION
+#pragma warning( pop )
+#endif
+
+        j.m_parent = this;
+#else
+        static_cast<void>(j);
+        static_cast<void>(old_capacity);
+#endif
+        return j;
     }
 
   public:
@@ -3035,481 +782,249 @@
     // JSON parser callback //
     //////////////////////////
 
-    /*!
-    @brief parser event types
+    /// @brief parser event types
+    /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/
+    using parse_event_t = detail::parse_event_t;
 
-    The parser callback distinguishes the following events:
-    - `object_start`: the parser read `{` and started to process a JSON object
-    - `key`: the parser read a key of a value in an object
-    - `object_end`: the parser read `}` and finished processing a JSON object
-    - `array_start`: the parser read `[` and started to process a JSON array
-    - `array_end`: the parser read `]` and finished processing a JSON array
-    - `value`: the parser finished reading a JSON value
-
-    @image html callback_events.png "Example when certain parse events are triggered"
-
-    @sa @ref parser_callback_t for more information and examples
-    */
-    enum class parse_event_t : uint8_t
-    {
-        /// the parser read `{` and started to process a JSON object
-        object_start,
-        /// the parser read `}` and finished processing a JSON object
-        object_end,
-        /// the parser read `[` and started to process a JSON array
-        array_start,
-        /// the parser read `]` and finished processing a JSON array
-        array_end,
-        /// the parser read a key of a value in an object
-        key,
-        /// the parser finished reading a JSON value
-        value
-    };
-
-    /*!
-    @brief per-element parser callback type
-
-    With a parser callback function, the result of parsing a JSON text can be
-    influenced. When passed to @ref parse, it is called on certain events
-    (passed as @ref parse_event_t via parameter @a event) with a set recursion
-    depth @a depth and context JSON value @a parsed. The return value of the
-    callback function is a boolean indicating whether the element that emitted
-    the callback shall be kept or not.
-
-    We distinguish six scenarios (determined by the event type) in which the
-    callback function can be called. The following table describes the values
-    of the parameters @a depth, @a event, and @a parsed.
-
-    parameter @a event | description | parameter @a depth | parameter @a parsed
-    ------------------ | ----------- | ------------------ | -------------------
-    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
-    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
-    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
-    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
-    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
-    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
-
-    @image html callback_events.png "Example when certain parse events are triggered"
-
-    Discarding a value (i.e., returning `false`) has different effects
-    depending on the context in which function was called:
-
-    - Discarded values in structured types are skipped. That is, the parser
-      will behave as if the discarded value was never read.
-    - In case a value outside a structured type is skipped, it is replaced
-      with `null`. This case happens if the top-level element is skipped.
-
-    @param[in] depth  the depth of the recursion during parsing
-
-    @param[in] event  an event of type parse_event_t indicating the context in
-    the callback function has been called
-
-    @param[in,out] parsed  the current intermediate parse result; note that
-    writing to this value has no effect for parse_event_t::key events
-
-    @return Whether the JSON value which called the function during parsing
-    should be kept (`true`) or not (`false`). In the latter case, it is either
-    skipped completely or replaced by an empty discarded object.
-
-    @sa @ref parse for examples
-
-    @since version 1.0.0
-    */
-    using parser_callback_t =
-        std::function<bool(int depth, parse_event_t event, json& parsed)>;
-
+    /// @brief per-element parser callback type
+    /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/
+    using parser_callback_t = detail::parser_callback_t<basic_json>;
 
     //////////////////
     // constructors //
     //////////////////
 
     /// @name constructors and destructors
-    /// Constructors of class @ref json, copy/move constructor, copy
+    /// Constructors of class @ref basic_json, copy/move constructor, copy
     /// assignment, static functions creating objects, and the destructor.
     /// @{
 
-    /*!
-    @brief create an empty value with a given type
-
-    Create an empty JSON value with a given type. The value will be default
-    initialized with an empty value which depends on the type:
-
-    Value type  | initial value
-    ----------- | -------------
-    null        | `null`
-    boolean     | `false`
-    string      | `""`
-    number      | `0`
-    object      | `{}`
-    array       | `[]`
-
-    @param[in] v  the type of the value to create
-
-    @complexity Constant.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
-
-    @liveexample{The following code shows the constructor for different @ref
-    value_t values,json__value_t}
-
-    @sa @ref clear() -- restores the postcondition of this constructor
-
-    @since version 1.0.0
-    */
-    json(const value_t v)
+    /// @brief create an empty value with a given type
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(const value_t v)
         : m_type(v), m_value(v)
     {
         assert_invariant();
     }
 
-    /*!
-    @brief create a null object
-
-    Create a `null` JSON value. It either takes a null pointer as parameter
-    (explicitly creating `null`) or no parameter (implicitly creating `null`).
-    The passed null pointer itself is not read -- it is only used to choose
-    the right constructor.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this constructor never throws
-    exceptions.
-
-    @liveexample{The following code shows the constructor with and without a
-    null pointer parameter.,json__nullptr_t}
-
-    @since version 1.0.0
-    */
-    json(std::nullptr_t = nullptr) noexcept
-        : json(value_t::null)
+    /// @brief create a null object
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
+        : basic_json(value_t::null)
     {
         assert_invariant();
     }
 
-    /*!
-    @brief create a JSON value
-
-    This is a "catch all" constructor for all compatible JSON types; that is,
-    types for which a `to_json()` method exists. The constructor forwards the
-    parameter @a val to that method (to `json_serializer<U>::to_json` method
-    with `U = uncvref_t<CompatibleType>`, to be exact).
-
-    Template type @a CompatibleType includes, but is not limited to, the
-    following types:
-    - **arrays**: @ref array_t and all kinds of compatible containers such as
-      `std::vector`, `std::deque`, `std::list`,
-      `std::array`, `std::set`, `std::unordered_set`,
-      `std::multiset`, and `std::unordered_multiset` with a `value_type` from
-      which a @ref json value can be constructed.
-    - **objects**: @ref object_t and all kinds of compatible associative
-      containers such as `std::map`, `std::unordered_map`, `std::multimap`,
-      and `std::unordered_multimap` with a `key_type` compatible to
-      `std::string` and a `value_type` from which a @ref json value can
-      be constructed.
-    - **strings**: `std::string`, string literals, and all compatible string
-      containers can be used.
-    - **numbers**: int64_t, uint64_t,
-      double, and all convertible number types such as `int`,
-      `size_t`, `int64_t`, `float` or `double` can be used.
-    - **boolean**: `bool` can be used.
-
-    See the examples below.
-
-    @tparam CompatibleType a type such that:
-    - @a CompatibleType is not derived from `std::istream`,
-    - @a CompatibleType is not @ref json (to avoid hijacking copy/move
-         constructors),
-    - @a CompatibleType is not a different @ref json type (i.e. with different template arguments)
-    - @a CompatibleType is not a @ref json nested type (e.g.,
-         @ref json_pointer, @ref iterator, etc ...)
-    - @ref @ref json_serializer<U> has a
-         `to_json(json_t&, CompatibleType&&)` method
-
-    @tparam U = `uncvref_t<CompatibleType>`
-
-    @param[in] val the value to be forwarded to the respective constructor
-
-    @complexity Usually linear in the size of the passed @a val, also
-                depending on the implementation of the called `to_json()`
-                method.
-
-    @exceptionsafety Depends on the called constructor. For types directly
-    supported by the library (i.e., all types for which no `to_json()` function
-    was provided), strong guarantee holds: if an exception is thrown, there are
-    no changes to any JSON value.
-
-    @liveexample{The following code shows the constructor with several
-    compatible types.,json__CompatibleType}
-
-    @since version 2.1.0
-    */
-    template <typename CompatibleType,
-              typename U = detail::uncvref_t<CompatibleType>,
-              detail::enable_if_t<
-                  detail::is_compatible_type<json_t, U>::value, int> = 0>
-    json(CompatibleType && val) noexcept(noexcept(
-                adl_serializer<U, void>::to_json(std::declval<json_t&>(),
+    /// @brief create a JSON value from compatible types
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    template < typename CompatibleType,
+               typename U = detail::uncvref_t<CompatibleType>,
+               detail::enable_if_t <
+                   !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
+    basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
+                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
                                            std::forward<CompatibleType>(val))))
     {
-        adl_serializer<U, void>::to_json(*this, std::forward<CompatibleType>(val));
+        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
+        set_parents();
         assert_invariant();
     }
 
-    /*!
-    @brief create a container (array or object) from an initializer list
+    /// @brief create a JSON value from an existing one
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    template < typename BasicJsonType,
+               detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
+    basic_json(const BasicJsonType& val)
+    {
+        using other_boolean_t = typename BasicJsonType::boolean_t;
+        using other_number_float_t = typename BasicJsonType::number_float_t;
+        using other_number_integer_t = typename BasicJsonType::number_integer_t;
+        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+        using other_string_t = typename BasicJsonType::string_t;
+        using other_object_t = typename BasicJsonType::object_t;
+        using other_array_t = typename BasicJsonType::array_t;
+        using other_binary_t = typename BasicJsonType::binary_t;
 
-    Creates a JSON value of type array or object from the passed initializer
-    list @a init. In case @a type_deduction is `true` (default), the type of
-    the JSON value to be created is deducted from the initializer list @a init
-    according to the following rules:
+        switch (val.type())
+        {
+            case value_t::boolean:
+                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
+                break;
+            case value_t::number_float:
+                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
+                break;
+            case value_t::number_integer:
+                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
+                break;
+            case value_t::number_unsigned:
+                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
+                break;
+            case value_t::string:
+                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
+                break;
+            case value_t::object:
+                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
+                break;
+            case value_t::array:
+                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
+                break;
+            case value_t::binary:
+                JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
+                break;
+            case value_t::null:
+                *this = nullptr;
+                break;
+            case value_t::discarded:
+                m_type = value_t::discarded;
+                break;
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+        JSON_ASSERT(m_type == val.type());
+        set_parents();
+        assert_invariant();
+    }
 
-    1. If the list is empty, an empty JSON object value `{}` is created.
-    2. If the list consists of pairs whose first element is a string, a JSON
-       object value is created where the first elements of the pairs are
-       treated as keys and the second elements are as values.
-    3. In all other cases, an array is created.
-
-    The rules aim to create the best fit between a C++ initializer list and
-    JSON values. The rationale is as follows:
-
-    1. The empty initializer list is written as `{}` which is exactly an empty
-       JSON object.
-    2. C++ has no way of describing mapped types other than to list a list of
-       pairs. As JSON requires that keys must be of type string, rule 2 is the
-       weakest constraint one can pose on initializer lists to interpret them
-       as an object.
-    3. In all other cases, the initializer list could not be interpreted as
-       JSON object type, so interpreting it as JSON array type is safe.
-
-    With the rules described above, the following JSON values cannot be
-    expressed by an initializer list:
-
-    - the empty array (`[]`): use @ref array(initializer_list_t)
-      with an empty initializer list in this case
-    - arrays whose elements satisfy rule 2: use @ref
-      array(initializer_list_t) with the same initializer list
-      in this case
-
-    @note When used without parentheses around an empty initializer list, @ref
-    json() is called instead of this function, yielding the JSON null
-    value.
-
-    @param[in] init  initializer list with JSON values
-
-    @param[in] type_deduction internal parameter; when set to `true`, the type
-    of the JSON value is deducted from the initializer list @a init; when set
-    to `false`, the type provided via @a manual_type is forced. This mode is
-    used by the functions @ref array(initializer_list_t) and
-    @ref object(initializer_list_t).
-
-    @param[in] manual_type internal parameter; when @a type_deduction is set
-    to `false`, the created JSON value will use the provided type (only @ref
-    value_t::array and @ref value_t::object are valid); when @a type_deduction
-    is set to `true`, this parameter has no effect
-
-    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is
-    `value_t::object`, but @a init contains an element which is not a pair
-    whose first element is a string. In this case, the constructor could not
-    create an object. If @a type_deduction would have be `true`, an array
-    would have been created. See @ref object(initializer_list_t)
-    for an example.
-
-    @complexity Linear in the size of the initializer list @a init.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
-
-    @liveexample{The example below shows how JSON values are created from
-    initializer lists.,json__list_init_t}
-
-    @sa @ref array(initializer_list_t) -- create a JSON array
-    value from an initializer list
-    @sa @ref object(initializer_list_t) -- create a JSON object
-    value from an initializer list
-
-    @since version 1.0.0
-    */
-    json(initializer_list_t init,
+    /// @brief create a container (array or object) from an initializer list
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(initializer_list_t init,
                bool type_deduction = true,
-               value_t manual_type = value_t::array);
-
-    /*!
-    @brief explicitly create an array from an initializer list
-
-    Creates a JSON array value from a given initializer list. That is, given a
-    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
-    initializer list is empty, the empty array `[]` is created.
-
-    @note This function is only needed to express two edge cases that cannot
-    be realized with the initializer list constructor (@ref
-    json(initializer_list_t, bool, value_t)). These cases
-    are:
-    1. creating an array whose elements are all pairs whose first element is a
-    string -- in this case, the initializer list constructor would create an
-    object, taking the first elements as keys
-    2. creating an empty array -- passing the empty initializer list to the
-    initializer list constructor yields an empty object
-
-    @param[in] init  initializer list with JSON values to create an array from
-    (optional)
-
-    @return JSON array value
-
-    @complexity Linear in the size of @a init.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
-
-    @liveexample{The following code shows an example for the `array`
-    function.,array}
-
-    @sa @ref json(initializer_list_t, bool, value_t) --
-    create a JSON value from an initializer list
-    @sa @ref object(initializer_list_t) -- create a JSON object
-    value from an initializer list
-
-    @since version 1.0.0
-    */
-    static json array(initializer_list_t init = {})
+               value_t manual_type = value_t::array)
     {
-        return json(init, false, value_t::array);
+        // check if each element is an array with two elements whose first
+        // element is a string
+        bool is_an_object = std::all_of(init.begin(), init.end(),
+                                        [](const detail::json_ref<basic_json>& element_ref)
+        {
+            return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();
+        });
+
+        // adjust type if type deduction is not wanted
+        if (!type_deduction)
+        {
+            // if array is wanted, do not create an object though possible
+            if (manual_type == value_t::array)
+            {
+                is_an_object = false;
+            }
+
+            // if object is wanted but impossible, throw an exception
+            if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
+            {
+                JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
+            }
+        }
+
+        if (is_an_object)
+        {
+            // the initializer list is a list of pairs -> create object
+            m_type = value_t::object;
+            m_value = value_t::object;
+
+            for (auto& element_ref : init)
+            {
+                auto element = element_ref.moved_or_copied();
+                m_value.object->emplace(
+                    std::move(*((*element.m_value.array)[0].m_value.string)),
+                    std::move((*element.m_value.array)[1]));
+            }
+        }
+        else
+        {
+            // the initializer list describes an array -> create array
+            m_type = value_t::array;
+            m_value.array = create<array_t>(init.begin(), init.end());
+        }
+
+        set_parents();
+        assert_invariant();
     }
 
-    /*!
-    @brief explicitly create an object from an initializer list
-
-    Creates a JSON object value from a given initializer list. The initializer
-    lists elements must be pairs, and their first elements must be strings. If
-    the initializer list is empty, the empty object `{}` is created.
-
-    @note This function is only added for symmetry reasons. In contrast to the
-    related function @ref array(initializer_list_t), there are
-    no cases which can only be expressed by this function. That is, any
-    initializer list @a init can also be passed to the initializer list
-    constructor @ref json(initializer_list_t, bool, value_t).
-
-    @param[in] init  initializer list to create an object from (optional)
-
-    @return JSON object value
-
-    @throw type_error.301 if @a init is not a list of pairs whose first
-    elements are strings. In this case, no object can be created. When such a
-    value is passed to @ref json(initializer_list_t, bool, value_t),
-    an array would have been created from the passed initializer list @a init.
-    See example below.
-
-    @complexity Linear in the size of @a init.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
-
-    @liveexample{The following code shows an example for the `object`
-    function.,object}
-
-    @sa @ref json(initializer_list_t, bool, value_t) --
-    create a JSON value from an initializer list
-    @sa @ref array(initializer_list_t) -- create a JSON array
-    value from an initializer list
-
-    @since version 1.0.0
-    */
-    static json object(initializer_list_t init = {})
+    /// @brief explicitly create a binary array (without subtype)
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(const typename binary_t::container_type& init)
     {
-        return json(init, false, value_t::object);
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = init;
+        return res;
     }
 
-    /*!
-    @brief construct an array with count copies of given value
-
-    Constructs a JSON array value by creating @a cnt copies of a passed value.
-    In case @a cnt is `0`, an empty array is created.
-
-    @param[in] cnt  the number of JSON copies of @a val to create
-    @param[in] val  the JSON value to copy
-
-    @post `std::distance(begin(),end()) == cnt` holds.
-
-    @complexity Linear in @a cnt.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
-
-    @liveexample{The following code shows examples for the @ref
-    json(size_type\, const json&)
-    constructor.,json__size_type_json}
-
-    @since version 1.0.0
-    */
-    json(size_type cnt, const json& val);
-
-    /*!
-    @brief construct a JSON container given an iterator range
-
-    Constructs the JSON value with the contents of the range `[first, last)`.
-    The semantics depends on the different types a JSON value can have:
-    - In case of a null type, invalid_iterator.206 is thrown.
-    - In case of other primitive types (number, boolean, or string), @a first
-      must be `begin()` and @a last must be `end()`. In this case, the value is
-      copied. Otherwise, invalid_iterator.204 is thrown.
-    - In case of structured types (array, object), the constructor behaves as
-      similar versions for `std::vector` or `std::map`; that is, a JSON array
-      or object is constructed from the values in the range.
-
-    @tparam InputIT an input iterator type (@ref iterator or @ref
-    const_iterator)
-
-    @param[in] first begin of the range to copy from (included)
-    @param[in] last end of the range to copy from (excluded)
-
-    @pre Iterators @a first and @a last must be initialized. **This
-         precondition is enforced with an assertion (see warning).** If
-         assertions are switched off, a violation of this precondition yields
-         undefined behavior.
-
-    @pre Range `[first, last)` is valid. Usually, this precondition cannot be
-         checked efficiently. Only certain edge cases are detected; see the
-         description of the exceptions below. A violation of this precondition
-         yields undefined behavior.
-
-    @warning A precondition is enforced with a runtime assertion that will
-             result in calling `std::abort` if this precondition is not met.
-             Assertions can be disabled by defining `NDEBUG` at compile time.
-             See http://en.cppreference.com/w/cpp/error/assert for more
-             information.
-
-    @throw invalid_iterator.201 if iterators @a first and @a last are not
-    compatible (i.e., do not belong to the same JSON value). In this case,
-    the range `[first, last)` is undefined.
-    @throw invalid_iterator.204 if iterators @a first and @a last belong to a
-    primitive type (number, boolean, or string), but @a first does not point
-    to the first element any more. In this case, the range `[first, last)` is
-    undefined. See example code below.
-    @throw invalid_iterator.206 if iterators @a first and @a last belong to a
-    null value. In this case, the range `[first, last)` is undefined.
-
-    @complexity Linear in distance between @a first and @a last.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
-
-    @liveexample{The example below shows several ways to create JSON values by
-    specifying a subrange with iterators.,json__InputIt_InputIt}
-
-    @since version 1.0.0
-    */
-    template<class InputIT, typename std::enable_if<
-                 std::is_same<InputIT, typename json_t::iterator>::value or
-                 std::is_same<InputIT, typename json_t::const_iterator>::value, int>::type = 0>
-    json(InputIT first, InputIT last)
+    /// @brief explicitly create a binary array (with subtype)
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
     {
-        assert(first.m_object != nullptr);
-        assert(last.m_object != nullptr);
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = binary_t(init, subtype);
+        return res;
+    }
+
+    /// @brief explicitly create a binary array
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(typename binary_t::container_type&& init)
+    {
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = std::move(init);
+        return res;
+    }
+
+    /// @brief explicitly create a binary array (with subtype)
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
+    {
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = binary_t(std::move(init), subtype);
+        return res;
+    }
+
+    /// @brief explicitly create an array from an initializer list
+    /// @sa https://json.nlohmann.me/api/basic_json/array/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json array(initializer_list_t init = {})
+    {
+        return basic_json(init, false, value_t::array);
+    }
+
+    /// @brief explicitly create an object from an initializer list
+    /// @sa https://json.nlohmann.me/api/basic_json/object/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json object(initializer_list_t init = {})
+    {
+        return basic_json(init, false, value_t::object);
+    }
+
+    /// @brief construct an array with count copies of given value
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(size_type cnt, const basic_json& val)
+        : m_type(value_t::array)
+    {
+        m_value.array = create<array_t>(cnt, val);
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief construct a JSON container given an iterator range
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    template < class InputIT, typename std::enable_if <
+                   std::is_same<InputIT, typename basic_json_t::iterator>::value ||
+                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
+    basic_json(InputIT first, InputIT last)
+    {
+        JSON_ASSERT(first.m_object != nullptr);
+        JSON_ASSERT(last.m_object != nullptr);
 
         // make sure iterator fits the current value
-        if (JSON_UNLIKELY(first.m_object != last.m_object))
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
         {
-            JSON_THROW(invalid_iterator::create(201, "iterators are not compatible"));
+            JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
         }
 
         // copy type from first iterator
@@ -3524,14 +1039,19 @@
             case value_t::number_unsigned:
             case value_t::string:
             {
-                if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin()
-                                  or not last.m_it.primitive_iterator.is_end()))
+                if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
+                                         || !last.m_it.primitive_iterator.is_end()))
                 {
-                    JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
+                    JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
                 }
                 break;
             }
 
+            case value_t::null:
+            case value_t::object:
+            case value_t::array:
+            case value_t::binary:
+            case value_t::discarded:
             default:
                 break;
         }
@@ -3568,6 +1088,13 @@
                 break;
             }
 
+            case value_t::object:
+            {
+                m_value.object = create<object_t>(first.m_it.object_iterator,
+                                                  last.m_it.object_iterator);
+                break;
+            }
+
             case value_t::array:
             {
                 m_value.array = create<array_t>(first.m_it.array_iterator,
@@ -3575,10 +1102,19 @@
                 break;
             }
 
+            case value_t::binary:
+            {
+                m_value = *first.m_object->m_value.binary;
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
             default:
-                JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from", first.m_object->type_name()));
+                JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
         }
 
+        set_parents();
         assert_invariant();
     }
 
@@ -3587,105 +1123,102 @@
     // other constructors and destructor //
     ///////////////////////////////////////
 
-    /// @private
-    json(const detail::json_ref<json>& ref)
-        : json(ref.moved_or_copied())
-    {}
+    template<typename JsonRef,
+             detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
+                                 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
+    basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
 
-    /*!
-    @brief copy constructor
+    /// @brief copy constructor
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(const basic_json& other)
+        : m_type(other.m_type)
+    {
+        // check of passed value is valid
+        other.assert_invariant();
 
-    Creates a copy of a given JSON value.
+        switch (m_type)
+        {
+            case value_t::object:
+            {
+                m_value = *other.m_value.object;
+                break;
+            }
 
-    @param[in] other  the JSON value to copy
+            case value_t::array:
+            {
+                m_value = *other.m_value.array;
+                break;
+            }
 
-    @post `*this == other`
+            case value_t::string:
+            {
+                m_value = *other.m_value.string;
+                break;
+            }
 
-    @complexity Linear in the size of @a other.
+            case value_t::boolean:
+            {
+                m_value = other.m_value.boolean;
+                break;
+            }
 
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes to any JSON value.
+            case value_t::number_integer:
+            {
+                m_value = other.m_value.number_integer;
+                break;
+            }
 
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is linear.
-    - As postcondition, it holds: `other == json(other)`.
+            case value_t::number_unsigned:
+            {
+                m_value = other.m_value.number_unsigned;
+                break;
+            }
 
-    @liveexample{The following code shows an example for the copy
-    constructor.,json__json}
+            case value_t::number_float:
+            {
+                m_value = other.m_value.number_float;
+                break;
+            }
 
-    @since version 1.0.0
-    */
-    json(const json& other);
+            case value_t::binary:
+            {
+                m_value = *other.m_value.binary;
+                break;
+            }
 
-    /*!
-    @brief move constructor
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                break;
+        }
 
-    Move constructor. Constructs a JSON value with the contents of the given
-    value @a other using move semantics. It "steals" the resources from @a
-    other and leaves it as JSON null value.
+        set_parents();
+        assert_invariant();
+    }
 
-    @param[in,out] other  value to move to this object
-
-    @post `*this` has the same value as @a other before the call.
-    @post @a other is a JSON null value.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this constructor never throws
-    exceptions.
-
-    @requirement This function helps `json` satisfying the
-    [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible)
-    requirements.
-
-    @liveexample{The code below shows the move constructor explicitly called
-    via std::move.,json__moveconstructor}
-
-    @since version 1.0.0
-    */
-    json(json&& other) noexcept
+    /// @brief move constructor
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(basic_json&& other) noexcept
         : m_type(std::move(other.m_type)),
           m_value(std::move(other.m_value))
     {
         // check that passed value is valid
-        other.assert_invariant();
+        other.assert_invariant(false);
 
         // invalidate payload
         other.m_type = value_t::null;
         other.m_value = {};
 
+        set_parents();
         assert_invariant();
     }
 
-    /*!
-    @brief copy assignment
-
-    Copy assignment operator. Copies a JSON value via the "copy and swap"
-    strategy: It is expressed in terms of the copy constructor, destructor,
-    and the `swap()` member function.
-
-    @param[in] other  value to copy from
-
-    @complexity Linear.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is linear.
-
-    @liveexample{The code below shows and example for the copy assignment. It
-    creates a copy of value `a` which is then swapped with `b`. Finally\, the
-    copy of `a` (which is the null value after the swap) is
-    destroyed.,json__copyassignment}
-
-    @since version 1.0.0
-    */
-    reference& operator=(json other) noexcept (
-        std::is_nothrow_move_constructible<value_t>::value and
-        std::is_nothrow_move_assignable<value_t>::value and
-        std::is_nothrow_move_constructible<json_value>::value and
+    /// @brief copy assignment
+    /// @sa https://json.nlohmann.me/api/basic_json/operator=/
+    basic_json& operator=(basic_json other) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value&&
+        std::is_nothrow_move_assignable<value_t>::value&&
+        std::is_nothrow_move_constructible<json_value>::value&&
         std::is_nothrow_move_assignable<json_value>::value
     )
     {
@@ -3696,28 +1229,16 @@
         swap(m_type, other.m_type);
         swap(m_value, other.m_value);
 
+        set_parents();
         assert_invariant();
         return *this;
     }
 
-    /*!
-    @brief destructor
-
-    Destroys the JSON value and frees all allocated memory.
-
-    @complexity Linear.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is linear.
-    - All stored elements are destroyed and all memory is freed.
-
-    @since version 1.0.0
-    */
-    ~json() noexcept
+    /// @brief destructor
+    /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/
+    ~basic_json() noexcept
     {
-        assert_invariant();
+        assert_invariant(false);
         m_value.destroy(m_type);
     }
 
@@ -3732,416 +1253,147 @@
     /// Functions to inspect the type of a JSON value.
     /// @{
 
-    /*!
-    @brief serialization
+    /// @brief serialization
+    /// @sa https://json.nlohmann.me/api/basic_json/dump/
+    string_t dump(const int indent = -1,
+                  const char indent_char = ' ',
+                  const bool ensure_ascii = false,
+                  const error_handler_t error_handler = error_handler_t::strict) const
+    {
+        string_t result;
+        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
 
-    Serialization function for JSON values. The function tries to mimic
-    Python's `json.dumps()` function, and currently supports its @a indent
-    and @a ensure_ascii parameters.
+        if (indent >= 0)
+        {
+            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
+        }
+        else
+        {
+            s.dump(*this, false, ensure_ascii, 0);
+        }
 
-    @param[in] indent If indent is nonnegative, then array elements and object
-    members will be pretty-printed with that indent level. An indent level of
-    `0` will only insert newlines. `-1` (the default) selects the most compact
-    representation.
-    @param[in] indent_char The character to use for indentation if @a indent is
-    greater than `0`. The default is ` ` (space).
-    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
-    in the output are escaped with `\uXXXX` sequences, and the result consists
-    of ASCII characters only.
+        return result;
+    }
 
-    @return string containing the serialization of the JSON value
+    void dump(raw_ostream& os, const int indent = -1,
+                  const char indent_char = ' ',
+                  const bool ensure_ascii = false,
+                  const error_handler_t error_handler = error_handler_t::strict) const {
+      serializer s(os, indent_char);
 
-    @throw type_error.316 if a string stored inside the JSON value is not
-                          UTF-8 encoded
+      if (indent >= 0)
+      {
+          s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
+      }
+      else
+      {
+          s.dump(*this, false, ensure_ascii, 0);
+      }
 
-    @complexity Linear.
+      os.flush();
+    }
 
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @liveexample{The following example shows the effect of different @a indent\,
-    @a indent_char\, and @a ensure_ascii parameters to the result of the
-    serialization.,dump}
-
-    @see https://docs.python.org/2/library/json.html#json.dump
-
-    @since version 1.0.0; indentation character @a indent_char, option
-           @a ensure_ascii and exceptions added in version 3.0.0
-    */
-    std::string dump(const int indent = -1, const char indent_char = ' ',
-                     const bool ensure_ascii = false) const;
-
-    void dump(raw_ostream& os, int indent = -1, const char indent_char = ' ',
-              const bool ensure_ascii = false) const;
-
-    /*!
-    @brief return the type of the JSON value (explicit)
-
-    Return the type of the JSON value as a value from the @ref value_t
-    enumeration.
-
-    @return the type of the JSON value
-            Value type                | return value
-            ------------------------- | -------------------------
-            null                      | value_t::null
-            boolean                   | value_t::boolean
-            string                    | value_t::string
-            number (integer)          | value_t::number_integer
-            number (unsigned integer) | value_t::number_unsigned
-            number (floating-point)   | value_t::number_float
-            object                    | value_t::object
-            array                     | value_t::array
-            discarded                 | value_t::discarded
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `type()` for all JSON
-    types.,type}
-
-    @sa @ref operator value_t() -- return the type of the JSON value (implicit)
-    @sa @ref type_name() -- return the type as string
-
-    @since version 1.0.0
-    */
-    value_t type() const noexcept
+    /// @brief return the type of the JSON value (explicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/type/
+    constexpr value_t type() const noexcept
     {
         return m_type;
     }
 
-    /*!
-    @brief return whether type is primitive
-
-    This function returns true if and only if the JSON type is primitive
-    (string, number, boolean, or null).
-
-    @return `true` if type is primitive (string, number, boolean, or null),
-    `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_primitive()` for all JSON
-    types.,is_primitive}
-
-    @sa @ref is_structured() -- returns whether JSON value is structured
-    @sa @ref is_null() -- returns whether JSON value is `null`
-    @sa @ref is_string() -- returns whether JSON value is a string
-    @sa @ref is_boolean() -- returns whether JSON value is a boolean
-    @sa @ref is_number() -- returns whether JSON value is a number
-
-    @since version 1.0.0
-    */
-    bool is_primitive() const noexcept
+    /// @brief return whether type is primitive
+    /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
+    constexpr bool is_primitive() const noexcept
     {
-        return is_null() or is_string() or is_boolean() or is_number();
+        return is_null() || is_string() || is_boolean() || is_number() || is_binary();
     }
 
-    /*!
-    @brief return whether type is structured
-
-    This function returns true if and only if the JSON type is structured
-    (array or object).
-
-    @return `true` if type is structured (array or object), `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_structured()` for all JSON
-    types.,is_structured}
-
-    @sa @ref is_primitive() -- returns whether value is primitive
-    @sa @ref is_array() -- returns whether value is an array
-    @sa @ref is_object() -- returns whether value is an object
-
-    @since version 1.0.0
-    */
-    bool is_structured() const noexcept
+    /// @brief return whether type is structured
+    /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
+    constexpr bool is_structured() const noexcept
     {
-        return is_array() or is_object();
+        return is_array() || is_object();
     }
 
-    /*!
-    @brief return whether value is null
-
-    This function returns true if and only if the JSON value is null.
-
-    @return `true` if type is null, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_null()` for all JSON
-    types.,is_null}
-
-    @since version 1.0.0
-    */
-    bool is_null() const noexcept
+    /// @brief return whether value is null
+    /// @sa https://json.nlohmann.me/api/basic_json/is_null/
+    constexpr bool is_null() const noexcept
     {
-        return (m_type == value_t::null);
+        return m_type == value_t::null;
     }
 
-    /*!
-    @brief return whether value is a boolean
-
-    This function returns true if and only if the JSON value is a boolean.
-
-    @return `true` if type is boolean, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_boolean()` for all JSON
-    types.,is_boolean}
-
-    @since version 1.0.0
-    */
-    bool is_boolean() const noexcept
+    /// @brief return whether value is a boolean
+    /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
+    constexpr bool is_boolean() const noexcept
     {
-        return (m_type == value_t::boolean);
+        return m_type == value_t::boolean;
     }
 
-    /*!
-    @brief return whether value is a number
-
-    This function returns true if and only if the JSON value is a number. This
-    includes both integer (signed and unsigned) and floating-point values.
-
-    @return `true` if type is number (regardless whether integer, unsigned
-    integer or floating-type), `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_number()` for all JSON
-    types.,is_number}
-
-    @sa @ref is_number_integer() -- check if value is an integer or unsigned
-    integer number
-    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
-    number
-    @sa @ref is_number_float() -- check if value is a floating-point number
-
-    @since version 1.0.0
-    */
-    bool is_number() const noexcept
+    /// @brief return whether value is a number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number/
+    constexpr bool is_number() const noexcept
     {
-        return is_number_integer() or is_number_float();
+        return is_number_integer() || is_number_float();
     }
 
-    /*!
-    @brief return whether value is an integer number
-
-    This function returns true if and only if the JSON value is a signed or
-    unsigned integer number. This excludes floating-point values.
-
-    @return `true` if type is an integer or unsigned integer number, `false`
-    otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_number_integer()` for all
-    JSON types.,is_number_integer}
-
-    @sa @ref is_number() -- check if value is a number
-    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
-    number
-    @sa @ref is_number_float() -- check if value is a floating-point number
-
-    @since version 1.0.0
-    */
-    bool is_number_integer() const noexcept
+    /// @brief return whether value is an integer number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
+    constexpr bool is_number_integer() const noexcept
     {
-        return (m_type == value_t::number_integer or m_type == value_t::number_unsigned);
+        return m_type == value_t::number_integer || m_type == value_t::number_unsigned;
     }
 
-    /*!
-    @brief return whether value is an unsigned integer number
-
-    This function returns true if and only if the JSON value is an unsigned
-    integer number. This excludes floating-point and signed integer values.
-
-    @return `true` if type is an unsigned integer number, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_number_unsigned()` for all
-    JSON types.,is_number_unsigned}
-
-    @sa @ref is_number() -- check if value is a number
-    @sa @ref is_number_integer() -- check if value is an integer or unsigned
-    integer number
-    @sa @ref is_number_float() -- check if value is a floating-point number
-
-    @since version 2.0.0
-    */
-    bool is_number_unsigned() const noexcept
+    /// @brief return whether value is an unsigned integer number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
+    constexpr bool is_number_unsigned() const noexcept
     {
-        return (m_type == value_t::number_unsigned);
+        return m_type == value_t::number_unsigned;
     }
 
-    /*!
-    @brief return whether value is a floating-point number
-
-    This function returns true if and only if the JSON value is a
-    floating-point number. This excludes signed and unsigned integer values.
-
-    @return `true` if type is a floating-point number, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_number_float()` for all
-    JSON types.,is_number_float}
-
-    @sa @ref is_number() -- check if value is number
-    @sa @ref is_number_integer() -- check if value is an integer number
-    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
-    number
-
-    @since version 1.0.0
-    */
-    bool is_number_float() const noexcept
+    /// @brief return whether value is a floating-point number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
+    constexpr bool is_number_float() const noexcept
     {
-        return (m_type == value_t::number_float);
+        return m_type == value_t::number_float;
     }
 
-    /*!
-    @brief return whether value is an object
-
-    This function returns true if and only if the JSON value is an object.
-
-    @return `true` if type is object, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_object()` for all JSON
-    types.,is_object}
-
-    @since version 1.0.0
-    */
-    bool is_object() const noexcept
+    /// @brief return whether value is an object
+    /// @sa https://json.nlohmann.me/api/basic_json/is_object/
+    constexpr bool is_object() const noexcept
     {
-        return (m_type == value_t::object);
+        return m_type == value_t::object;
     }
 
-    /*!
-    @brief return whether value is an array
-
-    This function returns true if and only if the JSON value is an array.
-
-    @return `true` if type is array, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_array()` for all JSON
-    types.,is_array}
-
-    @since version 1.0.0
-    */
-    bool is_array() const noexcept
+    /// @brief return whether value is an array
+    /// @sa https://json.nlohmann.me/api/basic_json/is_array/
+    constexpr bool is_array() const noexcept
     {
-        return (m_type == value_t::array);
+        return m_type == value_t::array;
     }
 
-    /*!
-    @brief return whether value is a string
-
-    This function returns true if and only if the JSON value is a string.
-
-    @return `true` if type is string, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_string()` for all JSON
-    types.,is_string}
-
-    @since version 1.0.0
-    */
-    bool is_string() const noexcept
+    /// @brief return whether value is a string
+    /// @sa https://json.nlohmann.me/api/basic_json/is_string/
+    constexpr bool is_string() const noexcept
     {
-        return (m_type == value_t::string);
+        return m_type == value_t::string;
     }
 
-    /*!
-    @brief return whether value is discarded
-
-    This function returns true if and only if the JSON value was discarded
-    during parsing with a callback function (see @ref parser_callback_t).
-
-    @note This function will always be `false` for JSON values after parsing.
-    That is, discarded values can only occur during parsing, but will be
-    removed when inside a structured value or replaced by null in other cases.
-
-    @return `true` if type is discarded, `false` otherwise.
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies `is_discarded()` for all JSON
-    types.,is_discarded}
-
-    @since version 1.0.0
-    */
-    bool is_discarded() const noexcept
+    /// @brief return whether value is a binary array
+    /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
+    constexpr bool is_binary() const noexcept
     {
-        return (m_type == value_t::discarded);
+        return m_type == value_t::binary;
     }
 
-    /*!
-    @brief return the type of the JSON value (implicit)
+    /// @brief return whether value is discarded
+    /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
+    constexpr bool is_discarded() const noexcept
+    {
+        return m_type == value_t::discarded;
+    }
 
-    Implicitly return the type of the JSON value as a value from the @ref
-    value_t enumeration.
-
-    @return the type of the JSON value
-
-    @complexity Constant.
-
-    @exceptionsafety No-throw guarantee: this member function never throws
-    exceptions.
-
-    @liveexample{The following code exemplifies the @ref value_t operator for
-    all JSON types.,operator__value_t}
-
-    @sa @ref type() -- return the type of the JSON value (explicit)
-    @sa @ref type_name() -- return the type as string
-
-    @since version 1.0.0
-    */
-    operator value_t() const noexcept
+    /// @brief return the type of the JSON value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
+    constexpr operator value_t() const noexcept
     {
         return m_type;
     }
@@ -4154,14 +1406,14 @@
     //////////////////
 
     /// get a boolean (explicit)
-    bool get_impl(bool* /*unused*/) const
+    boolean_t get_impl(boolean_t* /*unused*/) const
     {
-        if (JSON_LIKELY(is_boolean()))
+        if (JSON_HEDLEY_LIKELY(is_boolean()))
         {
             return m_value.boolean;
         }
 
-        JSON_THROW(type_error::create(302, "type must be boolean, but is", type_name()));
+        JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
     }
 
     /// get a pointer to the value (object)
@@ -4171,7 +1423,7 @@
     }
 
     /// get a pointer to the value (object)
-    const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
+    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
     {
         return is_object() ? m_value.object : nullptr;
     }
@@ -4183,78 +1435,90 @@
     }
 
     /// get a pointer to the value (array)
-    const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
+    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
     {
         return is_array() ? m_value.array : nullptr;
     }
 
     /// get a pointer to the value (string)
-    std::string* get_impl_ptr(std::string* /*unused*/) noexcept
+    string_t* get_impl_ptr(string_t* /*unused*/) noexcept
     {
         return is_string() ? m_value.string : nullptr;
     }
 
     /// get a pointer to the value (string)
-    const std::string* get_impl_ptr(const std::string* /*unused*/) const noexcept
+    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
     {
         return is_string() ? m_value.string : nullptr;
     }
 
     /// get a pointer to the value (boolean)
-    bool* get_impl_ptr(bool* /*unused*/) noexcept
+    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
     {
         return is_boolean() ? &m_value.boolean : nullptr;
     }
 
     /// get a pointer to the value (boolean)
-    const bool* get_impl_ptr(const bool* /*unused*/) const noexcept
+    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
     {
         return is_boolean() ? &m_value.boolean : nullptr;
     }
 
     /// get a pointer to the value (integer number)
-    int64_t* get_impl_ptr(int64_t* /*unused*/) noexcept
+    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
     {
         return is_number_integer() ? &m_value.number_integer : nullptr;
     }
 
     /// get a pointer to the value (integer number)
-    const int64_t* get_impl_ptr(const int64_t* /*unused*/) const noexcept
+    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
     {
         return is_number_integer() ? &m_value.number_integer : nullptr;
     }
 
     /// get a pointer to the value (unsigned number)
-    uint64_t* get_impl_ptr(uint64_t* /*unused*/) noexcept
+    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
     {
         return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
     }
 
     /// get a pointer to the value (unsigned number)
-    const uint64_t* get_impl_ptr(const uint64_t* /*unused*/) const noexcept
+    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
     {
         return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
     }
 
     /// get a pointer to the value (floating-point number)
-    double* get_impl_ptr(double* /*unused*/) noexcept
+    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
     {
         return is_number_float() ? &m_value.number_float : nullptr;
     }
 
     /// get a pointer to the value (floating-point number)
-    const double* get_impl_ptr(const double* /*unused*/) const noexcept
+    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
     {
         return is_number_float() ? &m_value.number_float : nullptr;
     }
 
+    /// get a pointer to the value (binary)
+    binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
+    {
+        return is_binary() ? m_value.binary : nullptr;
+    }
+
+    /// get a pointer to the value (binary)
+    constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
+    {
+        return is_binary() ? m_value.binary : nullptr;
+    }
+
     /*!
     @brief helper function to implement get_ref()
 
     This function helps to implement get_ref() without code duplication for
     const and non-const overloads
 
-    @tparam ThisType will be deduced as `json` or `const json`
+    @tparam ThisType will be deduced as `basic_json` or `const basic_json`
 
     @throw type_error.303 if ReferenceType does not match underlying value
     type of the current JSON
@@ -4263,14 +1527,14 @@
     static ReferenceType get_ref_impl(ThisType& obj)
     {
         // delegate the call to get_ptr<>()
-        auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
+        auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
 
-        if (JSON_LIKELY(ptr != nullptr))
+        if (JSON_HEDLEY_LIKELY(ptr != nullptr))
         {
             return *ptr;
         }
 
-        JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is", obj.type_name()));
+        JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
     }
 
   public:
@@ -4278,52 +1542,51 @@
     /// Direct access to the stored value of a JSON value.
     /// @{
 
-    /*!
-    @brief get special-case overload
-
-    This overloads avoids a lot of template boilerplate, it can be seen as the
-    identity method
-
-    @tparam BasicJsonType == @ref json
-
-    @return a copy of *this
-
-    @complexity Constant.
-
-    @since version 2.1.0
-    */
-    template<typename BasicJsonType, detail::enable_if_t<
-                 std::is_same<typename std::remove_const<BasicJsonType>::type, json_t>::value,
-                 int> = 0>
-    json get() const
+    /// @brief get a pointer value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
+    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
     {
-        return *this;
+        // delegate the call to get_impl_ptr<>()
+        return get_impl_ptr(static_cast<PointerType>(nullptr));
     }
 
+    /// @brief get a pointer value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
+    template < typename PointerType, typename std::enable_if <
+                   std::is_pointer<PointerType>::value&&
+                   std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
+    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
+    {
+        // delegate the call to get_impl_ptr<>() const
+        return get_impl_ptr(static_cast<PointerType>(nullptr));
+    }
+
+  private:
     /*!
     @brief get a value (explicit)
 
     Explicit type conversion between the JSON value and a compatible value
-    which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible)
-    and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible).
+    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
+    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
     The value is converted by calling the @ref json_serializer<ValueType>
     `from_json()` method.
 
     The function is equivalent to executing
     @code {.cpp}
     ValueType ret;
-    adl_serializer<ValueType, void>::from_json(*this, ret);
+    JSONSerializer<ValueType>::from_json(*this, ret);
     return ret;
     @endcode
 
     This overloads is chosen if:
-    - @a ValueType is not @ref json,
+    - @a ValueType is not @ref basic_json,
     - @ref json_serializer<ValueType> has a `from_json()` method of the form
-      `void from_json(const json&, ValueType&)`, and
+      `void from_json(const basic_json&, ValueType&)`, and
     - @ref json_serializer<ValueType> does not have a `from_json()` method of
-      the form `ValueType from_json(const json&)`
+      the form `ValueType from_json(const basic_json&)`
 
-    @tparam ValueTypeCV the provided value type
     @tparam ValueType the returned value type
 
     @return copy of the JSON value, converted to @a ValueType
@@ -4339,25 +1602,16 @@
 
     @since version 2.1.0
     */
-    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
-             detail::enable_if_t <
-                 not detail::is_json<ValueType>::value and
-                 detail::has_from_json<json_t, ValueType>::value and
-                 not detail::has_non_default_from_json<json_t, ValueType>::value,
-                 int> = 0>
-    ValueType get() const noexcept(noexcept(
-                                       adl_serializer<ValueType, void>::from_json(std::declval<const json_t&>(), std::declval<ValueType&>())))
+    template < typename ValueType,
+               detail::enable_if_t <
+                   detail::is_default_constructible<ValueType>::value&&
+                   detail::has_from_json<basic_json_t, ValueType>::value,
+                   int > = 0 >
+    ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
+                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
     {
-        // we cannot static_assert on ValueTypeCV being non-const, because
-        // there is support for get<const json_t>(), which is why we
-        // still need the uncvref
-        static_assert(not std::is_reference<ValueTypeCV>::value,
-                      "get() cannot be used with reference types, you might want to use get_ref()");
-        static_assert(std::is_default_constructible<ValueType>::value,
-                      "types must be DefaultConstructible when used with get()");
-
-        ValueType ret;
-        adl_serializer<ValueType, void>::from_json(*this, ret);
+        auto ret = ValueType();
+        JSONSerializer<ValueType>::from_json(*this, ret);
         return ret;
     }
 
@@ -4365,25 +1619,24 @@
     @brief get a value (explicit); special case
 
     Explicit type conversion between the JSON value and a compatible value
-    which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible)
-    and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible).
+    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
+    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
     The value is converted by calling the @ref json_serializer<ValueType>
     `from_json()` method.
 
     The function is equivalent to executing
     @code {.cpp}
-    return adl_serializer<ValueTypeCV, void>::from_json(*this);
+    return JSONSerializer<ValueType>::from_json(*this);
     @endcode
 
     This overloads is chosen if:
-    - @a ValueType is not @ref json and
+    - @a ValueType is not @ref basic_json and
     - @ref json_serializer<ValueType> has a `from_json()` method of the form
-      `ValueType from_json(const json&)`
+      `ValueType from_json(const basic_json&)`
 
     @note If @ref json_serializer<ValueType> has both overloads of
     `from_json()`, this one is chosen.
 
-    @tparam ValueTypeCV the provided value type
     @tparam ValueType the returned value type
 
     @return copy of the JSON value, converted to @a ValueType
@@ -4392,16 +1645,116 @@
 
     @since version 2.1.0
     */
-    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
-             detail::enable_if_t<not std::is_same<json_t, ValueType>::value and
-                                 detail::has_non_default_from_json<json_t, ValueType>::value,
-                                 int> = 0>
-    ValueType get() const noexcept(noexcept(
-                                       adl_serializer<ValueTypeCV, void>::from_json(std::declval<const json_t&>())))
+    template < typename ValueType,
+               detail::enable_if_t <
+                   detail::has_non_default_from_json<basic_json_t, ValueType>::value,
+                   int > = 0 >
+    ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
+                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
     {
-        static_assert(not std::is_reference<ValueTypeCV>::value,
+        return JSONSerializer<ValueType>::from_json(*this);
+    }
+
+    /*!
+    @brief get special-case overload
+
+    This overloads converts the current @ref basic_json in a different
+    @ref basic_json type
+
+    @tparam BasicJsonType == @ref basic_json
+
+    @return a copy of *this, converted into @a BasicJsonType
+
+    @complexity Depending on the implementation of the called `from_json()`
+                method.
+
+    @since version 3.2.0
+    */
+    template < typename BasicJsonType,
+               detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value,
+                   int > = 0 >
+    BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
+    {
+        return *this;
+    }
+
+    /*!
+    @brief get special-case overload
+
+    This overloads avoids a lot of template boilerplate, it can be seen as the
+    identity method
+
+    @tparam BasicJsonType == @ref basic_json
+
+    @return a copy of *this
+
+    @complexity Constant.
+
+    @since version 2.1.0
+    */
+    template<typename BasicJsonType,
+             detail::enable_if_t<
+                 std::is_same<BasicJsonType, basic_json_t>::value,
+                 int> = 0>
+    basic_json get_impl(detail::priority_tag<3> /*unused*/) const
+    {
+        return *this;
+    }
+
+    /*!
+    @brief get a pointer value (explicit)
+    @copydoc get()
+    */
+    template<typename PointerType,
+             detail::enable_if_t<
+                 std::is_pointer<PointerType>::value,
+                 int> = 0>
+    constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
+    -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
+    {
+        // delegate the call to get_ptr
+        return get_ptr<PointerType>();
+    }
+
+  public:
+    /*!
+    @brief get a (pointer) value (explicit)
+
+    Performs explicit type conversion between the JSON value and a compatible value if required.
+
+    - If the requested type is a pointer to the internally stored JSON value that pointer is returned.
+    No copies are made.
+
+    - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible
+    from the current @ref basic_json.
+
+    - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`
+    method.
+
+    @tparam ValueTypeCV the provided value type
+    @tparam ValueType the returned value type
+
+    @return copy of the JSON value, converted to @tparam ValueType if necessary
+
+    @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
+
+    @since version 2.1.0
+    */
+    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
+#if defined(JSON_HAS_CPP_14)
+    constexpr
+#endif
+    auto get() const noexcept(
+    noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
+    -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
+    {
+        // we cannot static_assert on ValueTypeCV being non-const, because
+        // there is support for get<const basic_json_t>(), which is why we
+        // still need the uncvref
+        static_assert(!std::is_reference<ValueTypeCV>::value,
                       "get() cannot be used with reference types, you might want to use get_ref()");
-        return adl_serializer<ValueTypeCV, void>::from_json(*this);
+        return get_impl<ValueType>(detail::priority_tag<4> {});
     }
 
     /*!
@@ -4414,7 +1767,8 @@
     changes.
 
     @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
-    object_t, `std::string`, bool, int64_t, uint64_t, or double.
+    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+    @ref number_unsigned_t, or @ref number_float_t.
 
     @return pointer to the internally stored JSON value if the requested
     pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -4426,132 +1780,59 @@
     `nullptr` is returned if the value and the requested pointer type does not
     match.,get__PointerType}
 
-    @sa @ref get_ptr() for explicit pointer-member access
+    @sa see @ref get_ptr() for explicit pointer-member access
 
     @since version 1.0.0
     */
     template<typename PointerType, typename std::enable_if<
                  std::is_pointer<PointerType>::value, int>::type = 0>
-    PointerType get() noexcept
+    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
     {
         // delegate the call to get_ptr
         return get_ptr<PointerType>();
     }
 
-    /*!
-    @brief get a pointer value (explicit)
-    @copydoc get()
-    */
-    template<typename PointerType, typename std::enable_if<
-                 std::is_pointer<PointerType>::value, int>::type = 0>
-    const PointerType get() const noexcept
+    /// @brief get a value (explicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_to/
+    template < typename ValueType,
+               detail::enable_if_t <
+                   !detail::is_basic_json<ValueType>::value&&
+                   detail::has_from_json<basic_json_t, ValueType>::value,
+                   int > = 0 >
+    ValueType & get_to(ValueType& v) const noexcept(noexcept(
+                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
     {
-        // delegate the call to get_ptr
-        return get_ptr<PointerType>();
+        JSONSerializer<ValueType>::from_json(*this, v);
+        return v;
     }
 
-    /*!
-    @brief get a pointer value (implicit)
-
-    Implicit pointer access to the internally stored JSON value. No copies are
-    made.
-
-    @warning Writing data to the pointee of the result yields an undefined
-    state.
-
-    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
-    object_t, `std::string`, bool, int64_t,
-    uint64_t, or double. Enforced by a static assertion.
-
-    @return pointer to the internally stored JSON value if the requested
-    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
-
-    @complexity Constant.
-
-    @liveexample{The example below shows how pointers to internal values of a
-    JSON value can be requested. Note that no type conversions are made and a
-    `nullptr` is returned if the value and the requested pointer type does not
-    match.,get_ptr}
-
-    @since version 1.0.0
-    */
-    template<typename PointerType, typename std::enable_if<
-                 std::is_pointer<PointerType>::value, int>::type = 0>
-    PointerType get_ptr() noexcept
+    // specialization to allow calling get_to with a basic_json value
+    // see https://github.com/nlohmann/json/issues/2175
+    template<typename ValueType,
+             detail::enable_if_t <
+                 detail::is_basic_json<ValueType>::value,
+                 int> = 0>
+    ValueType & get_to(ValueType& v) const
     {
-        // get the type of the PointerType (remove pointer and const)
-        using pointee_t = typename std::remove_const<typename
-                          std::remove_pointer<typename
-                          std::remove_const<PointerType>::type>::type>::type;
-        // make sure the type matches the allowed types
-        static_assert(
-            std::is_same<object_t, pointee_t>::value
-            or std::is_same<array_t, pointee_t>::value
-            or std::is_same<std::string, pointee_t>::value
-            or std::is_same<bool, pointee_t>::value
-            or std::is_same<int64_t, pointee_t>::value
-            or std::is_same<uint64_t, pointee_t>::value
-            or std::is_same<double, pointee_t>::value
-            , "incompatible pointer type");
-
-        // delegate the call to get_impl_ptr<>()
-        return get_impl_ptr(static_cast<PointerType>(nullptr));
+        v = *this;
+        return v;
     }
 
-    /*!
-    @brief get a pointer value (implicit)
-    @copydoc get_ptr()
-    */
-    template<typename PointerType, typename std::enable_if<
-                 std::is_pointer<PointerType>::value and
-                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
-    const PointerType get_ptr() const noexcept
+    template <
+        typename T, std::size_t N,
+        typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+        detail::enable_if_t <
+            detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
+    Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+    noexcept(noexcept(JSONSerializer<Array>::from_json(
+                          std::declval<const basic_json_t&>(), v)))
     {
-        // get the type of the PointerType (remove pointer and const)
-        using pointee_t = typename std::remove_const<typename
-                          std::remove_pointer<typename
-                          std::remove_const<PointerType>::type>::type>::type;
-        // make sure the type matches the allowed types
-        static_assert(
-            std::is_same<object_t, pointee_t>::value
-            or std::is_same<array_t, pointee_t>::value
-            or std::is_same<std::string, pointee_t>::value
-            or std::is_same<bool, pointee_t>::value
-            or std::is_same<int64_t, pointee_t>::value
-            or std::is_same<uint64_t, pointee_t>::value
-            or std::is_same<double, pointee_t>::value
-            , "incompatible pointer type");
-
-        // delegate the call to get_impl_ptr<>() const
-        return get_impl_ptr(static_cast<PointerType>(nullptr));
+        JSONSerializer<Array>::from_json(*this, v);
+        return v;
     }
 
-    /*!
-    @brief get a reference value (implicit)
-
-    Implicit reference access to the internally stored JSON value. No copies
-    are made.
-
-    @warning Writing data to the referee of the result yields an undefined
-    state.
-
-    @tparam ReferenceType reference type; must be a reference to @ref array_t,
-    @ref object_t, std::string, bool, int64_t, or
-    double. Enforced by static assertion.
-
-    @return reference to the internally stored JSON value if the requested
-    reference type @a ReferenceType fits to the JSON value; throws
-    type_error.303 otherwise
-
-    @throw type_error.303 in case passed type @a ReferenceType is incompatible
-    with the stored JSON value; see example below
-
-    @complexity Constant.
-
-    @liveexample{The example shows several calls to `get_ref()`.,get_ref}
-
-    @since version 1.1.0
-    */
+    /// @brief get a reference value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
     template<typename ReferenceType, typename std::enable_if<
                  std::is_reference<ReferenceType>::value, int>::type = 0>
     ReferenceType get_ref()
@@ -4560,13 +1841,11 @@
         return get_ref_impl<ReferenceType>(*this);
     }
 
-    /*!
-    @brief get a reference value (implicit)
-    @copydoc get_ref()
-    */
-    template<typename ReferenceType, typename std::enable_if<
-                 std::is_reference<ReferenceType>::value and
-                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
+    /// @brief get a reference value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
+    template < typename ReferenceType, typename std::enable_if <
+                   std::is_reference<ReferenceType>::value&&
+                   std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
     ReferenceType get_ref() const
     {
         // delegate call to get_ref_impl
@@ -4581,7 +1860,7 @@
 
     @tparam ValueType non-pointer type compatible to the JSON value, for
     instance `int` for JSON integer numbers, `bool` for JSON booleans, or
-    `std::vector` types for JSON arrays. The character type of `std::string`
+    `std::vector` types for JSON arrays. The character type of @ref string_t
     as well as an initializer list of this type is excluded to avoid
     ambiguities as these types implicitly convert to `std::string`.
 
@@ -4603,21 +1882,51 @@
     @since version 1.0.0
     */
     template < typename ValueType, typename std::enable_if <
-                   not std::is_pointer<ValueType>::value and
-                   not std::is_same<ValueType, detail::json_ref<json>>::value and
-                   not std::is_same<ValueType, std::string::value_type>::value and
-                   not detail::is_json<ValueType>::value
-#ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015
-                   and not std::is_same<ValueType, std::initializer_list<std::string::value_type>>::value
+                   detail::conjunction <
+                       detail::negation<std::is_pointer<ValueType>>,
+                       detail::negation<std::is_same<ValueType, std::nullptr_t>>,
+                       detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
+                                        detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
+                                        detail::negation<detail::is_basic_json<ValueType>>,
+                                        detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
+#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
+                                                detail::negation<std::is_same<ValueType, std::string_view>>,
 #endif
-                   and not std::is_same<ValueType, typename std::string_view>::value
-                   , int >::type = 0 >
-    operator ValueType() const
+#if defined(JSON_HAS_CPP_17)
+                                                detail::negation<std::is_same<ValueType, std::any>>,
+#endif
+                                                detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
+                                                >::value, int >::type = 0 >
+                                        JSON_EXPLICIT operator ValueType() const
     {
         // delegate the call to get<>() const
         return get<ValueType>();
     }
 
+    /// @brief get a binary value
+    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
+    binary_t& get_binary()
+    {
+        if (!is_binary())
+        {
+            JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
+        }
+
+        return *get_ptr<binary_t*>();
+    }
+
+    /// @brief get a binary value
+    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
+    const binary_t& get_binary() const
+    {
+        if (!is_binary())
+        {
+            JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
+        }
+
+        return *get_ptr<const binary_t*>();
+    }
+
     /// @}
 
 
@@ -4629,542 +1938,478 @@
     /// Access to the JSON value.
     /// @{
 
-    /*!
-    @brief access specified array element with bounds checking
-
-    Returns a reference to the element at specified location @a idx, with
-    bounds checking.
-
-    @param[in] idx  index of the element to access
-
-    @return reference to the element at index @a idx
-
-    @throw type_error.304 if the JSON value is not an array; in this case,
-    calling `at` with an index makes no sense. See example below.
-    @throw out_of_range.401 if the index @a idx is out of range of the array;
-    that is, `idx >= size()`. See example below.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Constant.
-
-    @since version 1.0.0
-
-    @liveexample{The example below shows how array elements can be read and
-    written using `at()`. It also demonstrates the different exceptions that
-    can be thrown.,at__size_type}
-    */
-    reference at(size_type idx);
-
-    /*!
-    @brief access specified array element with bounds checking
-
-    Returns a const reference to the element at specified location @a idx,
-    with bounds checking.
-
-    @param[in] idx  index of the element to access
-
-    @return const reference to the element at index @a idx
-
-    @throw type_error.304 if the JSON value is not an array; in this case,
-    calling `at` with an index makes no sense. See example below.
-    @throw out_of_range.401 if the index @a idx is out of range of the array;
-    that is, `idx >= size()`. See example below.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Constant.
-
-    @since version 1.0.0
-
-    @liveexample{The example below shows how array elements can be read using
-    `at()`. It also demonstrates the different exceptions that can be thrown.,
-    at__size_type_const}
-    */
-    const_reference at(size_type idx) const;
-
-    /*!
-    @brief access specified object element with bounds checking
-
-    Returns a reference to the element at with specified key @a key, with
-    bounds checking.
-
-    @param[in] key  key of the element to access
-
-    @return reference to the element at key @a key
-
-    @throw type_error.304 if the JSON value is not an object; in this case,
-    calling `at` with a key makes no sense. See example below.
-    @throw out_of_range.403 if the key @a key is is not stored in the object;
-    that is, `find(key) == end()`. See example below.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Logarithmic in the size of the container.
-
-    @sa @ref operator[](const typename object_t::key_type&) for unchecked
-    access by reference
-    @sa @ref value() for access by value with a default value
-
-    @since version 1.0.0
-
-    @liveexample{The example below shows how object elements can be read and
-    written using `at()`. It also demonstrates the different exceptions that
-    can be thrown.,at__object_t_key_type}
-    */
-    reference at(std::string_view key);
-
-    /*!
-    @brief access specified object element with bounds checking
-
-    Returns a const reference to the element at with specified key @a key,
-    with bounds checking.
-
-    @param[in] key  key of the element to access
-
-    @return const reference to the element at key @a key
-
-    @throw type_error.304 if the JSON value is not an object; in this case,
-    calling `at` with a key makes no sense. See example below.
-    @throw out_of_range.403 if the key @a key is is not stored in the object;
-    that is, `find(key) == end()`. See example below.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Logarithmic in the size of the container.
-
-    @sa @ref operator[](const typename object_t::key_type&) for unchecked
-    access by reference
-    @sa @ref value() for access by value with a default value
-
-    @since version 1.0.0
-
-    @liveexample{The example below shows how object elements can be read using
-    `at()`. It also demonstrates the different exceptions that can be thrown.,
-    at__object_t_key_type_const}
-    */
-    const_reference at(std::string_view key) const;
-
-    /*!
-    @brief access specified array element
-
-    Returns a reference to the element at specified location @a idx.
-
-    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
-    then the array is silently filled up with `null` values to make `idx` a
-    valid reference to the last stored element.
-
-    @param[in] idx  index of the element to access
-
-    @return reference to the element at index @a idx
-
-    @throw type_error.305 if the JSON value is not an array or null; in that
-    cases, using the [] operator with an index makes no sense.
-
-    @complexity Constant if @a idx is in the range of the array. Otherwise
-    linear in `idx - size()`.
-
-    @liveexample{The example below shows how array elements can be read and
-    written using `[]` operator. Note the addition of `null`
-    values.,operatorarray__size_type}
-
-    @since version 1.0.0
-    */
-    reference operator[](size_type idx);
-
-    /*!
-    @brief access specified array element
-
-    Returns a const reference to the element at specified location @a idx.
-
-    @param[in] idx  index of the element to access
-
-    @return const reference to the element at index @a idx
-
-    @throw type_error.305 if the JSON value is not an array; in that case,
-    using the [] operator with an index makes no sense.
-
-    @complexity Constant.
-
-    @liveexample{The example below shows how array elements can be read using
-    the `[]` operator.,operatorarray__size_type_const}
-
-    @since version 1.0.0
-    */
-    const_reference operator[](size_type idx) const;
-
-    /*!
-    @brief access specified object element
-
-    Returns a reference to the element at with specified key @a key.
-
-    @note If @a key is not found in the object, then it is silently added to
-    the object and filled with a `null` value to make `key` a valid reference.
-    In case the value was `null` before, it is converted to an object.
-
-    @param[in] key  key of the element to access
-
-    @return reference to the element at key @a key
-
-    @throw type_error.305 if the JSON value is not an object or null; in that
-    cases, using the [] operator with a key makes no sense.
-
-    @complexity Logarithmic in the size of the container.
-
-    @liveexample{The example below shows how object elements can be read and
-    written using the `[]` operator.,operatorarray__key_type}
-
-    @sa @ref at(const typename object_t::key_type&) for access by reference
-    with range checking
-    @sa @ref value() for access by value with a default value
-
-    @since version 1.0.0
-    */
-    reference operator[](std::string_view key);
-
-    /*!
-    @brief read-only access specified object element
-
-    Returns a const reference to the element at with specified key @a key. No
-    bounds checking is performed.
-
-    @warning If the element with key @a key does not exist, the behavior is
-    undefined.
-
-    @param[in] key  key of the element to access
-
-    @return const reference to the element at key @a key
-
-    @pre The element with key @a key must exist. **This precondition is
-         enforced with an assertion.**
-
-    @throw type_error.305 if the JSON value is not an object; in that case,
-    using the [] operator with a key makes no sense.
-
-    @complexity Logarithmic in the size of the container.
-
-    @liveexample{The example below shows how object elements can be read using
-    the `[]` operator.,operatorarray__key_type_const}
-
-    @sa @ref at(const typename object_t::key_type&) for access by reference
-    with range checking
-    @sa @ref value() for access by value with a default value
-
-    @since version 1.0.0
-    */
-    const_reference operator[](std::string_view key) const;
-
-    /*!
-    @brief access specified object element
-
-    Returns a reference to the element at with specified key @a key.
-
-    @note If @a key is not found in the object, then it is silently added to
-    the object and filled with a `null` value to make `key` a valid reference.
-    In case the value was `null` before, it is converted to an object.
-
-    @param[in] key  key of the element to access
-
-    @return reference to the element at key @a key
-
-    @throw type_error.305 if the JSON value is not an object or null; in that
-    cases, using the [] operator with a key makes no sense.
-
-    @complexity Logarithmic in the size of the container.
-
-    @liveexample{The example below shows how object elements can be read and
-    written using the `[]` operator.,operatorarray__key_type}
-
-    @sa @ref at(const typename object_t::key_type&) for access by reference
-    with range checking
-    @sa @ref value() for access by value with a default value
-
-    @since version 1.1.0
-    */
-    template<typename T>
-    reference operator[](T* key)
+    /// @brief access specified array element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    reference at(size_type idx)
     {
-        // implicitly convert null to object
+        // at only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            JSON_TRY
+            {
+                return set_parent(m_value.array->at(idx));
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
+            }
+        }
+        else
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+    }
+
+    /// @brief access specified array element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    const_reference at(size_type idx) const
+    {
+        // at only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            JSON_TRY
+            {
+                return m_value.array->at(idx);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
+            }
+        }
+        else
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    reference at(const typename object_t::key_type& key)
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(key);
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
+        }
+        return set_parent(it->second);
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    reference at(KeyType && key)
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(std::forward<KeyType>(key));
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
+        }
+        return set_parent(it->second);
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    const_reference at(const typename object_t::key_type& key) const
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(key);
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
+        }
+        return it->second;
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    const_reference at(KeyType && key) const
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(std::forward<KeyType>(key));
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
+        }
+        return it->second;
+    }
+
+    /// @brief access specified array element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    reference operator[](size_type idx)
+    {
+        // implicitly convert null value to an empty array
         if (is_null())
         {
-            m_type = value_t::object;
-            m_value = value_t::object;
+            m_type = value_t::array;
+            m_value.array = create<array_t>();
             assert_invariant();
         }
 
-        // at only works for objects
-        if (JSON_LIKELY(is_object()))
+        // operator[] only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
         {
-            return m_value.object->operator[](key);
+            // fill up array with null values if given idx is outside range
+            if (idx >= m_value.array->size())
+            {
+#if JSON_DIAGNOSTICS
+                // remember array size & capacity before resizing
+                const auto old_size = m_value.array->size();
+                const auto old_capacity = m_value.array->capacity();
+#endif
+                m_value.array->resize(idx + 1);
+
+#if JSON_DIAGNOSTICS
+                if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
+                {
+                    // capacity has changed: update all parents
+                    set_parents();
+                }
+                else
+                {
+                    // set parent for values added above
+                    set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));
+                }
+#endif
+                assert_invariant();
+            }
+
+            return m_value.array->operator[](idx);
         }
 
-        JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
     }
 
-    /*!
-    @brief read-only access specified object element
+    /// @brief access specified array element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    const_reference operator[](size_type idx) const
+    {
+        // const operator[] only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            return m_value.array->operator[](idx);
+        }
 
-    Returns a const reference to the element at with specified key @a key. No
-    bounds checking is performed.
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
+    }
 
-    @warning If the element with key @a key does not exist, the behavior is
-    undefined.
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    reference operator[](typename object_t::key_type key)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
 
-    @param[in] key  key of the element to access
+        // operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto result = m_value.object->emplace(std::move(key), nullptr);
+            return set_parent(result.first->second);
+        }
 
-    @return const reference to the element at key @a key
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
 
-    @pre The element with key @a key must exist. **This precondition is
-         enforced with an assertion.**
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    const_reference operator[](const typename object_t::key_type& key) const
+    {
+        // const operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto it = m_value.object->find(key);
+            JSON_ASSERT(it != m_value.object->end());
+            return it->second;
+        }
 
-    @throw type_error.305 if the JSON value is not an object; in that case,
-    using the [] operator with a key makes no sense.
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
 
-    @complexity Logarithmic in the size of the container.
+    // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
+    // (they seemingly cannot be constrained to resolve the ambiguity)
+    template<typename T>
+    reference operator[](T* key)
+    {
+        return operator[](typename object_t::key_type(key));
+    }
 
-    @liveexample{The example below shows how object elements can be read using
-    the `[]` operator.,operatorarray__key_type_const}
-
-    @sa @ref at(const typename object_t::key_type&) for access by reference
-    with range checking
-    @sa @ref value() for access by value with a default value
-
-    @since version 1.1.0
-    */
     template<typename T>
     const_reference operator[](T* key) const
     {
-        // at only works for objects
-        if (JSON_LIKELY(is_object()))
+        return operator[](typename object_t::key_type(key));
+    }
+
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    reference operator[](KeyType && key)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
         {
-            assert(m_value.object->find(key) != m_value.object->end());
-            return m_value.object->find(key)->second;
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
         }
 
-        JSON_THROW(type_error::create(305, "cannot use operator[] with", type_name()));
+        // operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto result = m_value.object->emplace(std::forward<KeyType>(key), nullptr);
+            return set_parent(result.first->second);
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
     }
 
-    /*!
-    @brief access specified object element with default value
-
-    Returns either a copy of an object's element at the specified key @a key
-    or a given default value if no element with key @a key exists.
-
-    The function is basically equivalent to executing
-    @code {.cpp}
-    try {
-        return at(key);
-    } catch(out_of_range) {
-        return default_value;
-    }
-    @endcode
-
-    @note Unlike @ref at(const typename object_t::key_type&), this function
-    does not throw if the given key @a key was not found.
-
-    @note Unlike @ref operator[](const typename object_t::key_type& key), this
-    function does not implicitly add an element to the position defined by @a
-    key. This function is furthermore also applicable to const objects.
-
-    @param[in] key  key of the element to access
-    @param[in] default_value  the value to return if @a key is not found
-
-    @tparam ValueType type compatible to JSON values, for instance `int` for
-    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
-    JSON arrays. Note the type of the expected value at @a key and the default
-    value @a default_value must be compatible.
-
-    @return copy of the element at key @a key or @a default_value if @a key
-    is not found
-
-    @throw type_error.306 if the JSON value is not an object; in that case,
-    using `value()` with a key makes no sense.
-
-    @complexity Logarithmic in the size of the container.
-
-    @liveexample{The example below shows how object elements can be queried
-    with a default value.,json__value}
-
-    @sa @ref at(const typename object_t::key_type&) for access by reference
-    with range checking
-    @sa @ref operator[](const typename object_t::key_type&) for unchecked
-    access by reference
-
-    @since version 1.0.0
-    */
-    template<class ValueType, typename std::enable_if<
-                 std::is_convertible<json_t, ValueType>::value, int>::type = 0>
-    ValueType value(std::string_view key, const ValueType& default_value) const
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    const_reference operator[](KeyType && key) const
     {
-        // at only works for objects
-        if (JSON_LIKELY(is_object()))
+        // const operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto it = m_value.object->find(std::forward<KeyType>(key));
+            JSON_ASSERT(it != m_value.object->end());
+            return it->second;
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
+
+  private:
+    template<typename KeyType>
+    using is_comparable_with_object_key = detail::is_comparable <
+        object_comparator_t, const typename object_t::key_type&, KeyType >;
+
+    template<typename ValueType>
+    using value_return_type = std::conditional <
+        detail::is_c_string_uncvref<ValueType>::value,
+        string_t, typename std::decay<ValueType>::type >;
+
+  public:
+    /// @brief access specified object element with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, detail::enable_if_t <
+                   !detail::is_transparent<object_comparator_t>::value
+                   && detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
         {
             // if key is found, return value and given default value otherwise
             const auto it = find(key);
             if (it != end())
             {
-                return *it;
+                return it->template get<ValueType>();
             }
 
             return default_value;
         }
 
-        JSON_THROW(type_error::create(306, "cannot use value() with", type_name()));
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
     }
 
-    /*!
-    @brief overload for a default value of type const char*
-    @copydoc json::value(const typename object_t::key_type&, ValueType) const
-    */
-    std::string value(std::string_view key, const char* default_value) const
+    /// @brief access specified object element with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   !detail::is_transparent<object_comparator_t>::value
+                   && detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
     {
-        return value(key, std::string(default_value));
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(key);
+            if (it != end())
+            {
+                return it->template get<ReturnType>();
+            }
+
+            return std::forward<ValueType>(default_value);
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
     }
 
-    /*!
-    @brief access specified object element via JSON Pointer with default value
+    /// @brief access specified object element with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class KeyType, detail::enable_if_t <
+                   detail::is_transparent<object_comparator_t>::value
+                   && !detail::is_json_pointer<KeyType>::value
+                   && is_comparable_with_object_key<KeyType>::value
+                   && detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ValueType value(KeyType && key, const ValueType& default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(std::forward<KeyType>(key));
+            if (it != end())
+            {
+                return it->template get<ValueType>();
+            }
 
-    Returns either a copy of an object's element at the specified key @a key
-    or a given default value if no element with key @a key exists.
+            return default_value;
+        }
 
-    The function is basically equivalent to executing
-    @code {.cpp}
-    try {
-        return at(ptr);
-    } catch(out_of_range) {
-        return default_value;
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
     }
-    @endcode
 
-    @note Unlike @ref at(const json_pointer&), this function does not throw
-    if the given key @a key was not found.
+    /// @brief access specified object element via JSON Pointer with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   detail::is_transparent<object_comparator_t>::value
+                   && !detail::is_json_pointer<KeyType>::value
+                   && is_comparable_with_object_key<KeyType>::value
+                   && detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ReturnType value(KeyType && key, ValueType && default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(std::forward<KeyType>(key));
+            if (it != end())
+            {
+                return it->template get<ReturnType>();
+            }
 
-    @param[in] ptr  a JSON pointer to the element to access
-    @param[in] default_value  the value to return if @a ptr found no value
+            return std::forward<ValueType>(default_value);
+        }
 
-    @tparam ValueType type compatible to JSON values, for instance `int` for
-    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
-    JSON arrays. Note the type of the expected value at @a key and the default
-    value @a default_value must be compatible.
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
 
-    @return copy of the element at key @a key or @a default_value if @a key
-    is not found
-
-    @throw type_error.306 if the JSON value is not an object; in that case,
-    using `value()` with a key makes no sense.
-
-    @complexity Logarithmic in the size of the container.
-
-    @liveexample{The example below shows how object elements can be queried
-    with a default value.,json__value_ptr}
-
-    @sa @ref operator[](const json_pointer&) for unchecked access by reference
-
-    @since version 2.0.2
-    */
-    template<class ValueType, typename std::enable_if<
-                 std::is_convertible<json_t, ValueType>::value, int>::type = 0>
+    /// @brief access specified object element via JSON Pointer with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, detail::enable_if_t <
+                   detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
     ValueType value(const json_pointer& ptr, const ValueType& default_value) const
     {
-        // at only works for objects
-        if (JSON_LIKELY(is_object()))
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
         {
             // if pointer resolves a value, return it or use default value
             JSON_TRY
             {
-                return ptr.get_checked(this);
+                return ptr.get_checked(this).template get<ValueType>();
             }
-            JSON_CATCH (out_of_range&)
+            JSON_INTERNAL_CATCH (out_of_range&)
             {
                 return default_value;
             }
         }
 
-        JSON_THROW(type_error::create(306, "cannot use value() with", type_name()));
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
     }
 
-    /*!
-    @brief overload for a default value of type const char*
-    @copydoc json::value(const json_pointer&, ValueType) const
-    */
-    std::string value(const json_pointer& ptr, const char* default_value) const
+    /// @brief access specified object element via JSON Pointer with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ReturnType value(const json_pointer& ptr, ValueType && default_value) const
     {
-        return value(ptr, std::string(default_value));
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if pointer resolves a value, return it or use default value
+            JSON_TRY
+            {
+                return ptr.get_checked(this).template get<ReturnType>();
+            }
+            JSON_INTERNAL_CATCH (out_of_range&)
+            {
+                return std::forward<ValueType>(default_value);
+            }
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
     }
 
-    /*!
-    @brief access the first element
+    template < class ValueType, class BasicJsonType, detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value
+                   && detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    ValueType value(const ::wpi::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
+    {
+        return value(ptr.convert(), default_value);
+    }
 
-    Returns a reference to the first element in the container. For a JSON
-    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
+    template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value
+                   && detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    ReturnType value(const ::wpi::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
+    {
+        return value(ptr.convert(), std::forward<ValueType>(default_value));
+    }
 
-    @return In case of a structured type (array or object), a reference to the
-    first element is returned. In case of number, string, or boolean values, a
-    reference to the value is returned.
-
-    @complexity Constant.
-
-    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
-    or an empty array or object (undefined behavior, **guarded by
-    assertions**).
-    @post The JSON value remains unchanged.
-
-    @throw invalid_iterator.214 when called on `null` value
-
-    @liveexample{The following code shows an example for `front()`.,front}
-
-    @sa @ref back() -- access the last element
-
-    @since version 1.0.0
-    */
+    /// @brief access the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/front/
     reference front()
     {
         return *begin();
     }
 
-    /*!
-    @copydoc json::front()
-    */
+    /// @brief access the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/front/
     const_reference front() const
     {
         return *cbegin();
     }
 
-    /*!
-    @brief access the last element
-
-    Returns a reference to the last element in the container. For a JSON
-    container `c`, the expression `c.back()` is equivalent to
-    @code {.cpp}
-    auto tmp = c.end();
-    --tmp;
-    return *tmp;
-    @endcode
-
-    @return In case of a structured type (array or object), a reference to the
-    last element is returned. In case of number, string, or boolean values, a
-    reference to the value is returned.
-
-    @complexity Constant.
-
-    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
-    or an empty array or object (undefined behavior, **guarded by
-    assertions**).
-    @post The JSON value remains unchanged.
-
-    @throw invalid_iterator.214 when called on a `null` value. See example
-    below.
-
-    @liveexample{The following code shows an example for `back()`.,back}
-
-    @sa @ref front() -- access the first element
-
-    @since version 1.0.0
-    */
+    /// @brief access the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/back/
     reference back()
     {
         auto tmp = end();
@@ -5172,9 +2417,8 @@
         return *tmp;
     }
 
-    /*!
-    @copydoc json::back()
-    */
+    /// @brief access the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/back/
     const_reference back() const
     {
         auto tmp = cend();
@@ -5182,161 +2426,17 @@
         return *tmp;
     }
 
-    /*!
-    @brief remove element given an iterator
-
-    Removes the element specified by iterator @a pos. The iterator @a pos must
-    be valid and dereferenceable. Thus the `end()` iterator (which is valid,
-    but is not dereferenceable) cannot be used as a value for @a pos.
-
-    If called on a primitive type other than `null`, the resulting JSON value
-    will be `null`.
-
-    @param[in] pos iterator to the element to remove
-
-    @tparam IteratorType an @ref iterator or @ref const_iterator
-
-    @post Invalidates iterators and references at or after the point of the
-    erase, including the `end()` iterator.
-
-    @throw type_error.307 if called on a `null` value; example: `"cannot use
-    erase() with null"`
-    @throw invalid_iterator.202 if called on an iterator which does not belong
-    to the current JSON value; example: `"iterator does not fit current
-    value"`
-    @throw invalid_iterator.205 if called on a primitive type with invalid
-    iterator (i.e., any iterator which is not `begin()`); example: `"iterator
-    out of range"`
-
-    @complexity The complexity depends on the type:
-    - objects: amortized constant
-    - arrays: linear in distance between @a pos and the end of the container
-    - strings: linear in the length of the string
-    - other types: constant
-
-    @liveexample{The example shows the result of `erase()` for different JSON
-    types.,erase__IteratorType}
-
-    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
-    the given range
-    @sa @ref erase(std::string_view) -- removes the element
-    from an object at the given key
-    @sa @ref erase(const size_type) -- removes the element from an array at
-    the given index
-
-    @since version 1.0.0
-    */
-    template<class IteratorType, typename std::enable_if<
-                 std::is_same<IteratorType, typename json_t::iterator>::value or
-                 std::is_same<IteratorType, typename json_t::const_iterator>::value, int>::type
-             = 0>
-    void erase(IteratorType pos)
+    /// @brief remove element given an iterator
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    template < class IteratorType, detail::enable_if_t <
+                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
+                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
+    IteratorType erase(IteratorType pos)
     {
         // make sure iterator fits the current value
-        if (JSON_UNLIKELY(this != pos.m_object))
+        if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
         {
-            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
-        }
-
-        switch (m_type)
-        {
-            case value_t::boolean:
-            case value_t::number_float:
-            case value_t::number_integer:
-            case value_t::number_unsigned:
-            case value_t::string:
-            {
-                if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))
-                {
-                    JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
-                }
-
-                if (is_string())
-                {
-                    std::allocator<std::string> alloc;
-					std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
-					std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
-                    m_value.string = nullptr;
-                }
-
-                m_type = value_t::null;
-                assert_invariant();
-                break;
-            }
-
-            case value_t::object:
-            {
-                m_value.object->erase(pos.m_it.object_iterator);
-                break;
-            }
-
-            case value_t::array:
-            {
-                m_value.array->erase(pos.m_it.array_iterator);
-                break;
-            }
-
-            default:
-                JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
-        }
-    }
-
-    /*!
-    @brief remove elements given an iterator range
-
-    Removes the element specified by the range `[first; last)`. The iterator
-    @a first does not need to be dereferenceable if `first == last`: erasing
-    an empty range is a no-op.
-
-    If called on a primitive type other than `null`, the resulting JSON value
-    will be `null`.
-
-    @param[in] first iterator to the beginning of the range to remove
-    @param[in] last iterator past the end of the range to remove
-    @return Iterator following the last removed element. If the iterator @a
-    second refers to the last element, the `end()` iterator is returned.
-
-    @tparam IteratorType an @ref iterator or @ref const_iterator
-
-    @post Invalidates iterators and references at or after the point of the
-    erase, including the `end()` iterator.
-
-    @throw type_error.307 if called on a `null` value; example: `"cannot use
-    erase() with null"`
-    @throw invalid_iterator.203 if called on iterators which does not belong
-    to the current JSON value; example: `"iterators do not fit current value"`
-    @throw invalid_iterator.204 if called on a primitive type with invalid
-    iterators (i.e., if `first != begin()` and `last != end()`); example:
-    `"iterators out of range"`
-
-    @complexity The complexity depends on the type:
-    - objects: `log(size()) + std::distance(first, last)`
-    - arrays: linear in the distance between @a first and @a last, plus linear
-      in the distance between @a last and end of the container
-    - strings: linear in the length of the string
-    - other types: constant
-
-    @liveexample{The example shows the result of `erase()` for different JSON
-    types.,erase__IteratorType_IteratorType}
-
-    @sa @ref erase(IteratorType) -- removes the element at a given position
-    @sa @ref erase(const typename object_t::key_type&) -- removes the element
-    from an object at the given key
-    @sa @ref erase(const size_type) -- removes the element from an array at
-    the given index
-
-    @since version 1.0.0
-    */
-    template<class IteratorType, typename std::enable_if<
-                 std::is_same<IteratorType, typename json_t::iterator>::value or
-                 std::is_same<IteratorType, typename json_t::const_iterator>::value, int>::type
-             = 0>
-    IteratorType erase(IteratorType first, IteratorType last)
-    {
-        // make sure iterator fits the current value
-        if (JSON_UNLIKELY(this != first.m_object or this != last.m_object))
-        {
-            JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
+            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
         }
 
         IteratorType result = end();
@@ -5348,26 +2448,111 @@
             case value_t::number_integer:
             case value_t::number_unsigned:
             case value_t::string:
+            case value_t::binary:
             {
-                if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin()
-                                or not last.m_it.primitive_iterator.is_end()))
+                if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
                 {
-                    JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
+                    JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
                 }
 
                 if (is_string())
                 {
-                    std::allocator<std::string> alloc;
-					std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
-					std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
+                    AllocatorType<string_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
                     m_value.string = nullptr;
                 }
+                else if (is_binary())
+                {
+                    AllocatorType<binary_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
+                    m_value.binary = nullptr;
+                }
 
                 m_type = value_t::null;
                 assert_invariant();
                 break;
             }
 
+            case value_t::object:
+            {
+                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+
+        return result;
+    }
+
+    /// @brief remove elements given an iterator range
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    template < class IteratorType, detail::enable_if_t <
+                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
+                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
+    IteratorType erase(IteratorType first, IteratorType last)
+    {
+        // make sure iterator fits the current value
+        if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
+        }
+
+        IteratorType result = end();
+
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            case value_t::binary:
+            {
+                if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
+                                       || !last.m_it.primitive_iterator.is_end()))
+                {
+                    JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
+                }
+
+                if (is_string())
+                {
+                    AllocatorType<string_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
+                    m_value.string = nullptr;
+                }
+                else if (is_binary())
+                {
+                    AllocatorType<binary_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
+                    m_value.binary = nullptr;
+                }
+
+                m_type = value_t::null;
+                assert_invariant();
+                break;
+            }
+
+            case value_t::object:
+            {
+                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
+                                              last.m_it.object_iterator);
+                break;
+            }
+
             case value_t::array:
             {
                 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
@@ -5375,69 +2560,87 @@
                 break;
             }
 
+            case value_t::null:
+            case value_t::discarded:
             default:
-                JSON_THROW(type_error::create(307, "cannot use erase() with", type_name()));
+                JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
         }
 
         return result;
     }
 
-    /*!
-    @brief remove element from a JSON object given a key
+  private:
+    template < typename KeyType, detail::enable_if_t <
+                   detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    size_type erase_internal(KeyType && key)
+    {
+        // this erase only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
 
-    Removes elements from a JSON object with the key value @a key.
+        return m_value.object->erase(std::forward<KeyType>(key));
+    }
 
-    @param[in] key value of the elements to remove
+    template < typename KeyType, detail::enable_if_t <
+                   !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    size_type erase_internal(KeyType && key)
+    {
+        // this erase only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
 
-    @return Number of elements removed. If @a ObjectType is the default
-    `std::map` type, the return value will always be `0` (@a key was not
-    found) or `1` (@a key was found).
+        const auto it = m_value.object->find(std::forward<KeyType>(key));
+        if (it != m_value.object->end())
+        {
+            m_value.object->erase(it);
+            return 1;
+        }
+        return 0;
+    }
 
-    @post References and iterators to the erased elements are invalidated.
-    Other references and iterators are not affected.
+  public:
 
-    @throw type_error.307 when called on a type other than JSON object;
-    example: `"cannot use erase() with null"`
+    /// @brief remove element from a JSON object given a key
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    size_type erase(const typename object_t::key_type& key)
+    {
+        // the indirection via erase_internal() is added to avoid making this
+        // function a template and thus de-rank it during overload resolution
+        return erase_internal(key);
+    }
 
-    @complexity `log(size()) + count(key)`
+    /// @brief remove element from a JSON object given a key
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    size_type erase(KeyType && key)
+    {
+        return erase_internal(std::forward<KeyType>(key));
+    }
 
-    @liveexample{The example shows the effect of `erase()`.,erase__key_type}
+    /// @brief remove element from a JSON array given an index
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    void erase(const size_type idx)
+    {
+        // this erase only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            if (JSON_HEDLEY_UNLIKELY(idx >= size()))
+            {
+                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
+            }
 
-    @sa @ref erase(IteratorType) -- removes the element at a given position
-    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
-    the given range
-    @sa @ref erase(const size_type) -- removes the element from an array at
-    the given index
-
-    @since version 1.0.0
-    */
-    size_type erase(std::string_view key);
-
-    /*!
-    @brief remove element from a JSON array given an index
-
-    Removes element from a JSON array at the index @a idx.
-
-    @param[in] idx index of the element to remove
-
-    @throw type_error.307 when called on a type other than JSON object;
-    example: `"cannot use erase() with null"`
-    @throw out_of_range.401 when `idx >= size()`; example: `"array index 17
-    is out of range"`
-
-    @complexity Linear in distance between @a idx and the end of the container.
-
-    @liveexample{The example shows the effect of `erase()`.,erase__size_type}
-
-    @sa @ref erase(IteratorType) -- removes the element at a given position
-    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
-    the given range
-    @sa @ref erase(const typename object_t::key_type&) -- removes the element
-    from an object at the given key
-
-    @since version 1.0.0
-    */
-    void erase(const size_type idx);
+            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
+        }
+        else
+        {
+            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+    }
 
     /// @}
 
@@ -5449,58 +2652,113 @@
     /// @name lookup
     /// @{
 
-    /*!
-    @brief find an element in a JSON object
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    iterator find(const typename object_t::key_type& key)
+    {
+        auto result = end();
 
-    Finds an element in a JSON object with key equivalent to @a key. If the
-    element is not found or the JSON value is not an object, end() is
-    returned.
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(key);
+        }
 
-    @note This method always returns @ref end() when executed on a JSON type
-          that is not an object.
+        return result;
+    }
 
-    @param[in] key key value of the element to search for.
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    const_iterator find(const typename object_t::key_type& key) const
+    {
+        auto result = cend();
 
-    @return Iterator to an element with key equivalent to @a key. If no such
-    element is found or the JSON value is not an object, past-the-end (see
-    @ref end()) iterator is returned.
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(key);
+        }
 
-    @complexity Logarithmic in the size of the JSON object.
+        return result;
+    }
 
-    @liveexample{The example shows how `find()` is used.,find__key_type}
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    iterator find(KeyType && key)
+    {
+        auto result = end();
 
-    @since version 1.0.0
-    */
-    iterator find(std::string_view key);
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
+        }
 
-    /*!
-    @brief find an element in a JSON object
-    @copydoc find(KeyT&&)
-    */
-    const_iterator find(std::string_view key) const;
+        return result;
+    }
 
-    /*!
-    @brief returns the number of occurrences of a key in a JSON object
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    const_iterator find(KeyType && key) const
+    {
+        auto result = cend();
 
-    Returns the number of elements with key @a key. If ObjectType is the
-    default `std::map` type, the return value will always be `0` (@a key was
-    not found) or `1` (@a key was found).
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
+        }
 
-    @note This method always returns `0` when executed on a JSON type that is
-          not an object.
+        return result;
+    }
 
-    @param[in] key key value of the element to count
+    /// @brief returns the number of occurrences of a key in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/count/
+    size_type count(const typename object_t::key_type& key) const
+    {
+        // return 0 for all nonobject types
+        return is_object() ? m_value.object->count(key) : 0;
+    }
 
-    @return Number of elements with key @a key. If the JSON value is not an
-    object, the return value will be `0`.
+    /// @brief returns the number of occurrences of a key in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/count/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    size_type count(KeyType && key) const
+    {
+        // return 0 for all nonobject types
+        return is_object() ? m_value.object->count(std::forward<KeyType>(key)) : 0;
+    }
 
-    @complexity Logarithmic in the size of the JSON object.
+    /// @brief check the existence of an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/contains/
+    bool contains(const typename object_t::key_type& key) const
+    {
+        return is_object() && m_value.object->find(key) != m_value.object->end();
+    }
 
-    @liveexample{The example shows how `count()` is used.,count}
+    /// @brief check the existence of an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/contains/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    bool contains(KeyType && key) const
+    {
+        return is_object() && m_value.object->find(std::forward<KeyType>(key)) != m_value.object->end();
+    }
 
-    @since version 1.0.0
-    */
-    size_type count(std::string_view key) const;
+    /// @brief check the existence of an element in a JSON object given a JSON pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/contains/
+    bool contains(const json_pointer& ptr) const
+    {
+        return ptr.contains(this);
+    }
+
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    bool contains(const typename ::wpi::json_pointer<BasicJsonType>& ptr) const
+    {
+        return ptr.contains(this);
+    }
 
     /// @}
 
@@ -5512,30 +2770,8 @@
     /// @name iterators
     /// @{
 
-    /*!
-    @brief returns an iterator to the first element
-
-    Returns an iterator to the first element.
-
-    @image html range-begin-end.svg "Illustration from cppreference.com"
-
-    @return iterator to the first element
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-
-    @liveexample{The following code shows an example for `begin()`.,begin}
-
-    @sa @ref cbegin() -- returns a const iterator to the beginning
-    @sa @ref end() -- returns an iterator to the end
-    @sa @ref cend() -- returns a const iterator to the end
-
-    @since version 1.0.0
-    */
+    /// @brief returns an iterator to the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/begin/
     iterator begin() noexcept
     {
         iterator result(this);
@@ -5543,39 +2779,15 @@
         return result;
     }
 
-    /*!
-    @copydoc json::cbegin()
-    */
+    /// @brief returns an iterator to the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/begin/
     const_iterator begin() const noexcept
     {
         return cbegin();
     }
 
-    /*!
-    @brief returns a const iterator to the first element
-
-    Returns a const iterator to the first element.
-
-    @image html range-begin-end.svg "Illustration from cppreference.com"
-
-    @return const iterator to the first element
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `const_cast<const json&>(*this).begin()`.
-
-    @liveexample{The following code shows an example for `cbegin()`.,cbegin}
-
-    @sa @ref begin() -- returns an iterator to the beginning
-    @sa @ref end() -- returns an iterator to the end
-    @sa @ref cend() -- returns a const iterator to the end
-
-    @since version 1.0.0
-    */
+    /// @brief returns a const iterator to the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/cbegin/
     const_iterator cbegin() const noexcept
     {
         const_iterator result(this);
@@ -5583,30 +2795,8 @@
         return result;
     }
 
-    /*!
-    @brief returns an iterator to one past the last element
-
-    Returns an iterator to one past the last element.
-
-    @image html range-begin-end.svg "Illustration from cppreference.com"
-
-    @return iterator one past the last element
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-
-    @liveexample{The following code shows an example for `end()`.,end}
-
-    @sa @ref cend() -- returns a const iterator to the end
-    @sa @ref begin() -- returns an iterator to the beginning
-    @sa @ref cbegin() -- returns a const iterator to the beginning
-
-    @since version 1.0.0
-    */
+    /// @brief returns an iterator to one past the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/end/
     iterator end() noexcept
     {
         iterator result(this);
@@ -5614,39 +2804,15 @@
         return result;
     }
 
-    /*!
-    @copydoc json::cend()
-    */
+    /// @brief returns an iterator to one past the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/end/
     const_iterator end() const noexcept
     {
         return cend();
     }
 
-    /*!
-    @brief returns a const iterator to one past the last element
-
-    Returns a const iterator to one past the last element.
-
-    @image html range-begin-end.svg "Illustration from cppreference.com"
-
-    @return const iterator one past the last element
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `const_cast<const json&>(*this).end()`.
-
-    @liveexample{The following code shows an example for `cend()`.,cend}
-
-    @sa @ref end() -- returns an iterator to the end
-    @sa @ref begin() -- returns an iterator to the beginning
-    @sa @ref cbegin() -- returns a const iterator to the beginning
-
-    @since version 1.0.0
-    */
+    /// @brief returns an iterator to one past the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/cend/
     const_iterator cend() const noexcept
     {
         const_iterator result(this);
@@ -5654,198 +2820,80 @@
         return result;
     }
 
-    /*!
-    @brief returns an iterator to the reverse-beginning
-
-    Returns an iterator to the reverse-beginning; that is, the last element.
-
-    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `reverse_iterator(end())`.
-
-    @liveexample{The following code shows an example for `rbegin()`.,rbegin}
-
-    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
-    @sa @ref rend() -- returns a reverse iterator to the end
-    @sa @ref crend() -- returns a const reverse iterator to the end
-
-    @since version 1.0.0
-    */
+    /// @brief returns an iterator to the reverse-beginning
+    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
     reverse_iterator rbegin() noexcept
     {
         return reverse_iterator(end());
     }
 
-    /*!
-    @copydoc json::crbegin()
-    */
+    /// @brief returns an iterator to the reverse-beginning
+    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
     const_reverse_iterator rbegin() const noexcept
     {
         return crbegin();
     }
 
-    /*!
-    @brief returns an iterator to the reverse-end
-
-    Returns an iterator to the reverse-end; that is, one before the first
-    element.
-
-    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `reverse_iterator(begin())`.
-
-    @liveexample{The following code shows an example for `rend()`.,rend}
-
-    @sa @ref crend() -- returns a const reverse iterator to the end
-    @sa @ref rbegin() -- returns a reverse iterator to the beginning
-    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
-
-    @since version 1.0.0
-    */
+    /// @brief returns an iterator to the reverse-end
+    /// @sa https://json.nlohmann.me/api/basic_json/rend/
     reverse_iterator rend() noexcept
     {
         return reverse_iterator(begin());
     }
 
-    /*!
-    @copydoc json::crend()
-    */
+    /// @brief returns an iterator to the reverse-end
+    /// @sa https://json.nlohmann.me/api/basic_json/rend/
     const_reverse_iterator rend() const noexcept
     {
         return crend();
     }
 
-    /*!
-    @brief returns a const reverse iterator to the last element
-
-    Returns a const iterator to the reverse-beginning; that is, the last
-    element.
-
-    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `const_cast<const json&>(*this).rbegin()`.
-
-    @liveexample{The following code shows an example for `crbegin()`.,crbegin}
-
-    @sa @ref rbegin() -- returns a reverse iterator to the beginning
-    @sa @ref rend() -- returns a reverse iterator to the end
-    @sa @ref crend() -- returns a const reverse iterator to the end
-
-    @since version 1.0.0
-    */
+    /// @brief returns a const reverse iterator to the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/crbegin/
     const_reverse_iterator crbegin() const noexcept
     {
         return const_reverse_iterator(cend());
     }
 
-    /*!
-    @brief returns a const reverse iterator to one before the first
-
-    Returns a const reverse iterator to the reverse-end; that is, one before
-    the first element.
-
-    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
-
-    @complexity Constant.
-
-    @requirement This function helps `json` satisfying the
-    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `const_cast<const json&>(*this).rend()`.
-
-    @liveexample{The following code shows an example for `crend()`.,crend}
-
-    @sa @ref rend() -- returns a reverse iterator to the end
-    @sa @ref rbegin() -- returns a reverse iterator to the beginning
-    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
-
-    @since version 1.0.0
-    */
+    /// @brief returns a const reverse iterator to one before the first
+    /// @sa https://json.nlohmann.me/api/basic_json/crend/
     const_reverse_iterator crend() const noexcept
     {
         return const_reverse_iterator(cbegin());
     }
 
   public:
-    /*!
-    @brief helper to access iterator member functions in range-based for
-
-    This function allows to access @ref iterator::key() and @ref
-    iterator::value() during range-based for loops. In these loops, a
-    reference to the JSON values is returned, so there is no access to the
-    underlying iterator.
-
-    For loop without `items()` function:
-
-    @code{cpp}
-    for (auto it = j_object.begin(); it != j_object.end(); ++it)
+    /// @brief wrapper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
+    /// @deprecated This function is deprecated since 3.1.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use @ref items() instead;
+    ///             that is, replace `json::iterator_wrapper(j)` with `j.items()`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
+    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
     {
-        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
+        return ref.items();
     }
-    @endcode
 
-    Range-based for loop without `items()` function:
-
-    @code{cpp}
-    for (auto it : j_object)
+    /// @brief wrapper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
+    /// @deprecated This function is deprecated since 3.1.0 and will be removed in
+    ///         version 4.0.0 of the library. Please use @ref items() instead;
+    ///         that is, replace `json::iterator_wrapper(j)` with `j.items()`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
+    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
     {
-        // "it" is of type json::reference and has no key() member
-        std::cout << "value: " << it << '\n';
+        return ref.items();
     }
-    @endcode
 
-    Range-based for loop with `items()` function:
-
-    @code{cpp}
-    for (auto it : j_object.items())
-    {
-        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
-    }
-    @endcode
-
-    @note When iterating over an array, `key()` will return the index of the
-          element as string (see example). For primitive types (e.g., numbers),
-          `key()` returns an empty string.
-
-    @return iteration proxy object wrapping @a ref with an interface to use in
-            range-based for loops
-
-    @liveexample{The following code shows how the function is used.,items}
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Constant.
-
-    @since version 3.x.x.
-    */
+    /// @brief helper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
     iteration_proxy<iterator> items() noexcept
     {
         return iteration_proxy<iterator>(*this);
     }
 
-    /*!
-    @copydoc items()
-    */
+    /// @brief helper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
     iteration_proxy<const_iterator> items() const noexcept
     {
         return iteration_proxy<const_iterator>(*this);
@@ -5861,134 +2909,117 @@
     /// @name capacity
     /// @{
 
-    /*!
-    @brief checks whether the container is empty.
+    /// @brief checks whether the container is empty.
+    /// @sa https://json.nlohmann.me/api/basic_json/empty/
+    bool empty() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+            {
+                // null values are empty
+                return true;
+            }
 
-    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).
+            case value_t::array:
+            {
+                // delegate call to array_t::empty()
+                return m_value.array->empty();
+            }
 
-    @return The return value depends on the different types and is
-            defined as follows:
-            Value type  | return value
-            ----------- | -------------
-            null        | `true`
-            boolean     | `false`
-            string      | `false`
-            number      | `false`
-            object      | result of function `object_t::empty()`
-            array       | result of function `array_t::empty()`
+            case value_t::object:
+            {
+                // delegate call to object_t::empty()
+                return m_value.object->empty();
+            }
 
-    @liveexample{The following code uses `empty()` to check if a JSON
-    object contains any elements.,empty}
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // all other types are nonempty
+                return false;
+            }
+        }
+    }
 
-    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
-    the Container concept; that is, their `empty()` functions have constant
-    complexity.
+    /// @brief returns the number of elements
+    /// @sa https://json.nlohmann.me/api/basic_json/size/
+    size_type size() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+            {
+                // null values are empty
+                return 0;
+            }
 
-    @iterators No changes.
+            case value_t::array:
+            {
+                // delegate call to array_t::size()
+                return m_value.array->size();
+            }
 
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
+            case value_t::object:
+            {
+                // delegate call to object_t::size()
+                return m_value.object->size();
+            }
 
-    @note This function does not return whether a string stored as JSON value
-    is empty - it returns whether the JSON container itself is empty which is
-    false in the case of a string.
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // all other types have size 1
+                return 1;
+            }
+        }
+    }
 
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `begin() == end()`.
+    /// @brief returns the maximum possible number of elements
+    /// @sa https://json.nlohmann.me/api/basic_json/max_size/
+    size_type max_size() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::array:
+            {
+                // delegate call to array_t::max_size()
+                return m_value.array->max_size();
+            }
 
-    @sa @ref size() -- returns the number of elements
+            case value_t::object:
+            {
+                // delegate call to object_t::max_size()
+                return m_value.object->max_size();
+            }
 
-    @since version 1.0.0
-    */
-    bool empty() const noexcept;
-
-    /*!
-    @brief returns the number of elements
-
-    Returns the number of elements in a JSON value.
-
-    @return The return value depends on the different types and is
-            defined as follows:
-            Value type  | return value
-            ----------- | -------------
-            null        | `0`
-            boolean     | `1`
-            string      | `1`
-            number      | `1`
-            object      | result of function object_t::size()
-            array       | result of function array_t::size()
-
-    @liveexample{The following code calls `size()` on the different value
-    types.,size}
-
-    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
-    the Container concept; that is, their size() functions have constant
-    complexity.
-
-    @iterators No changes.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @note This function does not return the length of a string stored as JSON
-    value - it returns the number of elements in the JSON value which is 1 in
-    the case of a string.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of `std::distance(begin(), end())`.
-
-    @sa @ref empty() -- checks whether the container is empty
-    @sa @ref max_size() -- returns the maximal number of elements
-
-    @since version 1.0.0
-    */
-    size_type size() const noexcept;
-
-    /*!
-    @brief returns the maximum possible number of elements
-
-    Returns the maximum number of elements a JSON value is able to hold due to
-    system or library implementation limitations, i.e. `std::distance(begin(),
-    end())` for the JSON value.
-
-    @return The return value depends on the different types and is
-            defined as follows:
-            Value type  | return value
-            ----------- | -------------
-            null        | `0` (same as `size()`)
-            boolean     | `1` (same as `size()`)
-            string      | `1` (same as `size()`)
-            number      | `1` (same as `size()`)
-            object      | result of function `object_t::max_size()`
-            array       | result of function `array_t::max_size()`
-
-    @liveexample{The following code calls `max_size()` on the different value
-    types. Note the output is implementation specific.,max_size}
-
-    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
-    the Container concept; that is, their `max_size()` functions have constant
-    complexity.
-
-    @iterators No changes.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @requirement This function helps `json` satisfying the
-    [Container](http://en.cppreference.com/w/cpp/concept/Container)
-    requirements:
-    - The complexity is constant.
-    - Has the semantics of returning `b.size()` where `b` is the largest
-      possible JSON value.
-
-    @sa @ref size() -- returns the number of elements
-
-    @since version 1.0.0
-    */
-    size_type max_size() const noexcept;
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // all other types have max_size() == size()
+                return size();
+            }
+        }
+    }
 
     /// @}
 
@@ -6000,119 +3031,140 @@
     /// @name modifiers
     /// @{
 
-    /*!
-    @brief clears the contents
+    /// @brief clears the contents
+    /// @sa https://json.nlohmann.me/api/basic_json/clear/
+    void clear() noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = 0;
+                break;
+            }
 
-    Clears the content of a JSON value and resets it to the default value as
-    if @ref json(value_t) would have been called with the current value
-    type from @ref type():
+            case value_t::number_unsigned:
+            {
+                m_value.number_unsigned = 0;
+                break;
+            }
 
-    Value type  | initial value
-    ----------- | -------------
-    null        | `null`
-    boolean     | `false`
-    string      | `""`
-    number      | `0`
-    object      | `{}`
-    array       | `[]`
+            case value_t::number_float:
+            {
+                m_value.number_float = 0.0;
+                break;
+            }
 
-    @post Has the same effect as calling
-    @code {.cpp}
-    *this = json(type());
-    @endcode
+            case value_t::boolean:
+            {
+                m_value.boolean = false;
+                break;
+            }
 
-    @liveexample{The example below shows the effect of `clear()` to different
-    JSON types.,clear}
+            case value_t::string:
+            {
+                m_value.string->clear();
+                break;
+            }
 
-    @complexity Linear in the size of the JSON value.
+            case value_t::binary:
+            {
+                m_value.binary->clear();
+                break;
+            }
 
-    @iterators All iterators, pointers and references related to this container
-               are invalidated.
+            case value_t::array:
+            {
+                m_value.array->clear();
+                break;
+            }
 
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
+            case value_t::object:
+            {
+                m_value.object->clear();
+                break;
+            }
 
-    @sa @ref json(value_t) -- constructor that creates an object with the
-        same value than calling `clear()`
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
 
-    @since version 1.0.0
-    */
-    void clear() noexcept;
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(basic_json&& val)
+    {
+        // push_back only works for null objects or arrays
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
+        {
+            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
+        }
 
-    /*!
-    @brief add an object to an array
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
 
-    Appends the given element @a val to the end of the JSON value. If the
-    function is called on a JSON null value, an empty array is created before
-    appending @a val.
+        // add element to array (move semantics)
+        const auto old_capacity = m_value.array->capacity();
+        m_value.array->push_back(std::move(val));
+        set_parent(m_value.array->back(), old_capacity);
+        // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
+    }
 
-    @param[in] val the value to add to the JSON array
-
-    @throw type_error.308 when called on a type other than JSON array or
-    null; example: `"cannot use push_back() with number"`
-
-    @complexity Amortized constant.
-
-    @liveexample{The example shows how `push_back()` and `+=` can be used to
-    add elements to a JSON array. Note how the `null` value was silently
-    converted to a JSON array.,push_back}
-
-    @since version 1.0.0
-    */
-    void push_back(json&& val);
-
-    /*!
-    @brief add an object to an array
-    @copydoc push_back(json&&)
-    */
-    reference operator+=(json&& val)
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(basic_json&& val)
     {
         push_back(std::move(val));
         return *this;
     }
 
-    /*!
-    @brief add an object to an array
-    @copydoc push_back(json&&)
-    */
-    void push_back(const json& val);
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(const basic_json& val)
+    {
+        // push_back only works for null objects or arrays
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
+        {
+            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
+        }
 
-    /*!
-    @brief add an object to an array
-    @copydoc push_back(json&&)
-    */
-    reference operator+=(const json& val)
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array
+        const auto old_capacity = m_value.array->capacity();
+        m_value.array->push_back(val);
+        set_parent(m_value.array->back(), old_capacity);
+    }
+
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(const basic_json& val)
     {
         push_back(val);
         return *this;
     }
 
-    /*!
-    @brief add an object to an object
-
-    Inserts the given element @a val to the JSON object. If the function is
-    called on a JSON null value, an empty object is created before inserting
-    @a val.
-
-    @param[in] val the value to add to the JSON object
-
-    @throw type_error.308 when called on a type other than JSON object or
-    null; example: `"cannot use push_back() with number"`
-
-    @complexity Logarithmic in the size of the container, O(log(`size()`)).
-
-    @liveexample{The example shows how `push_back()` and `+=` can be used to
-    add elements to a JSON object. Note how the `null` value was silently
-    converted to a JSON object.,push_back__object_t__value}
-
-    @since version 1.0.0
-    */
-    template<typename T, typename U>
-    void push_back(const std::pair<T, U>& val)
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(const typename object_t::value_type& val)
     {
         // push_back only works for null objects or objects
-        if (JSON_UNLIKELY(not(is_null() or is_object())))
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
         {
-            JSON_THROW(type_error::create(308, "cannot use push_back() with", type_name()));
+            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
         }
 
         // transform null object into an object
@@ -6123,86 +3175,52 @@
             assert_invariant();
         }
 
-        // add element to array
-        m_value.object->try_emplace(val.first, std::move(val.second));
+        // add element to object
+        auto res = m_value.object->insert(val);
+        set_parent(res.first->second);
     }
 
-    /*!
-    @brief add an object to an object
-    @copydoc push_back(const typename object_t::value_type&)
-    */
-    template<typename T, typename U>
-    reference operator+=(const std::pair<T, U>& val)
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(const typename object_t::value_type& val)
     {
         push_back(val);
         return *this;
     }
 
-    /*!
-    @brief add an object to an object
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(initializer_list_t init)
+    {
+        if (is_object() && init.size() == 2 && (*init.begin())->is_string())
+        {
+            basic_json&& key = init.begin()->moved_or_copied();
+            push_back(typename object_t::value_type(
+                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
+        }
+        else
+        {
+            push_back(basic_json(init));
+        }
+    }
 
-    This function allows to use `push_back` with an initializer list. In case
-
-    1. the current value is an object,
-    2. the initializer list @a init contains only two elements, and
-    3. the first element of @a init is a string,
-
-    @a init is converted into an object element and added using
-    @ref push_back(const typename object_t::value_type&). Otherwise, @a init
-    is converted to a JSON value and added using @ref push_back(json&&).
-
-    @param[in] init  an initializer list
-
-    @complexity Linear in the size of the initializer list @a init.
-
-    @note This function is required to resolve an ambiguous overload error,
-          because pairs like `{"key", "value"}` can be both interpreted as
-          `object_t::value_type` or `std::initializer_list<json>`, see
-          https://github.com/nlohmann/json/issues/235 for more information.
-
-    @liveexample{The example shows how initializer lists are treated as
-    objects when possible.,push_back__initializer_list}
-    */
-    void push_back(initializer_list_t init);
-
-    /*!
-    @brief add an object to an object
-    @copydoc push_back(initializer_list_t)
-    */
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
     reference operator+=(initializer_list_t init)
     {
         push_back(init);
         return *this;
     }
 
-    /*!
-    @brief add an object to an array
-
-    Creates a JSON value from the passed parameters @a args to the end of the
-    JSON value. If the function is called on a JSON null value, an empty array
-    is created before appending the value created from @a args.
-
-    @param[in] args arguments to forward to a constructor of @ref json
-    @tparam Args compatible types to create a @ref json object
-
-    @throw type_error.311 when called on a type other than JSON array or
-    null; example: `"cannot use emplace_back() with number"`
-
-    @complexity Amortized constant.
-
-    @liveexample{The example shows how `push_back()` can be used to add
-    elements to a JSON array. Note how the `null` value was silently converted
-    to a JSON array.,emplace_back}
-
-    @since version 2.0.8
-    */
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/
     template<class... Args>
-    void emplace_back(Args&& ... args)
+    reference emplace_back(Args&& ... args)
     {
         // emplace_back only works for null objects or arrays
-        if (JSON_UNLIKELY(not(is_null() or is_array())))
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
         {
-            JSON_THROW(type_error::create(311, "cannot use emplace_back() with", type_name()));
+            JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
         }
 
         // transform null object into an array
@@ -6214,43 +3232,20 @@
         }
 
         // add element to array (perfect forwarding)
+        const auto old_capacity = m_value.array->capacity();
         m_value.array->emplace_back(std::forward<Args>(args)...);
+        return set_parent(m_value.array->back(), old_capacity);
     }
 
-    /*!
-    @brief add an object to an object if key does not exist
-
-    Inserts a new element into a JSON object constructed in-place with the
-    given @a args if there is no element with the key in the container. If the
-    function is called on a JSON null value, an empty object is created before
-    appending the value created from @a args.
-
-    @param[in] args arguments to forward to a constructor of @ref json
-    @tparam Args compatible types to create a @ref json object
-
-    @return a pair consisting of an iterator to the inserted element, or the
-            already-existing element if no insertion happened, and a bool
-            denoting whether the insertion took place.
-
-    @throw type_error.311 when called on a type other than JSON object or
-    null; example: `"cannot use emplace() with number"`
-
-    @complexity Logarithmic in the size of the container, O(log(`size()`)).
-
-    @liveexample{The example shows how `emplace()` can be used to add elements
-    to a JSON object. Note how the `null` value was silently converted to a
-    JSON object. Further note how no value is added if there was already one
-    value stored with the same key.,emplace}
-
-    @since version 2.0.8
-    */
+    /// @brief add an object to an object if key does not exist
+    /// @sa https://json.nlohmann.me/api/basic_json/emplace/
     template<class... Args>
-    std::pair<iterator, bool> emplace(std::string_view key, Args&& ... args)
+    std::pair<iterator, bool> emplace(Args&& ... args)
     {
         // emplace only works for null objects or arrays
-        if (JSON_UNLIKELY(not(is_null() or is_object())))
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
         {
-            JSON_THROW(type_error::create(311, "cannot use emplace() with", type_name()));
+            JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
         }
 
         // transform null object into an object
@@ -6262,7 +3257,9 @@
         }
 
         // add element to array (perfect forwarding)
-        auto res = m_value.object->try_emplace(key, std::forward<Args>(args)...);
+        auto res = m_value.object->emplace(std::forward<Args>(args)...);
+        set_parent(res.first->second);
+
         // create result iterator and set iterator to the result of emplace
         auto it = begin();
         it.m_it.object_iterator = res.first;
@@ -6271,328 +3268,315 @@
         return {it, res.second};
     }
 
-    /*!
-    @brief inserts element
+    /// Helper for insertion of an iterator
+    /// @note: This uses std::distance to support GCC 4.8,
+    ///        see https://github.com/nlohmann/json/pull/1257
+    template<typename... Args>
+    iterator insert_iterator(const_iterator pos, Args&& ... args)
+    {
+        iterator result(this);
+        JSON_ASSERT(m_value.array != nullptr);
 
-    Inserts element @a val before iterator @a pos.
+        auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
+        m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
+        result.m_it.array_iterator = m_value.array->begin() + insert_pos;
 
-    @param[in] pos iterator before which the content will be inserted; may be
-    the end() iterator
-    @param[in] val element to insert
-    @return iterator pointing to the inserted @a val.
+        // This could have been written as:
+        // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
+        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
 
-    @throw type_error.309 if called on JSON values other than arrays;
-    example: `"cannot use insert() with string"`
-    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
-    example: `"iterator does not fit current value"`
+        set_parents();
+        return result;
+    }
 
-    @complexity Constant plus linear in the distance between @a pos and end of
-    the container.
+    /// @brief inserts element into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, const basic_json& val)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            // check if iterator pos fits to this JSON value
+            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+            {
+                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+            }
 
-    @liveexample{The example shows how `insert()` is used.,insert}
+            // insert to array and return iterator
+            return insert_iterator(pos, val);
+        }
 
-    @since version 1.0.0
-    */
-    iterator insert(const_iterator pos, const json& val);
+        JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+    }
 
-    /*!
-    @brief inserts element
-    @copydoc insert(const_iterator, const json&)
-    */
-    iterator insert(const_iterator pos, json&& val)
+    /// @brief inserts element into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, basic_json&& val)
     {
         return insert(pos, val);
     }
 
-    /*!
-    @brief inserts elements
+    /// @brief inserts copies of element into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            // check if iterator pos fits to this JSON value
+            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+            {
+                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+            }
 
-    Inserts @a cnt copies of @a val before iterator @a pos.
+            // insert to array and return iterator
+            return insert_iterator(pos, cnt, val);
+        }
 
-    @param[in] pos iterator before which the content will be inserted; may be
-    the end() iterator
-    @param[in] cnt number of copies of @a val to insert
-    @param[in] val element to insert
-    @return iterator pointing to the first element inserted, or @a pos if
-    `cnt==0`
+        JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+    }
 
-    @throw type_error.309 if called on JSON values other than arrays; example:
-    `"cannot use insert() with string"`
-    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
-    example: `"iterator does not fit current value"`
+    /// @brief inserts range of elements into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_UNLIKELY(!is_array()))
+        {
+            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+        }
 
-    @complexity Linear in @a cnt plus linear in the distance between @a pos
-    and end of the container.
+        // check if iterator pos fits to this JSON value
+        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+        }
 
-    @liveexample{The example shows how `insert()` is used.,insert__count}
+        // check if range iterators belong to the same JSON object
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
+        }
 
-    @since version 1.0.0
-    */
-    iterator insert(const_iterator pos, size_type cnt, const json& val);
+        if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
+        {
+            JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
+        }
 
-    /*!
-    @brief inserts elements
+        // insert to array and return iterator
+        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
+    }
 
-    Inserts elements from range `[first, last)` before iterator @a pos.
+    /// @brief inserts elements from initializer list into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, initializer_list_t ilist)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_UNLIKELY(!is_array()))
+        {
+            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+        }
 
-    @param[in] pos iterator before which the content will be inserted; may be
-    the end() iterator
-    @param[in] first begin of the range of elements to insert
-    @param[in] last end of the range of elements to insert
+        // check if iterator pos fits to this JSON value
+        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+        }
 
-    @throw type_error.309 if called on JSON values other than arrays; example:
-    `"cannot use insert() with string"`
-    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
-    example: `"iterator does not fit current value"`
-    @throw invalid_iterator.210 if @a first and @a last do not belong to the
-    same JSON value; example: `"iterators do not fit"`
-    @throw invalid_iterator.211 if @a first or @a last are iterators into
-    container for which insert is called; example: `"passed iterators may not
-    belong to container"`
+        // insert to array and return iterator
+        return insert_iterator(pos, ilist.begin(), ilist.end());
+    }
 
-    @return iterator pointing to the first element inserted, or @a pos if
-    `first==last`
+    /// @brief inserts range of elements into object
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    void insert(const_iterator first, const_iterator last)
+    {
+        // insert only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+        }
 
-    @complexity Linear in `std::distance(first, last)` plus linear in the
-    distance between @a pos and end of the container.
+        // check if range iterators belong to the same JSON object
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
+        }
 
-    @liveexample{The example shows how `insert()` is used.,insert__range}
+        // passed iterators must belong to objects
+        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
+        }
 
-    @since version 1.0.0
-    */
-    iterator insert(const_iterator pos, const_iterator first, const_iterator last);
+        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
+    }
 
-    /*!
-    @brief inserts elements
+    /// @brief updates a JSON object from another object, overwriting existing keys
+    /// @sa https://json.nlohmann.me/api/basic_json/update/
+    void update(const_reference j, bool merge_objects = false)
+    {
+        update(j.begin(), j.end(), merge_objects);
+    }
 
-    Inserts elements from initializer list @a ilist before iterator @a pos.
+    /// @brief updates a JSON object from another object, overwriting existing keys
+    /// @sa https://json.nlohmann.me/api/basic_json/update/
+    void update(const_iterator first, const_iterator last, bool merge_objects = false)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
 
-    @param[in] pos iterator before which the content will be inserted; may be
-    the end() iterator
-    @param[in] ilist initializer list to insert the values from
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
+        }
 
-    @throw type_error.309 if called on JSON values other than arrays; example:
-    `"cannot use insert() with string"`
-    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
-    example: `"iterator does not fit current value"`
+        // check if range iterators belong to the same JSON object
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
+        }
 
-    @return iterator pointing to the first element inserted, or @a pos if
-    `ilist` is empty
+        // passed iterators must belong to objects
+        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
+        {
+            JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
+        }
 
-    @complexity Linear in `ilist.size()` plus linear in the distance between
-    @a pos and end of the container.
+        for (auto it = first; it != last; ++it)
+        {
+            if (merge_objects && it.value().is_object())
+            {
+                auto it2 = m_value.object->find(it.key());
+                if (it2 != m_value.object->end())
+                {
+                    it2->second.update(it.value(), true);
+                    continue;
+                }
+            }
+            m_value.object->operator[](it.key()) = it.value();
+#if JSON_DIAGNOSTICS
+            m_value.object->operator[](it.key()).m_parent = this;
+#endif
+        }
+    }
 
-    @liveexample{The example shows how `insert()` is used.,insert__ilist}
-
-    @since version 1.0.0
-    */
-    iterator insert(const_iterator pos, initializer_list_t ilist);
-
-    /*!
-    @brief inserts elements
-
-    Inserts elements from range `[first, last)`.
-
-    @param[in] first begin of the range of elements to insert
-    @param[in] last end of the range of elements to insert
-
-    @throw type_error.309 if called on JSON values other than objects; example:
-    `"cannot use insert() with string"`
-    @throw invalid_iterator.202 if iterator @a first or @a last does does not
-    point to an object; example: `"iterators first and last must point to
-    objects"`
-    @throw invalid_iterator.210 if @a first and @a last do not belong to the
-    same JSON value; example: `"iterators do not fit"`
-
-    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number
-    of elements to insert.
-
-    @liveexample{The example shows how `insert()` is used.,insert__range_object}
-
-    @since version 3.0.0
-    */
-    void insert(const_iterator first, const_iterator last);
-
-    /*!
-    @brief updates a JSON object from another object, overwriting existing keys
-
-    Inserts all values from JSON object @a j and overwrites existing keys.
-
-    @param[in] j  JSON object to read values from
-
-    @throw type_error.312 if called on JSON values other than objects; example:
-    `"cannot use update() with string"`
-
-    @complexity O(N*log(size() + N)), where N is the number of elements to
-                insert.
-
-    @liveexample{The example shows how `update()` is used.,update}
-
-    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
-
-    @since version 3.0.0
-    */
-    void update(const_reference j);
-
-    /*!
-    @brief updates a JSON object from another object, overwriting existing keys
-
-    Inserts all values from from range `[first, last)` and overwrites existing
-    keys.
-
-    @param[in] first begin of the range of elements to insert
-    @param[in] last end of the range of elements to insert
-
-    @throw type_error.312 if called on JSON values other than objects; example:
-    `"cannot use update() with string"`
-    @throw invalid_iterator.202 if iterator @a first or @a last does does not
-    point to an object; example: `"iterators first and last must point to
-    objects"`
-    @throw invalid_iterator.210 if @a first and @a last do not belong to the
-    same JSON value; example: `"iterators do not fit"`
-
-    @complexity O(N*log(size() + N)), where N is the number of elements to
-                insert.
-
-    @liveexample{The example shows how `update()` is used__range.,update}
-
-    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
-
-    @since version 3.0.0
-    */
-    void update(const_iterator first, const_iterator last);
-
-    /*!
-    @brief exchanges the values
-
-    Exchanges the contents of the JSON value with those of @a other. Does not
-    invoke any move, copy, or swap operations on individual elements. All
-    iterators and references remain valid. The past-the-end iterator is
-    invalidated.
-
-    @param[in,out] other JSON value to exchange the contents with
-
-    @complexity Constant.
-
-    @liveexample{The example below shows how JSON values can be swapped with
-    `swap()`.,swap__reference}
-
-    @since version 1.0.0
-    */
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
     void swap(reference other) noexcept (
-        std::is_nothrow_move_constructible<value_t>::value and
-        std::is_nothrow_move_assignable<value_t>::value and
-        std::is_nothrow_move_constructible<json_value>::value and
+        std::is_nothrow_move_constructible<value_t>::value&&
+        std::is_nothrow_move_assignable<value_t>::value&&
+        std::is_nothrow_move_constructible<json_value>::value&&
         std::is_nothrow_move_assignable<json_value>::value
     )
     {
         std::swap(m_type, other.m_type);
         std::swap(m_value, other.m_value);
+
+        set_parents();
+        other.set_parents();
         assert_invariant();
     }
 
-    /*!
-    @brief exchanges the values
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    friend void swap(reference left, reference right) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value&&
+        std::is_nothrow_move_assignable<value_t>::value&&
+        std::is_nothrow_move_constructible<json_value>::value&&
+        std::is_nothrow_move_assignable<json_value>::value
+    )
+    {
+        left.swap(right);
+    }
 
-    Exchanges the contents of a JSON array with those of @a other. Does not
-    invoke any move, copy, or swap operations on individual elements. All
-    iterators and references remain valid. The past-the-end iterator is
-    invalidated.
-
-    @param[in,out] other array to exchange the contents with
-
-    @throw type_error.310 when JSON value is not an array; example: `"cannot
-    use swap() with string"`
-
-    @complexity Constant.
-
-    @liveexample{The example below shows how arrays can be swapped with
-    `swap()`.,swap__std_vector_json}
-
-    @since version 1.0.0
-    */
-    void swap(array_t& other)
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(array_t& other) // NOLINT(bugprone-exception-escape)
     {
         // swap only works for arrays
-        if (JSON_LIKELY(is_array()))
+        if (JSON_HEDLEY_LIKELY(is_array()))
         {
-            std::swap(*(m_value.array), other);
+            using std::swap;
+            swap(*(m_value.array), other);
         }
         else
         {
-            JSON_THROW(type_error::create(310, "cannot use swap() with", type_name()));
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
         }
     }
 
-    /*!
-    @brief exchanges the values
-
-    Exchanges the contents of a JSON object with those of @a other. Does not
-    invoke any move, copy, or swap operations on individual elements. All
-    iterators and references remain valid. The past-the-end iterator is
-    invalidated.
-
-    @param[in,out] other object to exchange the contents with
-
-    @throw type_error.310 when JSON value is not an object; example:
-    `"cannot use swap() with string"`
-
-    @complexity Constant.
-
-    @liveexample{The example below shows how objects can be swapped with
-    `swap()`.,swap__object_t}
-
-    @since version 1.0.0
-    */
-    void swap(object_t& other)
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(object_t& other) // NOLINT(bugprone-exception-escape)
     {
         // swap only works for objects
-        if (JSON_LIKELY(is_object()))
+        if (JSON_HEDLEY_LIKELY(is_object()))
         {
-            std::swap(*(m_value.object), other);
+            using std::swap;
+            swap(*(m_value.object), other);
         }
         else
         {
-            JSON_THROW(type_error::create(310, "cannot use swap() with", type_name()));
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
         }
     }
 
-    /*!
-    @brief exchanges the values
-
-    Exchanges the contents of a JSON string with those of @a other. Does not
-    invoke any move, copy, or swap operations on individual elements. All
-    iterators and references remain valid. The past-the-end iterator is
-    invalidated.
-
-    @param[in,out] other string to exchange the contents with
-
-    @throw type_error.310 when JSON value is not a string; example: `"cannot
-    use swap() with boolean"`
-
-    @complexity Constant.
-
-    @liveexample{The example below shows how strings can be swapped with
-    `swap()`.,swap__std_string}
-
-    @since version 1.0.0
-    */
-    void swap(std::string& other)
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(string_t& other) // NOLINT(bugprone-exception-escape)
     {
         // swap only works for strings
-        if (JSON_LIKELY(is_string()))
+        if (JSON_HEDLEY_LIKELY(is_string()))
         {
-            std::swap(*(m_value.string), other);
+            using std::swap;
+            swap(*(m_value.string), other);
         }
         else
         {
-            JSON_THROW(type_error::create(310, "cannot use swap() with", type_name()));
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(binary_t& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for strings
+        if (JSON_HEDLEY_LIKELY(is_binary()))
+        {
+            using std::swap;
+            swap(*(m_value.binary), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for strings
+        if (JSON_HEDLEY_LIKELY(is_binary()))
+        {
+            using std::swap;
+            swap(*(m_value.binary), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
         }
     }
 
     /// @}
 
-  public:
     //////////////////////////////////////////
     // lexicographical comparison operators //
     //////////////////////////////////////////
@@ -6600,301 +3584,391 @@
     /// @name lexicographical comparison operators
     /// @{
 
-    /*!
-    @brief comparison: equal
+    // note parentheses around operands are necessary; see
+    // https://github.com/nlohmann/json/issues/1530
+#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result)                       \
+    const auto lhs_type = lhs.type();                                                                    \
+    const auto rhs_type = rhs.type();                                                                    \
+    \
+    if (lhs_type == rhs_type) /* NOLINT(readability/braces) */                                           \
+    {                                                                                                    \
+        switch (lhs_type)                                                                                \
+        {                                                                                                \
+            case value_t::array:                                                                         \
+                return (*lhs.m_value.array) op (*rhs.m_value.array);                                     \
+                \
+            case value_t::object:                                                                        \
+                return (*lhs.m_value.object) op (*rhs.m_value.object);                                   \
+                \
+            case value_t::null:                                                                          \
+                return (null_result);                                                                    \
+                \
+            case value_t::string:                                                                        \
+                return (*lhs.m_value.string) op (*rhs.m_value.string);                                   \
+                \
+            case value_t::boolean:                                                                       \
+                return (lhs.m_value.boolean) op (rhs.m_value.boolean);                                   \
+                \
+            case value_t::number_integer:                                                                \
+                return (lhs.m_value.number_integer) op (rhs.m_value.number_integer);                     \
+                \
+            case value_t::number_unsigned:                                                               \
+                return (lhs.m_value.number_unsigned) op (rhs.m_value.number_unsigned);                   \
+                \
+            case value_t::number_float:                                                                  \
+                return (lhs.m_value.number_float) op (rhs.m_value.number_float);                         \
+                \
+            case value_t::binary:                                                                        \
+                return (*lhs.m_value.binary) op (*rhs.m_value.binary);                                   \
+                \
+            case value_t::discarded:                                                                     \
+            default:                                                                                     \
+                return (unordered_result);                                                               \
+        }                                                                                                \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)                   \
+    {                                                                                                    \
+        return static_cast<number_float_t>(lhs.m_value.number_integer) op rhs.m_value.number_float;      \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)                   \
+    {                                                                                                    \
+        return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_integer);      \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)                  \
+    {                                                                                                    \
+        return static_cast<number_float_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_float;     \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)                  \
+    {                                                                                                    \
+        return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_unsigned);     \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)                \
+    {                                                                                                    \
+        return static_cast<number_integer_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_integer; \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)                \
+    {                                                                                                    \
+        return lhs.m_value.number_integer op static_cast<number_integer_t>(rhs.m_value.number_unsigned); \
+    }                                                                                                    \
+    else if(compares_unordered(lhs, rhs))\
+    {\
+        return (unordered_result);\
+    }\
+    \
+    return (default_result);
 
-    Compares two JSON values for equality according to the following rules:
-    - Two JSON values are equal if (1) they are from the same type and (2)
-      their stored values are the same according to their respective
-      `operator==`.
-    - Integer and floating-point numbers are automatically converted before
-      comparison. Note than two NaN values are always treated as unequal.
-    - Two JSON null values are equal.
-
-    @note Floating-point inside JSON values numbers are compared with
-    `double::operator==`.
-    To compare floating-point while respecting an epsilon, an alternative
-    [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)
-    could be used, for instance
-    @code {.cpp}
-    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
-    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept
+  JSON_PRIVATE_UNLESS_TESTED:
+    // returns true if:
+    // - any operand is NaN and the other operand is of number type
+    // - any operand is discarded
+    // in legacy mode, discarded values are considered ordered if
+    // an operation is computed as an odd number of inverses of others
+    static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
     {
-        return std::abs(a - b) <= epsilon;
+        if ((lhs.is_number_float() && std::isnan(lhs.m_value.number_float) && rhs.is_number())
+                || (rhs.is_number_float() && std::isnan(rhs.m_value.number_float) && lhs.is_number()))
+        {
+            return true;
+        }
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+        return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
+#else
+        static_cast<void>(inverse);
+        return lhs.is_discarded() || rhs.is_discarded();
+#endif
     }
-    @endcode
 
-    @note NaN values never compare equal to themselves or to other NaN values.
+  private:
+    bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
+    {
+        return compares_unordered(*this, rhs, inverse);
+    }
 
-    @param[in] lhs  first JSON value to consider
-    @param[in] rhs  second JSON value to consider
-    @return whether the values @a lhs and @a rhs are equal
+  public:
+#if JSON_HAS_THREE_WAY_COMPARISON
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    bool operator==(const_reference rhs) const noexcept
+    {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+        const_reference lhs = *this;
+        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+    }
 
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    bool operator==(ScalarType rhs) const noexcept
+    {
+        return *this == basic_json(rhs);
+    }
 
-    @complexity Linear.
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
+    bool operator!=(const_reference rhs) const noexcept
+    {
+        if (compares_unordered(rhs, true))
+        {
+            return false;
+        }
+        return !operator==(rhs);
+    }
 
-    @liveexample{The example demonstrates comparing several JSON
-    types.,operator__equal}
+    /// @brief comparison: 3-way
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
+    std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
+    {
+        const_reference lhs = *this;
+        // default_result is used if we cannot compare values. In that case,
+        // we compare types.
+        JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
+                                std::partial_ordering::equivalent,
+                                std::partial_ordering::unordered,
+                                lhs_type <=> rhs_type) // *NOPAD*
+    }
 
-    @since version 1.0.0
-    */
-    friend bool operator==(const_reference lhs, const_reference rhs) noexcept;
+    /// @brief comparison: 3-way
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
+    {
+        return *this <=> basic_json(rhs); // *NOPAD*
+    }
 
-    /*!
-    @brief comparison: equal
-    @copydoc operator==(const_reference, const_reference)
-    */
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    // all operators that are computed as an odd number of inverses of others
+    // need to be overloaded to emulate the legacy comparison behavior
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
+    bool operator<=(const_reference rhs) const noexcept
+    {
+        if (compares_unordered(rhs, true))
+        {
+            return false;
+        }
+        return !(rhs < *this);
+    }
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    bool operator<=(ScalarType rhs) const noexcept
+    {
+        return *this <= basic_json(rhs);
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
+    bool operator>=(const_reference rhs) const noexcept
+    {
+        if (compares_unordered(rhs, true))
+        {
+            return false;
+        }
+        return !(*this < rhs);
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    bool operator>=(ScalarType rhs) const noexcept
+    {
+        return *this >= basic_json(rhs);
+    }
+#endif
+#else
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
+    {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+    }
+
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept
+    friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
     {
-        return (lhs == json(rhs));
+        return lhs == basic_json(rhs);
     }
 
-    /*!
-    @brief comparison: equal
-    @copydoc operator==(const_reference, const_reference)
-    */
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept
+    friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
     {
-        return (json(lhs) == rhs);
+        return basic_json(lhs) == rhs;
     }
 
-    /*!
-    @brief comparison: not equal
-
-    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
-
-    @param[in] lhs  first JSON value to consider
-    @param[in] rhs  second JSON value to consider
-    @return whether the values @a lhs and @a rhs are not equal
-
-    @complexity Linear.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @liveexample{The example demonstrates comparing several JSON
-    types.,operator__notequal}
-
-    @since version 1.0.0
-    */
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
     friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
     {
-        return not (lhs == rhs);
+        if (compares_unordered(lhs, rhs, true))
+        {
+            return false;
+        }
+        return !(lhs == rhs);
     }
 
-    /*!
-    @brief comparison: not equal
-    @copydoc operator!=(const_reference, const_reference)
-    */
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept
+    friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
     {
-        return (lhs != json(rhs));
+        return lhs != basic_json(rhs);
     }
 
-    /*!
-    @brief comparison: not equal
-    @copydoc operator!=(const_reference, const_reference)
-    */
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept
+    friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
     {
-        return (json(lhs) != rhs);
+        return basic_json(lhs) != rhs;
     }
 
-    /*!
-    @brief comparison: less than
+    /// @brief comparison: less than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
+    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
+    {
+        // default_result is used if we cannot compare values. In that case,
+        // we compare types. Note we have to call the operator explicitly,
+        // because MSVC has problems otherwise.
+        JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
+    }
 
-    Compares whether one JSON value @a lhs is less than another JSON value @a
-    rhs according to the following rules:
-    - If @a lhs and @a rhs have the same type, the values are compared using
-      the default `<` operator.
-    - Integer and floating-point numbers are automatically converted before
-      comparison
-    - In case @a lhs and @a rhs have different types, the values are ignored
-      and the order of the types is considered, see
-      @ref operator<(const value_t, const value_t).
-
-    @param[in] lhs  first JSON value to consider
-    @param[in] rhs  second JSON value to consider
-    @return whether @a lhs is less than @a rhs
-
-    @complexity Linear.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @liveexample{The example demonstrates comparing several JSON
-    types.,operator__less}
-
-    @since version 1.0.0
-    */
-    friend bool operator<(const_reference lhs, const_reference rhs) noexcept;
-
-    /*!
-    @brief comparison: less than
-    @copydoc operator<(const_reference, const_reference)
-    */
+    /// @brief comparison: less than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept
+    friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
     {
-        return (lhs < json(rhs));
+        return lhs < basic_json(rhs);
     }
 
-    /*!
-    @brief comparison: less than
-    @copydoc operator<(const_reference, const_reference)
-    */
+    /// @brief comparison: less than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept
+    friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
     {
-        return (json(lhs) < rhs);
+        return basic_json(lhs) < rhs;
     }
 
-    /*!
-    @brief comparison: less than or equal
-
-    Compares whether one JSON value @a lhs is less than or equal to another
-    JSON value by calculating `not (rhs < lhs)`.
-
-    @param[in] lhs  first JSON value to consider
-    @param[in] rhs  second JSON value to consider
-    @return whether @a lhs is less than or equal to @a rhs
-
-    @complexity Linear.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @liveexample{The example demonstrates comparing several JSON
-    types.,operator__greater}
-
-    @since version 1.0.0
-    */
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
     friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
     {
-        return not (rhs < lhs);
+        if (compares_unordered(lhs, rhs, true))
+        {
+            return false;
+        }
+        return !(rhs < lhs);
     }
 
-    /*!
-    @brief comparison: less than or equal
-    @copydoc operator<=(const_reference, const_reference)
-    */
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept
+    friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
     {
-        return (lhs <= json(rhs));
+        return lhs <= basic_json(rhs);
     }
 
-    /*!
-    @brief comparison: less than or equal
-    @copydoc operator<=(const_reference, const_reference)
-    */
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept
+    friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
     {
-        return (json(lhs) <= rhs);
+        return basic_json(lhs) <= rhs;
     }
 
-    /*!
-    @brief comparison: greater than
-
-    Compares whether one JSON value @a lhs is greater than another
-    JSON value by calculating `not (lhs <= rhs)`.
-
-    @param[in] lhs  first JSON value to consider
-    @param[in] rhs  second JSON value to consider
-    @return whether @a lhs is greater than to @a rhs
-
-    @complexity Linear.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @liveexample{The example demonstrates comparing several JSON
-    types.,operator__lessequal}
-
-    @since version 1.0.0
-    */
+    /// @brief comparison: greater than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
     friend bool operator>(const_reference lhs, const_reference rhs) noexcept
     {
-        return not (lhs <= rhs);
+        // double inverse
+        if (compares_unordered(lhs, rhs))
+        {
+            return false;
+        }
+        return !(lhs <= rhs);
     }
 
-    /*!
-    @brief comparison: greater than
-    @copydoc operator>(const_reference, const_reference)
-    */
+    /// @brief comparison: greater than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept
+    friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
     {
-        return (lhs > json(rhs));
+        return lhs > basic_json(rhs);
     }
 
-    /*!
-    @brief comparison: greater than
-    @copydoc operator>(const_reference, const_reference)
-    */
+    /// @brief comparison: greater than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept
+    friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
     {
-        return (json(lhs) > rhs);
+        return basic_json(lhs) > rhs;
     }
 
-    /*!
-    @brief comparison: greater than or equal
-
-    Compares whether one JSON value @a lhs is greater than or equal to another
-    JSON value by calculating `not (lhs < rhs)`.
-
-    @param[in] lhs  first JSON value to consider
-    @param[in] rhs  second JSON value to consider
-    @return whether @a lhs is greater than or equal to @a rhs
-
-    @complexity Linear.
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @liveexample{The example demonstrates comparing several JSON
-    types.,operator__greaterequal}
-
-    @since version 1.0.0
-    */
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
     friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
     {
-        return not (lhs < rhs);
+        if (compares_unordered(lhs, rhs, true))
+        {
+            return false;
+        }
+        return !(lhs < rhs);
     }
 
-    /*!
-    @brief comparison: greater than or equal
-    @copydoc operator>=(const_reference, const_reference)
-    */
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept
+    friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
     {
-        return (lhs >= json(rhs));
+        return lhs >= basic_json(rhs);
     }
 
-    /*!
-    @brief comparison: greater than or equal
-    @copydoc operator>=(const_reference, const_reference)
-    */
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
     template<typename ScalarType, typename std::enable_if<
                  std::is_scalar<ScalarType>::value, int>::type = 0>
-    friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept
+    friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
     {
-        return (json(lhs) >= rhs);
+        return basic_json(lhs) >= rhs;
     }
+#endif
+
+#undef JSON_IMPLEMENT_OPERATOR
 
     /// @}
 
@@ -6904,40 +3978,42 @@
 
     /// @name serialization
     /// @{
+#ifndef JSON_NO_IO
+    /// @brief serialize to stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
+    {
+        // read width member and use it as indentation parameter if nonzero
+        const bool pretty_print = o.width() > 0;
+        const auto indentation = pretty_print ? o.width() : 0;
 
-    /*!
-    @brief serialize to stream
+        // reset width to 0 for subsequent calls to this stream
+        o.width(0);
 
-    Serialize the given JSON value @a j to the output stream @a o. The JSON
-    value will be serialized using the @ref dump member function.
+        // do the actual serialization
+        serializer s(detail::output_adapter<char>(o), o.fill());
+        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
+        return o;
+    }
 
-    - The indentation of the output can be controlled with the member variable
-      `width` of the output stream @a o. For instance, using the manipulator
-      `std::setw(4)` on @a o sets the indentation level to `4` and the
-      serialization result is the same as calling `dump(4)`.
-
-    - The indentation character can be controlled with the member variable
-      `fill` of the output stream @a o. For instance, the manipulator
-      `std::setfill('\\t')` sets indentation to use a tab character rather than
-      the default space character.
-
-    @param[in,out] o  stream to serialize to
-    @param[in] j  JSON value to serialize
-
-    @return the stream @a o
-
-    @throw type_error.316 if a string stored inside the JSON value is not
-                          UTF-8 encoded
-
-    @complexity Linear.
-
-    @liveexample{The example below shows the serialization with different
-    parameters to `width` to adjust the indentation level.,operator_serialize}
-
-    @since version 1.0.0; indentation character added in version 3.0.0
-    */
-    friend raw_ostream& operator<<(raw_ostream& o, const json& j);
-
+    /// @brief serialize to stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+    /// @deprecated This function is deprecated since 3.0.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use
+    ///             operator<<(std::ostream&, const basic_json&) instead; that is,
+    ///             replace calls like `j >> o;` with `o << j;`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
+    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
+    {
+        return o << j;
+    }
+#endif  // JSON_NO_IO
+    
+    friend raw_ostream& operator<<(raw_ostream& o, const basic_json& j)
+    {
+        j.dump(o, 0);
+        return o;
+    }
     /// @}
 
 
@@ -6948,156 +4024,181 @@
     /// @name deserialization
     /// @{
 
-    /*!
-    @brief deserialize from a compatible input
-
-    This function reads from a compatible input. Examples are:
-    - an array of 1-byte values
-    - strings with character/literal type with size of 1 byte
-    - input streams
-    - container with contiguous storage of 1-byte values. Compatible container
-      types include `std::vector`, `std::string`, `std::array`,
-      and `std::initializer_list`. Furthermore, C-style
-      arrays can be used with `std::begin()`/`std::end()`. User-defined
-      containers can be used as long as they implement random-access iterators
-      and a contiguous storage.
-
-    @pre Each element of the container has a size of 1 byte. Violating this
-    precondition yields undefined behavior. **This precondition is enforced
-    with a static assertion.**
-
-    @pre The container storage is contiguous. Violating this precondition
-    yields undefined behavior. **This precondition is enforced with an
-    assertion.**
-    @pre Each element of the container has a size of 1 byte. Violating this
-    precondition yields undefined behavior. **This precondition is enforced
-    with a static assertion.**
-
-    @warning There is no way to enforce all preconditions at compile-time. If
-             the function is called with a noncompliant container and with
-             assertions switched off, the behavior is undefined and will most
-             likely yield segmentation violation.
-
-    @param[in] i  input to read from
-    @param[in] cb  a parser callback function of type @ref parser_callback_t
-    which is used to control the deserialization by filtering unwanted values
-    (optional)
-
-    @return result of the deserialization
-
-    @throw parse_error.101 if a parse error occurs; example: `""unexpected end
-    of input; expected string literal""`
-    @throw parse_error.102 if to_unicode fails or surrogate error
-    @throw parse_error.103 if to_unicode fails
-
-    @complexity Linear in the length of the input. The parser is a predictive
-    LL(1) parser. The complexity can be higher if the parser callback function
-    @a cb has a super-linear complexity.
-
-    @note A UTF-8 byte order mark is silently ignored.
-
-    @liveexample{The example below demonstrates the `parse()` function reading
-    from an array.,parse__array__parser_callback_t}
-
-    @liveexample{The example below demonstrates the `parse()` function with
-    and without callback function.,parse__string__parser_callback_t}
-
-    @liveexample{The example below demonstrates the `parse()` function with
-    and without callback function.,parse__istream__parser_callback_t}
-
-    @liveexample{The example below demonstrates the `parse()` function reading
-    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
-
-    @since version 2.0.3 (contiguous containers)
-    */
-    static json parse(std::string_view s,
+    /// @brief deserialize from a compatible input
+    /// @sa https://json.nlohmann.me/api/basic_json/parse/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json parse(InputType&& i,
                             const parser_callback_t cb = nullptr,
-                            const bool allow_exceptions = true);
+                            const bool allow_exceptions = true,
+                            const bool ignore_comments = false)
+    {
+        basic_json result;
+        parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
+        return result;
+    }
 
-    static json parse(std::span<const uint8_t> arr,
+    /// @brief deserialize from a pair of character iterators
+    /// @sa https://json.nlohmann.me/api/basic_json/parse/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json parse(IteratorType first,
+                            IteratorType last,
                             const parser_callback_t cb = nullptr,
-                            const bool allow_exceptions = true);
+                            const bool allow_exceptions = true,
+                            const bool ignore_comments = false)
+    {
+        basic_json result;
+        parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
+        return result;
+    }
 
-    /*!
-    @copydoc json parse(raw_istream&, const parser_callback_t)
-    */
-    static json parse(raw_istream& i,
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
+    static basic_json parse(detail::span_input_adapter&& i,
                             const parser_callback_t cb = nullptr,
-                            const bool allow_exceptions = true);
+                            const bool allow_exceptions = true,
+                            const bool ignore_comments = false)
+    {
+        basic_json result;
+        parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
+        return result;
+    }
 
-    static bool accept(std::string_view s);
+    /// @brief check if the input is valid JSON
+    /// @sa https://json.nlohmann.me/api/basic_json/accept/
+    template<typename InputType>
+    static bool accept(InputType&& i,
+                       const bool ignore_comments = false)
+    {
+        return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
+    }
 
-    static bool accept(std::span<const uint8_t> arr);
+    /// @brief check if the input is valid JSON
+    /// @sa https://json.nlohmann.me/api/basic_json/accept/
+    template<typename IteratorType>
+    static bool accept(IteratorType first, IteratorType last,
+                       const bool ignore_comments = false)
+    {
+        return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
+    }
 
-    static bool accept(raw_istream& i);
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
+    static bool accept(detail::span_input_adapter&& i,
+                       const bool ignore_comments = false)
+    {
+        return parser(i.get(), nullptr, false, ignore_comments).accept(true);
+    }
 
-    /*!
-    @brief deserialize from stream
+    /// @brief generate SAX events
+    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
+    template <typename InputType, typename SAX>
+    JSON_HEDLEY_NON_NULL(2)
+    static bool sax_parse(InputType&& i, SAX* sax,
+                          input_format_t format = input_format_t::json,
+                          const bool strict = true,
+                          const bool ignore_comments = false)
+    {
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        return format == input_format_t::json
+               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
+               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
+    }
 
-    Deserializes an input stream to a JSON value.
+    /// @brief generate SAX events
+    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
+    template<class IteratorType, class SAX>
+    JSON_HEDLEY_NON_NULL(3)
+    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
+                          input_format_t format = input_format_t::json,
+                          const bool strict = true,
+                          const bool ignore_comments = false)
+    {
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        return format == input_format_t::json
+               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
+               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
+    }
 
-    @param[in,out] i  input stream to read a serialized JSON value from
-    @param[in,out] j  JSON value to write the deserialized input to
+    /// @brief generate SAX events
+    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
+    /// @deprecated This function is deprecated since 3.8.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use
+    ///             sax_parse(ptr, ptr + len) instead.
+    template <typename SAX>
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
+    JSON_HEDLEY_NON_NULL(2)
+    static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
+                          input_format_t format = input_format_t::json,
+                          const bool strict = true,
+                          const bool ignore_comments = false)
+    {
+        auto ia = i.get();
+        return format == input_format_t::json
+               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
+               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
+    }
+#ifndef JSON_NO_IO
+    /// @brief deserialize from stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
+    /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use
+    ///             operator>>(std::istream&, basic_json&) instead; that is,
+    ///             replace calls like `j << i;` with `i >> j;`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
+    friend std::istream& operator<<(basic_json& j, std::istream& i)
+    {
+        return operator>>(i, j);
+    }
 
-    @throw parse_error.101 in case of an unexpected token
-    @throw parse_error.102 if to_unicode fails or surrogate error
-    @throw parse_error.103 if to_unicode fails
-
-    @complexity Linear in the length of the input. The parser is a predictive
-    LL(1) parser.
-
-    @note A UTF-8 byte order mark is silently ignored.
-
-    @liveexample{The example below shows how a JSON value is constructed by
-    reading a serialization from a stream.,operator_deserialize}
-
-    @sa parse(std::istream&, const parser_callback_t) for a variant with a
-    parser callback function to filter values while parsing
-
-    @since version 1.0.0
-    */
-    friend raw_istream& operator>>(raw_istream& i, json& j);
-
+    /// @brief deserialize from stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
+    friend std::istream& operator>>(std::istream& i, basic_json& j)
+    {
+        parser(detail::input_adapter(i)).parse(false, j);
+        return i;
+    }
+#endif  // JSON_NO_IO
     /// @}
 
     ///////////////////////////
     // convenience functions //
     ///////////////////////////
 
-    /*!
-    @brief return the type as string
-
-    Returns the type name as string to be used in error messages - usually to
-    indicate that a function was called on a wrong JSON type.
-
-    @return a string representation of a the @a m_type member:
-            Value type  | return value
-            ----------- | -------------
-            null        | `"null"`
-            boolean     | `"boolean"`
-            string      | `"string"`
-            number      | `"number"` (for all number types)
-            object      | `"object"`
-            array       | `"array"`
-            discarded   | `"discarded"`
-
-    @exceptionsafety No-throw guarantee: this function never throws exceptions.
-
-    @complexity Constant.
-
-    @liveexample{The following code exemplifies `type_name()` for all JSON
-    types.,type_name}
-
-    @sa @ref type() -- return the type of the JSON value
-    @sa @ref operator value_t() -- return the type of the JSON value (implicit)
-
-    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`
-    since 3.0.0
-    */
-    const char* type_name() const noexcept;
+    /// @brief return the type as string
+    /// @sa https://json.nlohmann.me/api/basic_json/type_name/
+    JSON_HEDLEY_RETURNS_NON_NULL
+    const char* type_name() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+                return "null";
+            case value_t::object:
+                return "object";
+            case value_t::array:
+                return "array";
+            case value_t::string:
+                return "string";
+            case value_t::boolean:
+                return "boolean";
+            case value_t::binary:
+                return "binary";
+            case value_t::discarded:
+                return "discarded";
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            default:
+                return "number";
+        }
+    }
 
 
-  private:
+  JSON_PRIVATE_UNLESS_TESTED:
     //////////////////////
     // member variables //
     //////////////////////
@@ -7108,6 +4209,11 @@
     /// the value of the current element
     json_value m_value = {};
 
+#if JSON_DIAGNOSTICS
+    /// a pointer to a parent value (for debugging purposes)
+    basic_json* m_parent = nullptr;
+#endif
+
     //////////////////////////////////////////
     // binary serialization/deserialization //
     //////////////////////////////////////////
@@ -7116,514 +4222,380 @@
     /// @{
 
   public:
-    /*!
-    @brief create a CBOR serialization of a given JSON value
+    /// @brief create a CBOR serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
+    static std::vector<std::uint8_t> to_cbor(const basic_json& j)
+    {
+        std::vector<std::uint8_t> result;
+        to_cbor(j, result);
+        return result;
+    }
 
-    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
-    Binary Object Representation) serialization format. CBOR is a binary
-    serialization format which aims to be more compact than JSON itself, yet
-    more efficient to parse.
+    /// @brief create a CBOR serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
+    static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)
+    {
+        binary_writer<std::uint8_t>(o).write_cbor(j);
+    }
 
-    The library uses the following mapping from JSON values types to
-    CBOR types according to the CBOR specification (RFC 7049):
+    /// @brief create a CBOR serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
+    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
+    {
+        binary_writer<char>(o).write_cbor(j);
+    }
 
-    JSON value type | value/range                                | CBOR type                          | first byte
-    --------------- | ------------------------------------------ | ---------------------------------- | ---------------
-    null            | `null`                                     | Null                               | 0xF6
-    boolean         | `true`                                     | True                               | 0xF5
-    boolean         | `false`                                    | False                              | 0xF4
-    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B
-    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A
-    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39
-    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38
-    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37
-    number_integer  | 0..23                                      | Integer                            | 0x00..0x17
-    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18
-    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19
-    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A
-    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B
-    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17
-    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18
-    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19
-    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A
-    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B
-    number_float    | *any value*                                | Double-Precision Float             | 0xFB
-    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77
-    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78
-    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79
-    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A
-    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B
-    array           | *size*: 0..23                              | array                              | 0x80..0x97
-    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98
-    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99
-    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A
-    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B
-    object          | *size*: 0..23                              | map                                | 0xA0..0xB7
-    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8
-    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9
-    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA
-    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB
+    /// @brief create a MessagePack serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
+    static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
+    {
+        std::vector<std::uint8_t> result;
+        to_msgpack(j, result);
+        return result;
+    }
 
-    @note The mapping is **complete** in the sense that any JSON value type
-          can be converted to a CBOR value.
+    /// @brief create a MessagePack serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
+    static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)
+    {
+        binary_writer<std::uint8_t>(o).write_msgpack(j);
+    }
 
-    @note If NaN or Infinity are stored inside a JSON number, they are
-          serialized properly. This behavior differs from the @ref dump()
-          function which serializes NaN or Infinity to `null`.
+    /// @brief create a MessagePack serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
+    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
+    {
+        binary_writer<char>(o).write_msgpack(j);
+    }
 
-    @note The following CBOR types are not used in the conversion:
-          - byte strings (0x40..0x5F)
-          - UTF-8 strings terminated by "break" (0x7F)
-          - arrays terminated by "break" (0x9F)
-          - maps terminated by "break" (0xBF)
-          - date/time (0xC0..0xC1)
-          - bignum (0xC2..0xC3)
-          - decimal fraction (0xC4)
-          - bigfloat (0xC5)
-          - tagged items (0xC6..0xD4, 0xD8..0xDB)
-          - expected conversions (0xD5..0xD7)
-          - simple values (0xE0..0xF3, 0xF8)
-          - undefined (0xF7)
-          - half and single-precision floats (0xF9-0xFA)
-          - break (0xFF)
+    /// @brief create a UBJSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
+    static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
+            const bool use_size = false,
+            const bool use_type = false)
+    {
+        std::vector<std::uint8_t> result;
+        to_ubjson(j, result, use_size, use_type);
+        return result;
+    }
 
-    @param[in] j  JSON value to serialize
-    @return MessagePack serialization as byte vector
+    /// @brief create a UBJSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
+    static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
+    }
 
-    @complexity Linear in the size of the JSON value @a j.
+    /// @brief create a UBJSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
+    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<char>(o).write_ubjson(j, use_size, use_type);
+    }
 
-    @liveexample{The example shows the serialization of a JSON value to a byte
-    vector in CBOR format.,to_cbor}
+    /// @brief create a BJData serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
+    static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
+            const bool use_size = false,
+            const bool use_type = false)
+    {
+        std::vector<std::uint8_t> result;
+        to_bjdata(j, result, use_size, use_type);
+        return result;
+    }
 
-    @sa http://cbor.io
-    @sa @ref from_cbor(raw_istream&, const bool strict) for the
-        analogous deserialization
-    @sa @ref to_msgpack(const json&) for the related MessagePack format
-    @sa @ref to_ubjson(const json&, const bool, const bool) for the
-             related UBJSON format
+    /// @brief create a BJData serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
+    static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true);
+    }
 
-    @since version 2.0.9
-    */
-    static std::vector<uint8_t> to_cbor(const json& j);
-    static std::span<uint8_t> to_cbor(const json& j, std::vector<uint8_t>& buf);
-    static std::span<uint8_t> to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf);
-    static void to_cbor(raw_ostream& os, const json& j);
+    /// @brief create a BJData serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
+    static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true);
+    }
 
-    /*!
-    @brief create a MessagePack serialization of a given JSON value
+    /// @brief create a BSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
+    static std::vector<std::uint8_t> to_bson(const basic_json& j)
+    {
+        std::vector<std::uint8_t> result;
+        to_bson(j, result);
+        return result;
+    }
 
-    Serializes a given JSON value @a j to a byte vector using the MessagePack
-    serialization format. MessagePack is a binary serialization format which
-    aims to be more compact than JSON itself, yet more efficient to parse.
+    /// @brief create a BSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
+    static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)
+    {
+        binary_writer<std::uint8_t>(o).write_bson(j);
+    }
 
-    The library uses the following mapping from JSON values types to
-    MessagePack types according to the MessagePack specification:
+    /// @brief create a BSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
+    static void to_bson(const basic_json& j, detail::output_adapter<char> o)
+    {
+        binary_writer<char>(o).write_bson(j);
+    }
 
-    JSON value type | value/range                       | MessagePack type | first byte
-    --------------- | --------------------------------- | ---------------- | ----------
-    null            | `null`                            | nil              | 0xC0
-    boolean         | `true`                            | true             | 0xC3
-    boolean         | `false`                           | false            | 0xC2
-    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3
-    number_integer  | -2147483648..-32769               | int32            | 0xD2
-    number_integer  | -32768..-129                      | int16            | 0xD1
-    number_integer  | -128..-33                         | int8             | 0xD0
-    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF
-    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F
-    number_integer  | 128..255                          | uint 8           | 0xCC
-    number_integer  | 256..65535                        | uint 16          | 0xCD
-    number_integer  | 65536..4294967295                 | uint 32          | 0xCE
-    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF
-    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F
-    number_unsigned | 128..255                          | uint 8           | 0xCC
-    number_unsigned | 256..65535                        | uint 16          | 0xCD
-    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE
-    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF
-    number_float    | *any value*                       | float 64         | 0xCB
-    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF
-    string          | *length*: 32..255                 | str 8            | 0xD9
-    string          | *length*: 256..65535              | str 16           | 0xDA
-    string          | *length*: 65536..4294967295       | str 32           | 0xDB
-    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F
-    array           | *size*: 16..65535                 | array 16         | 0xDC
-    array           | *size*: 65536..4294967295         | array 32         | 0xDD
-    object          | *size*: 0..15                     | fix map          | 0x80..0x8F
-    object          | *size*: 16..65535                 | map 16           | 0xDE
-    object          | *size*: 65536..4294967295         | map 32           | 0xDF
+    /// @brief create a JSON value from an input in CBOR format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_cbor(InputType&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @note The mapping is **complete** in the sense that any JSON value type
-          can be converted to a MessagePack value.
+    /// @brief create a JSON value from an input in CBOR format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_cbor(IteratorType first, IteratorType last,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @note The following values can **not** be converted to a MessagePack value:
-          - strings with more than 4294967295 bytes
-          - arrays with more than 4294967295 elements
-          - objects with more than 4294967295 elements
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
+    static basic_json from_cbor(const T* ptr, std::size_t len,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
+    }
 
-    @note The following MessagePack types are not used in the conversion:
-          - bin 8 - bin 32 (0xC4..0xC6)
-          - ext 8 - ext 32 (0xC7..0xC9)
-          - float 32 (0xCA)
-          - fixext 1 - fixext 16 (0xD4..0xD8)
 
-    @note Any MessagePack output created @ref to_msgpack can be successfully
-          parsed by @ref from_msgpack.
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
+    static basic_json from_cbor(detail::span_input_adapter&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @note If NaN or Infinity are stored inside a JSON number, they are
-          serialized properly. This behavior differs from the @ref dump()
-          function which serializes NaN or Infinity to `null`.
+    /// @brief create a JSON value from an input in MessagePack format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_msgpack(InputType&& i,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @param[in] j  JSON value to serialize
-    @return MessagePack serialization as byte vector
+    /// @brief create a JSON value from an input in MessagePack format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_msgpack(IteratorType first, IteratorType last,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @complexity Linear in the size of the JSON value @a j.
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
+    static basic_json from_msgpack(const T* ptr, std::size_t len,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
+    }
 
-    @liveexample{The example shows the serialization of a JSON value to a byte
-    vector in MessagePack format.,to_msgpack}
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
+    static basic_json from_msgpack(detail::span_input_adapter&& i,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @sa http://msgpack.org
-    @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the
-        analogous deserialization
-    @sa @ref to_cbor(const json& for the related CBOR format
-    @sa @ref to_ubjson(const json&, const bool, const bool) for the
-             related UBJSON format
+    /// @brief create a JSON value from an input in UBJSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_ubjson(InputType&& i,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @since version 2.0.9
-    */
-    static std::vector<uint8_t> to_msgpack(const json& j);
-    static std::span<uint8_t> to_msgpack(const json& j, std::vector<uint8_t>& buf);
-    static std::span<uint8_t> to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf);
-    static void to_msgpack(raw_ostream& os, const json& j);
+    /// @brief create a JSON value from an input in UBJSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_ubjson(IteratorType first, IteratorType last,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    /*!
-    @brief create a UBJSON serialization of a given JSON value
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
+    static basic_json from_ubjson(const T* ptr, std::size_t len,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
+    }
 
-    Serializes a given JSON value @a j to a byte vector using the UBJSON
-    (Universal Binary JSON) serialization format. UBJSON aims to be more compact
-    than JSON itself, yet more efficient to parse.
-
-    The library uses the following mapping from JSON values types to
-    UBJSON types according to the UBJSON specification:
-
-    JSON value type | value/range                       | UBJSON type | marker
-    --------------- | --------------------------------- | ----------- | ------
-    null            | `null`                            | null        | `Z`
-    boolean         | `true`                            | true        | `T`
-    boolean         | `false`                           | false       | `F`
-    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`
-    number_integer  | -2147483648..-32769               | int32       | `l`
-    number_integer  | -32768..-129                      | int16       | `I`
-    number_integer  | -128..127                         | int8        | `i`
-    number_integer  | 128..255                          | uint8       | `U`
-    number_integer  | 256..32767                        | int16       | `I`
-    number_integer  | 32768..2147483647                 | int32       | `l`
-    number_integer  | 2147483648..9223372036854775807   | int64       | `L`
-    number_unsigned | 0..127                            | int8        | `i`
-    number_unsigned | 128..255                          | uint8       | `U`
-    number_unsigned | 256..32767                        | int16       | `I`
-    number_unsigned | 32768..2147483647                 | int32       | `l`
-    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`
-    number_float    | *any value*                       | float64     | `D`
-    string          | *with shortest length indicator*  | string      | `S`
-    array           | *see notes on optimized format*   | array       | `[`
-    object          | *see notes on optimized format*   | map         | `{`
-
-    @note The mapping is **complete** in the sense that any JSON value type
-          can be converted to a UBJSON value.
-
-    @note The following values can **not** be converted to a UBJSON value:
-          - strings with more than 9223372036854775807 bytes (theoretical)
-          - unsigned integer numbers above 9223372036854775807
-
-    @note The following markers are not used in the conversion:
-          - `Z`: no-op values are not created.
-          - `C`: single-byte strings are serialized with `S` markers.
-
-    @note Any UBJSON output created @ref to_ubjson can be successfully parsed
-          by @ref from_ubjson.
-
-    @note If NaN or Infinity are stored inside a JSON number, they are
-          serialized properly. This behavior differs from the @ref dump()
-          function which serializes NaN or Infinity to `null`.
-
-    @note The optimized formats for containers are supported: Parameter
-          @a use_size adds size information to the beginning of a container and
-          removes the closing marker. Parameter @a use_type further checks
-          whether all elements of a container have the same type and adds the
-          type marker to the beginning of the container. The @a use_type
-          parameter must only be used together with @a use_size = true. Note
-          that @a use_size = true alone may result in larger representations -
-          the benefit of this parameter is that the receiving side is
-          immediately informed on the number of elements of the container.
-
-    @param[in] j  JSON value to serialize
-    @param[in] use_size  whether to add size annotations to container types
-    @param[in] use_type  whether to add type annotations to container types
-                         (must be combined with @a use_size = true)
-    @return UBJSON serialization as byte vector
-
-    @complexity Linear in the size of the JSON value @a j.
-
-    @liveexample{The example shows the serialization of a JSON value to a byte
-    vector in UBJSON format.,to_ubjson}
-
-    @sa http://ubjson.org
-    @sa @ref from_ubjson(raw_istream&, const bool strict) for the
-        analogous deserialization
-    @sa @ref to_cbor(const json& for the related CBOR format
-    @sa @ref to_msgpack(const json&) for the related MessagePack format
-
-    @since version 3.1.0
-    */
-    static std::vector<uint8_t> to_ubjson(const json& j,
-                                          const bool use_size = false,
-                                          const bool use_type = false);
-    static std::span<uint8_t> to_ubjson(const json& j, std::vector<uint8_t>& buf,
-                                   const bool use_size = false, const bool use_type = false);
-    static std::span<uint8_t> to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
-                                   const bool use_size = false, const bool use_type = false);
-    static void to_ubjson(raw_ostream& os, const json& j,
-                          const bool use_size = false, const bool use_type = false);
-
-    /*!
-    @brief create a JSON value from an input in CBOR format
-
-    Deserializes a given input @a i to a JSON value using the CBOR (Concise
-    Binary Object Representation) serialization format.
-
-    The library maps CBOR types to JSON value types as follows:
-
-    CBOR type              | JSON value type | first byte
-    ---------------------- | --------------- | ----------
-    Integer                | number_unsigned | 0x00..0x17
-    Unsigned integer       | number_unsigned | 0x18
-    Unsigned integer       | number_unsigned | 0x19
-    Unsigned integer       | number_unsigned | 0x1A
-    Unsigned integer       | number_unsigned | 0x1B
-    Negative integer       | number_integer  | 0x20..0x37
-    Negative integer       | number_integer  | 0x38
-    Negative integer       | number_integer  | 0x39
-    Negative integer       | number_integer  | 0x3A
-    Negative integer       | number_integer  | 0x3B
-    Negative integer       | number_integer  | 0x40..0x57
-    UTF-8 string           | string          | 0x60..0x77
-    UTF-8 string           | string          | 0x78
-    UTF-8 string           | string          | 0x79
-    UTF-8 string           | string          | 0x7A
-    UTF-8 string           | string          | 0x7B
-    UTF-8 string           | string          | 0x7F
-    array                  | array           | 0x80..0x97
-    array                  | array           | 0x98
-    array                  | array           | 0x99
-    array                  | array           | 0x9A
-    array                  | array           | 0x9B
-    array                  | array           | 0x9F
-    map                    | object          | 0xA0..0xB7
-    map                    | object          | 0xB8
-    map                    | object          | 0xB9
-    map                    | object          | 0xBA
-    map                    | object          | 0xBB
-    map                    | object          | 0xBF
-    False                  | `false`         | 0xF4
-    True                   | `true`          | 0xF5
-    Nill                   | `null`          | 0xF6
-    Half-Precision Float   | number_float    | 0xF9
-    Single-Precision Float | number_float    | 0xFA
-    Double-Precision Float | number_float    | 0xFB
-
-    @warning The mapping is **incomplete** in the sense that not all CBOR
-             types can be converted to a JSON value. The following CBOR types
-             are not supported and will yield parse errors (parse_error.112):
-             - byte strings (0x40..0x5F)
-             - date/time (0xC0..0xC1)
-             - bignum (0xC2..0xC3)
-             - decimal fraction (0xC4)
-             - bigfloat (0xC5)
-             - tagged items (0xC6..0xD4, 0xD8..0xDB)
-             - expected conversions (0xD5..0xD7)
-             - simple values (0xE0..0xF3, 0xF8)
-             - undefined (0xF7)
-
-    @warning CBOR allows map keys of any type, whereas JSON only allows
-             strings as keys in object values. Therefore, CBOR maps with keys
-             other than UTF-8 strings are rejected (parse_error.113).
-
-    @note Any CBOR output created @ref to_cbor can be successfully parsed by
-          @ref from_cbor.
-
-    @param[in] i  an input in CBOR format convertible to an input adapter
-    @param[in] strict  whether to expect the input to be consumed until EOF
-                       (true by default)
-    @return deserialized JSON value
-
-    @throw parse_error.110 if the given input ends prematurely or the end of
-    file was not reached when @a strict was set to true
-    @throw parse_error.112 if unsupported features from CBOR were
-    used in the given input @a v or if the input is not valid CBOR
-    @throw parse_error.113 if a string was expected as map key, but not found
-
-    @complexity Linear in the size of the input @a i.
-
-    @liveexample{The example shows the deserialization of a byte vector in CBOR
-    format to a JSON value.,from_cbor}
-
-    @sa http://cbor.io
-    @sa @ref to_cbor(const json&) for the analogous serialization
-    @sa @ref from_msgpack(raw_istream&, const bool) for the
-        related MessagePack format
-    @sa @ref from_ubjson(raw_istream&, const bool) for the related
-        UBJSON format
-
-    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
-           consume input adapters, removed start_index parameter, and added
-           @a strict parameter since 3.0.0
-    */
-    static json from_cbor(raw_istream& is,
-                                const bool strict = true);
-
-    /*!
-    @copydoc from_cbor(raw_istream&, const bool)
-    */
-    static json from_cbor(std::span<const uint8_t> arr, const bool strict = true);
-
-    /*!
-    @brief create a JSON value from an input in MessagePack format
-
-    Deserializes a given input @a i to a JSON value using the MessagePack
-    serialization format.
-
-    The library maps MessagePack types to JSON value types as follows:
-
-    MessagePack type | JSON value type | first byte
-    ---------------- | --------------- | ----------
-    positive fixint  | number_unsigned | 0x00..0x7F
-    fixmap           | object          | 0x80..0x8F
-    fixarray         | array           | 0x90..0x9F
-    fixstr           | string          | 0xA0..0xBF
-    nil              | `null`          | 0xC0
-    false            | `false`         | 0xC2
-    true             | `true`          | 0xC3
-    float 32         | number_float    | 0xCA
-    float 64         | number_float    | 0xCB
-    uint 8           | number_unsigned | 0xCC
-    uint 16          | number_unsigned | 0xCD
-    uint 32          | number_unsigned | 0xCE
-    uint 64          | number_unsigned | 0xCF
-    int 8            | number_integer  | 0xD0
-    int 16           | number_integer  | 0xD1
-    int 32           | number_integer  | 0xD2
-    int 64           | number_integer  | 0xD3
-    str 8            | string          | 0xD9
-    str 16           | string          | 0xDA
-    str 32           | string          | 0xDB
-    array 16         | array           | 0xDC
-    array 32         | array           | 0xDD
-    map 16           | object          | 0xDE
-    map 32           | object          | 0xDF
-    negative fixint  | number_integer  | 0xE0-0xFF
-
-    @warning The mapping is **incomplete** in the sense that not all
-             MessagePack types can be converted to a JSON value. The following
-             MessagePack types are not supported and will yield parse errors:
-              - bin 8 - bin 32 (0xC4..0xC6)
-              - ext 8 - ext 32 (0xC7..0xC9)
-              - fixext 1 - fixext 16 (0xD4..0xD8)
-
-    @note Any MessagePack output created @ref to_msgpack can be successfully
-          parsed by @ref from_msgpack.
-
-    @param[in] i  an input in MessagePack format convertible to an input
-                  adapter
-    @param[in] strict  whether to expect the input to be consumed until EOF
-                       (true by default)
-
-    @throw parse_error.110 if the given input ends prematurely or the end of
-    file was not reached when @a strict was set to true
-    @throw parse_error.112 if unsupported features from MessagePack were
-    used in the given input @a i or if the input is not valid MessagePack
-    @throw parse_error.113 if a string was expected as map key, but not found
-
-    @complexity Linear in the size of the input @a i.
-
-    @liveexample{The example shows the deserialization of a byte vector in
-    MessagePack format to a JSON value.,from_msgpack}
-
-    @sa http://msgpack.org
-    @sa @ref to_msgpack(const json&) for the analogous serialization
-    @sa @ref from_cbor(raw_istream&, const bool) for the related CBOR
-        format
-    @sa @ref from_ubjson(raw_istream&, const bool) for the related
-        UBJSON format
-
-    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
-           consume input adapters, removed start_index parameter, and added
-           @a strict parameter since 3.0.0
-    */
-    static json from_msgpack(raw_istream& is,
-                                   const bool strict = true);
-
-    /*!
-    @copydoc from_msgpack(raw_istream&, const bool)
-    */
-    static json from_msgpack(std::span<const uint8_t> arr, const bool strict = true);
-
-    /*!
-    @brief create a JSON value from an input in UBJSON format
-
-    Deserializes a given input @a i to a JSON value using the UBJSON (Universal
-    Binary JSON) serialization format.
-
-    The library maps UBJSON types to JSON value types as follows:
-
-    UBJSON type | JSON value type                         | marker
-    ----------- | --------------------------------------- | ------
-    no-op       | *no value, next value is read*          | `N`
-    null        | `null`                                  | `Z`
-    false       | `false`                                 | `F`
-    true        | `true`                                  | `T`
-    float32     | number_float                            | `d`
-    float64     | number_float                            | `D`
-    uint8       | number_unsigned                         | `U`
-    int8        | number_integer                          | `i`
-    int16       | number_integer                          | `I`
-    int32       | number_integer                          | `l`
-    int64       | number_integer                          | `L`
-    string      | string                                  | `S`
-    char        | string                                  | `C`
-    array       | array (optimized values are supported)  | `[`
-    object      | object (optimized values are supported) | `{`
-
-    @note The mapping is **complete** in the sense that any UBJSON value can
-          be converted to a JSON value.
-
-    @param[in] i  an input in UBJSON format convertible to an input adapter
-    @param[in] strict  whether to expect the input to be consumed until EOF
-                       (true by default)
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
+    static basic_json from_ubjson(detail::span_input_adapter&& i,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @throw parse_error.110 if the given input ends prematurely or the end of
-    file was not reached when @a strict was set to true
-    @throw parse_error.112 if a parse error occurs
-    @throw parse_error.113 if a string could not be parsed successfully
 
-    @complexity Linear in the size of the input @a i.
+    /// @brief create a JSON value from an input in BJData format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bjdata(InputType&& i,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @liveexample{The example shows the deserialization of a byte vector in
-    UBJSON format to a JSON value.,from_ubjson}
+    /// @brief create a JSON value from an input in BJData format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bjdata(IteratorType first, IteratorType last,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @sa http://ubjson.org
-    @sa @ref to_ubjson(const json&, const bool, const bool) for the
-             analogous serialization
-    @sa @ref from_cbor(raw_istream&, const bool) for the related CBOR
-        format
-    @sa @ref from_msgpack(raw_istream&, const bool) for the related
-        MessagePack format
+    /// @brief create a JSON value from an input in BSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bson(InputType&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    @since version 3.1.0
-    */
-    static json from_ubjson(raw_istream& is,
-                                  const bool strict = true);
+    /// @brief create a JSON value from an input in BSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bson(IteratorType first, IteratorType last,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
 
-    static json from_ubjson(std::span<const uint8_t> arr, const bool strict = true);
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
+    static basic_json from_bson(const T* ptr, std::size_t len,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        return from_bson(ptr, ptr + len, strict, allow_exceptions);
+    }
 
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
+    static basic_json from_bson(detail::span_input_adapter&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
     /// @}
 
     //////////////////////////
@@ -7633,218 +4605,74 @@
     /// @name JSON Pointer functions
     /// @{
 
-    /*!
-    @brief access specified element via JSON Pointer
-
-    Uses a JSON pointer to retrieve a reference to the respective JSON value.
-    No bound checking is performed. Similar to @ref operator[](const typename
-    object_t::key_type&), `null` values are created in arrays and objects if
-    necessary.
-
-    In particular:
-    - If the JSON pointer points to an object key that does not exist, it
-      is created an filled with a `null` value before a reference to it
-      is returned.
-    - If the JSON pointer points to an array index that does not exist, it
-      is created an filled with a `null` value before a reference to it
-      is returned. All indices between the current maximum and the given
-      index are also filled with `null`.
-    - The special value `-` is treated as a synonym for the index past the
-      end.
-
-    @param[in] ptr  a JSON pointer
-
-    @return reference to the element pointed to by @a ptr
-
-    @complexity Constant.
-
-    @throw parse_error.106   if an array index begins with '0'
-    @throw parse_error.109   if an array index was not a number
-    @throw out_of_range.404  if the JSON pointer can not be resolved
-
-    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
-
-    @since version 2.0.0
-    */
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
     reference operator[](const json_pointer& ptr)
     {
         return ptr.get_unchecked(this);
     }
 
-    /*!
-    @brief access specified element via JSON Pointer
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    reference operator[](const ::wpi::json_pointer<BasicJsonType>& ptr)
+    {
+        return ptr.get_unchecked(this);
+    }
 
-    Uses a JSON pointer to retrieve a reference to the respective JSON value.
-    No bound checking is performed. The function does not change the JSON
-    value; no `null` values are created. In particular, the the special value
-    `-` yields an exception.
-
-    @param[in] ptr  JSON pointer to the desired element
-
-    @return const reference to the element pointed to by @a ptr
-
-    @complexity Constant.
-
-    @throw parse_error.106   if an array index begins with '0'
-    @throw parse_error.109   if an array index was not a number
-    @throw out_of_range.402  if the array index '-' is used
-    @throw out_of_range.404  if the JSON pointer can not be resolved
-
-    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
-
-    @since version 2.0.0
-    */
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
     const_reference operator[](const json_pointer& ptr) const
     {
         return ptr.get_unchecked(this);
     }
 
-    /*!
-    @brief access specified element via JSON Pointer
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    const_reference operator[](const ::wpi::json_pointer<BasicJsonType>& ptr) const
+    {
+        return ptr.get_unchecked(this);
+    }
 
-    Returns a reference to the element at with specified JSON pointer @a ptr,
-    with bounds checking.
-
-    @param[in] ptr  JSON pointer to the desired element
-
-    @return reference to the element pointed to by @a ptr
-
-    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
-    begins with '0'. See example below.
-
-    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
-    is not a number. See example below.
-
-    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
-    is out of range. See example below.
-
-    @throw out_of_range.402 if the array index '-' is used in the passed JSON
-    pointer @a ptr. As `at` provides checked access (and no elements are
-    implicitly inserted), the index '-' is always invalid. See example below.
-
-    @throw out_of_range.403 if the JSON pointer describes a key of an object
-    which cannot be found. See example below.
-
-    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
-    See example below.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Constant.
-
-    @since version 2.0.0
-
-    @liveexample{The behavior is shown in the example.,at_json_pointer}
-    */
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
     reference at(const json_pointer& ptr)
     {
         return ptr.get_checked(this);
     }
 
-    /*!
-    @brief access specified element via JSON Pointer
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    reference at(const ::wpi::json_pointer<BasicJsonType>& ptr)
+    {
+        return ptr.get_checked(this);
+    }
 
-    Returns a const reference to the element at with specified JSON pointer @a
-    ptr, with bounds checking.
-
-    @param[in] ptr  JSON pointer to the desired element
-
-    @return reference to the element pointed to by @a ptr
-
-    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
-    begins with '0'. See example below.
-
-    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
-    is not a number. See example below.
-
-    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
-    is out of range. See example below.
-
-    @throw out_of_range.402 if the array index '-' is used in the passed JSON
-    pointer @a ptr. As `at` provides checked access (and no elements are
-    implicitly inserted), the index '-' is always invalid. See example below.
-
-    @throw out_of_range.403 if the JSON pointer describes a key of an object
-    which cannot be found. See example below.
-
-    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
-    See example below.
-
-    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
-    changes in the JSON value.
-
-    @complexity Constant.
-
-    @since version 2.0.0
-
-    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
-    */
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
     const_reference at(const json_pointer& ptr) const
     {
         return ptr.get_checked(this);
     }
 
-    /*!
-    @brief return flattened JSON value
-
-    The function creates a JSON object whose keys are JSON pointers (see [RFC
-    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
-    primitive. The original JSON value can be restored using the @ref
-    unflatten() function.
-
-    @return an object that maps JSON pointers to primitive values
-
-    @note Empty objects and arrays are flattened to `null` and will not be
-          reconstructed correctly by the @ref unflatten() function.
-
-    @complexity Linear in the size the JSON value.
-
-    @liveexample{The following code shows how a JSON object is flattened to an
-    object whose keys consist of JSON pointers.,flatten}
-
-    @sa @ref unflatten() for the reverse function
-
-    @since version 2.0.0
-    */
-    json flatten() const
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or wpi::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    const_reference at(const ::wpi::json_pointer<BasicJsonType>& ptr) const
     {
-        json result(value_t::object);
+        return ptr.get_checked(this);
+    }
+
+    /// @brief return flattened JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/flatten/
+    basic_json flatten() const
+    {
+        basic_json result(value_t::object);
         json_pointer::flatten("", *this, result);
         return result;
     }
 
-    /*!
-    @brief unflatten a previously flattened JSON value
-
-    The function restores the arbitrary nesting of a JSON value that has been
-    flattened before using the @ref flatten() function. The JSON value must
-    meet certain constraints:
-    1. The value must be an object.
-    2. The keys must be JSON pointers (see
-       [RFC 6901](https://tools.ietf.org/html/rfc6901))
-    3. The mapped values must be primitive JSON types.
-
-    @return the original JSON from a flattened version
-
-    @note Empty objects and arrays are flattened by @ref flatten() to `null`
-          values and can not unflattened to their original type. Apart from
-          this example, for a JSON value `j`, the following is always true:
-          `j == j.flatten().unflatten()`.
-
-    @complexity Linear in the size the JSON value.
-
-    @throw type_error.314  if value is not an object
-    @throw type_error.315  if object values are not primitive
-
-    @liveexample{The following code shows how a flattened JSON object is
-    unflattened into the original nested JSON object.,unflatten}
-
-    @sa @ref flatten() for the reverse function
-
-    @since version 2.0.0
-    */
-    json unflatten() const
+    /// @brief unflatten a previously flattened JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/unflatten/
+    basic_json unflatten() const
     {
         return json_pointer::unflatten(*this);
     }
@@ -7858,91 +4686,420 @@
     /// @name JSON Patch functions
     /// @{
 
-    /*!
-    @brief applies a JSON patch
+    /// @brief applies a JSON patch in-place without copying the object
+    /// @sa https://json.nlohmann.me/api/basic_json/patch/
+    void patch_inplace(const basic_json& json_patch)
+    {
+        basic_json& result = *this;
+        // the valid JSON Patch operations
+        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
 
-    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
-    expressing a sequence of operations to apply to a JSON) document. With
-    this function, a JSON Patch is applied to the current JSON value by
-    executing all operations from the patch.
+        const auto get_op = [](const std::string & op)
+        {
+            if (op == "add")
+            {
+                return patch_operations::add;
+            }
+            if (op == "remove")
+            {
+                return patch_operations::remove;
+            }
+            if (op == "replace")
+            {
+                return patch_operations::replace;
+            }
+            if (op == "move")
+            {
+                return patch_operations::move;
+            }
+            if (op == "copy")
+            {
+                return patch_operations::copy;
+            }
+            if (op == "test")
+            {
+                return patch_operations::test;
+            }
 
-    @param[in] json_patch  JSON patch document
-    @return patched document
+            return patch_operations::invalid;
+        };
 
-    @note The application of a patch is atomic: Either all operations succeed
-          and the patched document is returned or an exception is thrown. In
-          any case, the original value is not changed: the patch is applied
-          to a copy of the value.
+        // wrapper for "add" operation; add value at ptr
+        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
+        {
+            // adding to the root of the target document means replacing it
+            if (ptr.empty())
+            {
+                result = val;
+                return;
+            }
 
-    @throw parse_error.104 if the JSON patch does not consist of an array of
-    objects
+            // make sure the top element of the pointer exists
+            json_pointer top_pointer = ptr.top();
+            if (top_pointer != ptr)
+            {
+                result.at(top_pointer);
+            }
 
-    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory
-    attributes are missing); example: `"operation add must have member path"`
+            // get reference to parent of JSON pointer ptr
+            const auto last_path = ptr.back();
+            ptr.pop_back();
+            // parent must exist when performing patch add per RFC6902 specs
+            basic_json& parent = result.at(ptr);
 
-    @throw out_of_range.401 if an array index is out of range.
+            switch (parent.m_type)
+            {
+                case value_t::null:
+                case value_t::object:
+                {
+                    // use operator[] to add value
+                    parent[last_path] = val;
+                    break;
+                }
 
-    @throw out_of_range.403 if a JSON pointer inside the patch could not be
-    resolved successfully in the current JSON value; example: `"key baz not
-    found"`
+                case value_t::array:
+                {
+                    if (last_path == "-")
+                    {
+                        // special case: append to back
+                        parent.push_back(val);
+                    }
+                    else
+                    {
+                        const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
+                        if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
+                        {
+                            // avoid undefined behavior
+                            JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
+                        }
 
-    @throw out_of_range.405 if JSON pointer has no parent ("add", "remove",
-    "move")
+                        // default case: insert add offset
+                        parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
+                    }
+                    break;
+                }
 
-    @throw other_error.501 if "test" operation was unsuccessful
+                // if there exists a parent it cannot be primitive
+                case value_t::string: // LCOV_EXCL_LINE
+                case value_t::boolean: // LCOV_EXCL_LINE
+                case value_t::number_integer: // LCOV_EXCL_LINE
+                case value_t::number_unsigned: // LCOV_EXCL_LINE
+                case value_t::number_float: // LCOV_EXCL_LINE
+                case value_t::binary: // LCOV_EXCL_LINE
+                case value_t::discarded: // LCOV_EXCL_LINE
+                default:            // LCOV_EXCL_LINE
+                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+            }
+        };
 
-    @complexity Linear in the size of the JSON value and the length of the
-    JSON patch. As usually only a fraction of the JSON value is affected by
-    the patch, the complexity can usually be neglected.
+        // wrapper for "remove" operation; remove value at ptr
+        const auto operation_remove = [this, &result](json_pointer & ptr)
+        {
+            // get reference to parent of JSON pointer ptr
+            const auto last_path = ptr.back();
+            ptr.pop_back();
+            basic_json& parent = result.at(ptr);
 
-    @liveexample{The following code shows how a JSON patch is applied to a
-    value.,patch}
+            // remove child
+            if (parent.is_object())
+            {
+                // perform range check
+                auto it = parent.find(last_path);
+                if (JSON_HEDLEY_LIKELY(it != parent.end()))
+                {
+                    parent.erase(it);
+                }
+                else
+                {
+                    JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
+                }
+            }
+            else if (parent.is_array())
+            {
+                // note erase performs range check
+                parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
+            }
+        };
 
-    @sa @ref diff -- create a JSON patch by comparing two JSON values
+        // type check: top level value must be an array
+        if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
+        {
+            JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
+        }
 
-    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
-    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
+        // iterate and apply the operations
+        for (const auto& val : json_patch)
+        {
+            // wrapper to get a value for an operation
+            const auto get_value = [&val](const std::string & op,
+                                          const std::string & member,
+                                          bool string_type) -> basic_json &
+            {
+                // find value
+                auto it = val.m_value.object->find(member);
 
-    @since version 2.0.0
-    */
-    json patch(const json& json_patch) const;
+                // context-sensitive error message
+                const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\'');
 
-    /*!
-    @brief creates a diff as a JSON patch
+                // check if desired value is present
+                if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end()))
+                {
+                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
+                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
+                }
 
-    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
-    be changed into the value @a target by calling @ref patch function.
+                // check if result is of type string
+                if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
+                {
+                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
+                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
+                }
 
-    @invariant For two JSON values @a source and @a target, the following code
-    yields always `true`:
-    @code {.cpp}
-    source.patch(diff(source, target)) == target;
-    @endcode
+                // no error: return value
+                return it->second;
+            };
 
-    @note Currently, only `remove`, `add`, and `replace` operations are
-          generated.
+            // type check: every element of the array must be an object
+            if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
+            {
+                JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
+            }
 
-    @param[in] source  JSON value to compare from
-    @param[in] target  JSON value to compare against
-    @param[in] path    helper value to create JSON pointers
+            // collect mandatory members
+            const auto op = get_value("op", "op", true).template get<std::string>();
+            const auto path = get_value(op, "path", true).template get<std::string>();
+            json_pointer ptr(path);
 
-    @return a JSON patch to convert the @a source to @a target
+            switch (get_op(op))
+            {
+                case patch_operations::add:
+                {
+                    operation_add(ptr, get_value("add", "value", false));
+                    break;
+                }
 
-    @complexity Linear in the lengths of @a source and @a target.
+                case patch_operations::remove:
+                {
+                    operation_remove(ptr);
+                    break;
+                }
 
-    @liveexample{The following code shows how a JSON patch is created as a
-    diff for two JSON values.,diff}
+                case patch_operations::replace:
+                {
+                    // the "path" location must exist - use at()
+                    result.at(ptr) = get_value("replace", "value", false);
+                    break;
+                }
 
-    @sa @ref patch -- apply a JSON patch
-    @sa @ref merge_patch -- apply a JSON Merge Patch
+                case patch_operations::move:
+                {
+                    const auto from_path = get_value("move", "from", true).template get<std::string>();
+                    json_pointer from_ptr(from_path);
 
-    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
+                    // the "from" location must exist - use at()
+                    basic_json v = result.at(from_ptr);
 
-    @since version 2.0.0
-    */
-    static json diff(const json& source, const json& target,
-                           const std::string& path = "");
+                    // The move operation is functionally identical to a
+                    // "remove" operation on the "from" location, followed
+                    // immediately by an "add" operation at the target
+                    // location with the value that was just removed.
+                    operation_remove(from_ptr);
+                    operation_add(ptr, v);
+                    break;
+                }
 
+                case patch_operations::copy:
+                {
+                    const auto from_path = get_value("copy", "from", true).template get<std::string>();
+                    const json_pointer from_ptr(from_path);
+
+                    // the "from" location must exist - use at()
+                    basic_json v = result.at(from_ptr);
+
+                    // The copy is functionally identical to an "add"
+                    // operation at the target location using the value
+                    // specified in the "from" member.
+                    operation_add(ptr, v);
+                    break;
+                }
+
+                case patch_operations::test:
+                {
+                    bool success = false;
+                    JSON_TRY
+                    {
+                        // check if "value" matches the one at "path"
+                        // the "path" location must exist - use at()
+                        success = (result.at(ptr) == get_value("test", "value", false));
+                    }
+                    JSON_INTERNAL_CATCH (out_of_range&)
+                    {
+                        // ignore out of range errors: success remains false
+                    }
+
+                    // throw an exception if test fails
+                    if (JSON_HEDLEY_UNLIKELY(!success))
+                    {
+                        JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
+                    }
+
+                    break;
+                }
+
+                case patch_operations::invalid:
+                default:
+                {
+                    // op must be "add", "remove", "replace", "move", "copy", or
+                    // "test"
+                    JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
+                }
+            }
+        }
+    }
+
+    /// @brief applies a JSON patch to a copy of the current object
+    /// @sa https://json.nlohmann.me/api/basic_json/patch/
+    basic_json patch(const basic_json& json_patch) const
+    {
+        basic_json result = *this;
+        result.patch_inplace(json_patch);
+        return result;
+    }
+
+    /// @brief creates a diff as a JSON patch
+    /// @sa https://json.nlohmann.me/api/basic_json/diff/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json diff(const basic_json& source, const basic_json& target,
+                           const std::string& path = "")
+    {
+        // the patch
+        basic_json result(value_t::array);
+
+        // if the values are the same, return empty patch
+        if (source == target)
+        {
+            return result;
+        }
+
+        if (source.type() != target.type())
+        {
+            // different types: replace value
+            result.push_back(
+            {
+                {"op", "replace"}, {"path", path}, {"value", target}
+            });
+            return result;
+        }
+
+        switch (source.type())
+        {
+            case value_t::array:
+            {
+                // first pass: traverse common elements
+                std::size_t i = 0;
+                while (i < source.size() && i < target.size())
+                {
+                    // recursive call to compare array values at index i
+                    auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i)));
+                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());
+                    ++i;
+                }
+
+                // We now reached the end of at least one array
+                // in a second pass, traverse the remaining elements
+
+                // remove my remaining elements
+                const auto end_index = static_cast<difference_type>(result.size());
+                while (i < source.size())
+                {
+                    // add operations in reverse order to avoid invalid
+                    // indices
+                    result.insert(result.begin() + end_index, object(
+                    {
+                        {"op", "remove"},
+                        {"path", detail::concat(path, '/', std::to_string(i))}
+                    }));
+                    ++i;
+                }
+
+                // add other remaining elements
+                while (i < target.size())
+                {
+                    result.push_back(
+                    {
+                        {"op", "add"},
+                        {"path", detail::concat(path, "/-")},
+                        {"value", target[i]}
+                    });
+                    ++i;
+                }
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                // first pass: traverse this object's elements
+                for (auto it = source.cbegin(); it != source.cend(); ++it)
+                {
+                    // escape the key name to be used in a JSON patch
+                    const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
+
+                    if (target.find(it.key()) != target.end())
+                    {
+                        // recursive call to compare object values at key it
+                        auto temp_diff = diff(it.value(), target[it.key()], path_key);
+                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
+                    }
+                    else
+                    {
+                        // found a key that is not in o -> remove it
+                        result.push_back(object(
+                        {
+                            {"op", "remove"}, {"path", path_key}
+                        }));
+                    }
+                }
+
+                // second pass: traverse other object's elements
+                for (auto it = target.cbegin(); it != target.cend(); ++it)
+                {
+                    if (source.find(it.key()) == source.end())
+                    {
+                        // found a key that is not in this -> add it
+                        const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
+                        result.push_back(
+                        {
+                            {"op", "add"}, {"path", path_key},
+                            {"value", it.value()}
+                        });
+                    }
+                }
+
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // both primitive type: replace value
+                result.push_back(
+                {
+                    {"op", "replace"}, {"path", path}, {"value", target}
+                });
+                break;
+            }
+        }
+
+        return result;
+    }
     /// @}
 
     ////////////////////////////////
@@ -7952,168 +5109,129 @@
     /// @name JSON Merge Patch functions
     /// @{
 
-    /*!
-    @brief applies a JSON Merge Patch
-
-    The merge patch format is primarily intended for use with the HTTP PATCH
-    method as a means of describing a set of modifications to a target
-    resource's content. This function applies a merge patch to the current
-    JSON value.
-
-    The function implements the following algorithm from Section 2 of
-    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):
-
-    ```
-    define MergePatch(Target, Patch):
-      if Patch is an Object:
-        if Target is not an Object:
-          Target = {} // Ignore the contents and set it to an empty Object
-        for each Name/Value pair in Patch:
-          if Value is null:
-            if Name exists in Target:
-              remove the Name/Value pair from Target
-          else:
-            Target[Name] = MergePatch(Target[Name], Value)
-        return Target
-      else:
-        return Patch
-    ```
-
-    Thereby, `Target` is the current object; that is, the patch is applied to
-    the current value.
-
-    @param[in] patch  the patch to apply
-
-    @complexity Linear in the lengths of @a patch.
-
-    @liveexample{The following code shows how a JSON Merge Patch is applied to
-    a JSON document.,merge_patch}
-
-    @sa @ref patch -- apply a JSON patch
-    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)
-
-    @since version 3.0.0
-    */
-    void merge_patch(const json& patch);
+    /// @brief applies a JSON Merge Patch
+    /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/
+    void merge_patch(const basic_json& apply_patch)
+    {
+        if (apply_patch.is_object())
+        {
+            if (!is_object())
+            {
+                *this = object();
+            }
+            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
+            {
+                if (it.value().is_null())
+                {
+                    erase(it.key());
+                }
+                else
+                {
+                    operator[](it.key()).merge_patch(it.value());
+                }
+            }
+        }
+        else
+        {
+            *this = apply_patch;
+        }
+    }
 
     /// @}
 };
-} // namespace wpi
+
+/// @brief user-defined to_string function for JSON values
+/// @sa https://json.nlohmann.me/api/basic_json/to_string/
+WPI_BASIC_JSON_TPL_DECLARATION
+std::string to_string(const WPI_BASIC_JSON_TPL& j)
+{
+    return j.dump();
+}
+
+inline namespace literals
+{
+inline namespace json_literals
+{
+
+/// @brief user-defined string literal for JSON values
+/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
+JSON_HEDLEY_NON_NULL(1)
+inline wpi::json operator "" _json(const char* s, std::size_t n)
+{
+    return wpi::json::parse(s, s + n);
+}
+
+/// @brief user-defined string literal for JSON pointer
+/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
+JSON_HEDLEY_NON_NULL(1)
+inline wpi::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
+{
+    return wpi::json::json_pointer(std::string(s, n));
+}
+
+}  // namespace json_literals
+}  // namespace literals
+WPI_JSON_NAMESPACE_END
 
 ///////////////////////
 // nonmember support //
 ///////////////////////
 
-// specialization of std::swap, and std::hash
-namespace std
+namespace std // NOLINT(cert-dcl58-cpp)
 {
-/*!
-@brief exchanges the values of two JSON objects
 
-@since version 1.0.0
-*/
-template<>
-inline void swap<wpi::json>(wpi::json& j1,
-                 wpi::json& j2) noexcept(
-                     is_nothrow_move_constructible<wpi::json>::value and
-                     is_nothrow_move_assignable<wpi::json>::value
-                 )
+/// @brief hash value for JSON objects
+/// @sa https://json.nlohmann.me/api/basic_json/std_hash/
+WPI_BASIC_JSON_TPL_DECLARATION
+struct hash<wpi::WPI_BASIC_JSON_TPL>
 {
-    j1.swap(j2);
-}
-
-/// hash value for JSON objects
-template<>
-struct hash<wpi::json>
-{
-    /*!
-    @brief return a hash value for a JSON object
-
-    @since version 1.0.0
-    */
-    std::size_t operator()(const wpi::json& j) const
+    std::size_t operator()(const wpi::WPI_BASIC_JSON_TPL& j) const
     {
-        // a naive hashing via the string representation
-        const auto& h = hash<std::string>();
-        return h(j.dump());
+        return wpi::detail::hash(j);
     }
 };
 
-/// specialization for std::less<value_t>
-/// @note: do not remove the space after '<',
-///        see https://github.com/nlohmann/json/pull/679
+// specialization for std::less<value_t>
 template<>
-struct less< ::wpi::detail::value_t>
+struct less< ::wpi::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
 {
     /*!
     @brief compare two value_t enum values
     @since version 3.0.0
     */
-    bool operator()(wpi::detail::value_t lhs,
-                    wpi::detail::value_t rhs) const noexcept
+    bool operator()(::wpi::detail::value_t lhs,
+                    ::wpi::detail::value_t rhs) const noexcept
     {
-        return wpi::detail::operator<(lhs, rhs);
+#if JSON_HAS_THREE_WAY_COMPARISON
+        return std::is_lt(lhs <=> rhs); // *NOPAD*
+#else
+        return ::wpi::detail::operator<(lhs, rhs);
+#endif
     }
 };
 
-} // namespace std
+// C++20 prohibit function specialization in the std namespace.
+#ifndef JSON_HAS_CPP_20
 
-/*!
-@brief user-defined string literal for JSON values
-
-This operator implements a user-defined string literal for JSON objects. It
-can be used by adding `"_json"` to a string literal and returns a JSON object
-if no parse error occurred.
-
-@param[in] s  a string representation of a JSON object
-@param[in] n  the length of string @a s
-@return a JSON object
-
-@since version 1.0.0
-*/
-inline wpi::json operator "" _json(const char* s, std::size_t n)
+/// @brief exchanges the values of two JSON objects
+/// @sa https://json.nlohmann.me/api/basic_json/std_swap/
+WPI_BASIC_JSON_TPL_DECLARATION
+inline void swap(wpi::WPI_BASIC_JSON_TPL& j1, wpi::WPI_BASIC_JSON_TPL& j2) noexcept(  // NOLINT(readability-inconsistent-declaration-parameter-name)
+    is_nothrow_move_constructible<wpi::WPI_BASIC_JSON_TPL>::value&&                          // NOLINT(misc-redundant-expression)
+    is_nothrow_move_assignable<wpi::WPI_BASIC_JSON_TPL>::value)
 {
-    return wpi::json::parse(std::string_view(s, n));
+    j1.swap(j2);
 }
 
-/*!
-@brief user-defined string literal for JSON pointer
-
-This operator implements a user-defined string literal for JSON Pointers. It
-can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
-object if no parse error occurred.
-
-@param[in] s  a string representation of a JSON Pointer
-@param[in] n  the length of string @a s
-@return a JSON pointer object
-
-@since version 2.0.0
-*/
-inline wpi::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
-{
-    return wpi::json::json_pointer(std::string_view(s, n));
-}
-
-#ifndef WPI_JSON_IMPLEMENTATION
-
-// restore GCC/clang diagnostic settings
-#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
-    #pragma GCC diagnostic pop
-#endif
-#if defined(__clang__)
-    #pragma GCC diagnostic pop
 #endif
 
-// clean up
-#undef JSON_CATCH
-#undef JSON_THROW
-#undef JSON_TRY
-#undef JSON_LIKELY
-#undef JSON_UNLIKELY
-#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
-#undef NLOHMANN_BASIC_JSON_TPL
-#undef NLOHMANN_JSON_HAS_HELPER
+}  // namespace std
 
-#endif  // WPI_JSON_IMPLEMENTATION
-
+#if JSON_USE_GLOBAL_UDLS
+    using wpi::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+    using wpi::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
 #endif
+
+#include <wpi/detail/macro_unscope.h>
+
+#endif  // INCLUDE_WPI_JSON_HPP_
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/json_fwd.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/json_fwd.h
new file mode 100644
index 0000000..3f549d7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/json_fwd.h
@@ -0,0 +1,74 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#ifndef INCLUDE_WPI_JSON_FWD_HPP_
+#define INCLUDE_WPI_JSON_FWD_HPP_
+
+#include <cstdint> // int64_t, uint64_t
+#include <map> // map
+#include <memory> // allocator
+#include <string> // string
+#include <vector> // vector
+
+#include <wpi/detail/abi_macros.h>
+
+/*!
+@brief namespace for Niels Lohmann
+@see https://github.com/nlohmann
+@since version 1.0.0
+*/
+WPI_JSON_NAMESPACE_BEGIN
+
+/*!
+@brief default JSONSerializer template argument
+
+This serializer ignores the template arguments and uses ADL
+([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
+for serialization.
+*/
+template<typename T = void, typename SFINAE = void>
+struct adl_serializer;
+
+/// a class to store JSON values
+/// @sa https://json.nlohmann.me/api/basic_json/
+template<template<typename U, typename V, typename... Args> class ObjectType =
+         std::map,
+         template<typename U, typename... Args> class ArrayType = std::vector,
+         class StringType = std::string, class BooleanType = bool,
+         class NumberIntegerType = std::int64_t,
+         class NumberUnsignedType = std::uint64_t,
+         class NumberFloatType = double,
+         template<typename U> class AllocatorType = std::allocator,
+         template<typename T, typename SFINAE = void> class JSONSerializer =
+         adl_serializer,
+         class BinaryType = std::vector<std::uint8_t>>
+class basic_json;
+
+/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
+/// @sa https://json.nlohmann.me/api/json_pointer/
+template<typename RefStringType>
+class json_pointer;
+
+/*!
+@brief default specialization
+@sa https://json.nlohmann.me/api/json/
+*/
+using json = basic_json<>;
+
+/// @brief a minimal map-like container that preserves insertion order
+/// @sa https://json.nlohmann.me/api/ordered_map/
+template<class Key, class T, class IgnoredLess, class Allocator>
+struct ordered_map;
+
+/// @brief specialization that maintains the insertion order of object keys
+/// @sa https://json.nlohmann.me/api/ordered_json/
+using ordered_json = basic_json<wpi::ordered_map>;
+
+WPI_JSON_NAMESPACE_END
+
+#endif  // INCLUDE_WPI_JSON_FWD_HPP_
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h
deleted file mode 100644
index 3796c95..0000000
--- a/wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) 2017-2018 FIRST. All Rights Reserved.          */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++
-|  |  |__   |  |  | | | |  version 3.1.2
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-#include "wpi/json.h"
-
-#include <clocale> // lconv, localeconv
-#include <cmath>  // labs, isfinite, isnan, signbit, ldexp
-#include <type_traits>
-
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-class json::serializer
-{
-    static constexpr uint8_t UTF8_ACCEPT = 0;
-    static constexpr uint8_t UTF8_REJECT = 1;
-
-  public:
-    /*!
-    @param[in] s  output stream to serialize to
-    @param[in] ichar  indentation character to use
-    @param[in] indent_init_len  initial length of indentation string buffer
-    */
-    serializer(raw_ostream& s, const char ichar, size_t indent_init_len = 512)
-        : o(s), indent_char(ichar),
-          indent_string(indent_init_len, indent_char)
-    {}
-
-    // delete because of pointer members
-    serializer(const serializer&) = delete;
-    serializer& operator=(const serializer&) = delete;
-
-    /*!
-    @brief internal implementation of the serialization function
-
-    This function is called by the public member function dump and organizes
-    the serialization internally. The indentation level is propagated as
-    additional parameter. In case of arrays and objects, the function is
-    called recursively.
-
-    - strings and object keys are escaped using `escape_string()`
-    - integer numbers are converted implicitly via `operator<<`
-    - floating-point numbers are converted to a string using `"%g"` format
-
-    @param[in] val             value to serialize
-    @param[in] pretty_print    whether the output shall be pretty-printed
-    @param[in] ensure_ascii    whether the output shall only use ASCII chars
-    @param[in] indent_step     the indent level
-    @param[in] current_indent  the current indent level (only used internally)
-    */
-    void dump(const json& val, const bool pretty_print,
-              const bool ensure_ascii,
-              const unsigned int indent_step,
-              const unsigned int current_indent = 0);
-
-    /*!
-    @brief dump escaped string
-
-    Escape a string by replacing certain special characters by a sequence of an
-    escape character (backslash) and another character and other control
-    characters by a sequence of "\u" followed by a four-digit hex
-    representation. The escaped string is written to output stream @a o.
-
-    @param[in] s  the string to escape
-    @param[in] ensure_ascii  whether to escape non-ASCII characters with
-                             "\uXXXX" sequences
-
-    Complexity: Linear in the length of string @a s.
-    */
-    void dump_escaped(std::string_view s, const bool ensure_ascii);
-
-    template <typename NumberType,
-              detail::enable_if_t<std::is_same_v<NumberType, uint64_t>, int> = 0>
-    bool is_negative_integer(NumberType x) {
-      return false;
-    }
-
-    template <typename NumberType,
-              detail::enable_if_t<std::is_same_v<NumberType, int64_t>, int> = 0>
-    bool is_negative_integer(NumberType x) {
-      return x < 0;
-    }
-
-    /*!
-    @brief dump an integer
-
-    Dump a given integer to output stream @a o. Works internally with
-    @a number_buffer.
-
-    @param[in] x  integer number (signed or unsigned) to dump
-    @tparam NumberType either @a int64_t or @a uint64_t
-    */
-    template<typename NumberType, detail::enable_if_t<
-                 std::is_same<NumberType, uint64_t>::value or
-                 std::is_same<NumberType, int64_t>::value,
-                 int> = 0>
-    void dump_integer(NumberType x)
-    {
-        // special case for "0"
-        if (x == 0)
-        {
-            o << '0';
-            return;
-        }
-
-        const bool is_negative = is_negative_integer(x);  // see issue #755
-        std::size_t i = 0;
-
-        while (x != 0)
-        {
-            // spare 1 byte for '\0'
-            assert(i < number_buffer.size() - 1);
-
-            const auto digit = std::labs(static_cast<long>(x % 10));
-            number_buffer[i++] = static_cast<char>('0' + digit);
-            x /= 10;
-        }
-
-        if (is_negative)
-        {
-            // make sure there is capacity for the '-'
-            assert(i < number_buffer.size() - 2);
-            number_buffer[i++] = '-';
-        }
-
-        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
-        o.write(number_buffer.data(), i);
-    }
-
-    /*!
-    @brief dump a floating-point number
-
-    Dump a given floating-point number to output stream @a o. Works internally
-    with @a number_buffer.
-
-    @param[in] x  floating-point number to dump
-    */
-    void dump_float(double x);
-
-    /*!
-    @brief check whether a string is UTF-8 encoded
-
-    The function checks each byte of a string whether it is UTF-8 encoded. The
-    result of the check is stored in the @a state parameter. The function must
-    be called initially with state 0 (accept). State 1 means the string must
-    be rejected, because the current byte is not allowed. If the string is
-    completely processed, but the state is non-zero, the string ended
-    prematurely; that is, the last byte indicated more bytes should have
-    followed.
-
-    @param[in,out] state  the state of the decoding
-    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
-    @param[in] byte       next byte to decode
-    @return               new state
-
-    @note The function has been edited: a std::array is used.
-
-    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
-    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
-    */
-    static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept;
-
-  private:
-    /// the output of the serializer
-    raw_ostream& o;
-
-    /// a (hopefully) large enough character buffer
-    std::array<char, 64> number_buffer{{}};
-
-    /// the indentation character
-    const char indent_char;
-    /// the indentation string
-    std::string indent_string;
-};
-
-}  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/ordered_map.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/ordered_map.h
new file mode 100644
index 0000000..14969f1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/ordered_map.h
@@ -0,0 +1,359 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <functional> // equal_to, less
+#include <initializer_list> // initializer_list
+#include <iterator> // input_iterator_tag, iterator_traits
+#include <memory> // allocator
+#include <stdexcept> // for out_of_range
+#include <type_traits> // enable_if, is_convertible
+#include <utility> // pair
+#include <vector> // vector
+
+#include <wpi/detail/macro_scope.h>
+#include <wpi/detail/meta/type_traits.h>
+
+WPI_JSON_NAMESPACE_BEGIN
+
+/// ordered_map: a minimal map-like container that preserves insertion order
+/// for use within wpi::basic_json<ordered_map>
+template <class Key, class T, class IgnoredLess = std::less<Key>,
+          class Allocator = std::allocator<std::pair<const Key, T>>>
+                  struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
+{
+    using key_type = Key;
+    using mapped_type = T;
+    using Container = std::vector<std::pair<const Key, T>, Allocator>;
+    using iterator = typename Container::iterator;
+    using const_iterator = typename Container::const_iterator;
+    using size_type = typename Container::size_type;
+    using value_type = typename Container::value_type;
+#ifdef JSON_HAS_CPP_14
+    using key_compare = std::equal_to<>;
+#else
+    using key_compare = std::equal_to<Key>;
+#endif
+
+    // Explicit constructors instead of `using Container::Container`
+    // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
+    ordered_map() noexcept(noexcept(Container())) : Container{} {}
+    explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
+    template <class It>
+    ordered_map(It first, It last, const Allocator& alloc = Allocator())
+        : Container{first, last, alloc} {}
+    ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
+        : Container{init, alloc} {}
+
+    std::pair<iterator, bool> emplace(const key_type& key, T&& t)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return {it, false};
+            }
+        }
+        Container::emplace_back(key, std::forward<T>(t));
+        return {std::prev(this->end()), true};
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    std::pair<iterator, bool> emplace(KeyType && key, T && t)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return {it, false};
+            }
+        }
+        Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t));
+        return {std::prev(this->end()), true};
+    }
+
+    T& operator[](const key_type& key)
+    {
+        return emplace(key, T{}).first->second;
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    T & operator[](KeyType && key)
+    {
+        return emplace(std::forward<KeyType>(key), T{}).first->second;
+    }
+
+    const T& operator[](const key_type& key) const
+    {
+        return at(key);
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    const T & operator[](KeyType && key) const
+    {
+        return at(std::forward<KeyType>(key));
+    }
+
+    T& at(const key_type& key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    T & at(KeyType && key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    const T& at(const key_type& key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    const T & at(KeyType && key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    size_type erase(const key_type& key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                // Since we cannot move const Keys, re-construct them in place
+                for (auto next = it; ++next != this->end(); ++it)
+                {
+                    it->~value_type(); // Destroy but keep allocation
+                    new (&*it) value_type{std::move(*next)};
+                }
+                Container::pop_back();
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    size_type erase(KeyType && key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                // Since we cannot move const Keys, re-construct them in place
+                for (auto next = it; ++next != this->end(); ++it)
+                {
+                    it->~value_type(); // Destroy but keep allocation
+                    new (&*it) value_type{std::move(*next)};
+                }
+                Container::pop_back();
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    iterator erase(iterator pos)
+    {
+        return erase(pos, std::next(pos));
+    }
+
+    iterator erase(iterator first, iterator last)
+    {
+        if (first == last)
+        {
+            return first;
+        }
+
+        const auto elements_affected = std::distance(first, last);
+        const auto offset = std::distance(Container::begin(), first);
+
+        // This is the start situation. We need to delete elements_affected
+        // elements (3 in this example: e, f, g), and need to return an
+        // iterator past the last deleted element (h in this example).
+        // Note that offset is the distance from the start of the vector
+        // to first. We will need this later.
+
+        // [ a, b, c, d, e, f, g, h, i, j ]
+        //               ^        ^
+        //             first    last
+
+        // Since we cannot move const Keys, we re-construct them in place.
+        // We start at first and re-construct (viz. copy) the elements from
+        // the back of the vector. Example for first iteration:
+
+        //               ,--------.
+        //               v        |   destroy e and re-construct with h
+        // [ a, b, c, d, e, f, g, h, i, j ]
+        //               ^        ^
+        //               it       it + elements_affected
+
+        for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
+        {
+            it->~value_type(); // destroy but keep allocation
+            new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
+        }
+
+        // [ a, b, c, d, h, i, j, h, i, j ]
+        //               ^        ^
+        //             first    last
+
+        // remove the unneeded elements at the end of the vector
+        Container::resize(this->size() - static_cast<size_type>(elements_affected));
+
+        // [ a, b, c, d, h, i, j ]
+        //               ^        ^
+        //             first    last
+
+        // first is now pointing past the last deleted element, but we cannot
+        // use this iterator, because it may have been invalidated by the
+        // resize call. Instead, we can return begin() + offset.
+        return Container::begin() + offset;
+    }
+
+    size_type count(const key_type& key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    size_type count(KeyType && key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    iterator find(const key_type& key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it;
+            }
+        }
+        return Container::end();
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    iterator find(KeyType && key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it;
+            }
+        }
+        return Container::end();
+    }
+
+    const_iterator find(const key_type& key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it;
+            }
+        }
+        return Container::end();
+    }
+
+    std::pair<iterator, bool> insert( value_type&& value )
+    {
+        return emplace(value.first, std::move(value.second));
+    }
+
+    std::pair<iterator, bool> insert( const value_type& value )
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, value.first))
+            {
+                return {it, false};
+            }
+        }
+        Container::push_back(value);
+        return {--this->end(), true};
+    }
+
+    template<typename InputIt>
+    using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
+            std::input_iterator_tag>::value>::type;
+
+    template<typename InputIt, typename = require_input_iter<InputIt>>
+    void insert(InputIt first, InputIt last)
+    {
+        for (auto it = first; it != last; ++it)
+        {
+            insert(*it);
+        }
+    }
+
+private:
+    JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
+};
+
+WPI_JSON_NAMESPACE_END
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/thirdparty/hedley/hedley.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/thirdparty/hedley/hedley.h
new file mode 100644
index 0000000..f1377f1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/thirdparty/hedley/hedley.h
@@ -0,0 +1,2045 @@
+#pragma once
+
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com>
+// SPDX-License-Identifier: MIT
+
+/* Hedley - https://nemequ.github.io/hedley
+ * Created by Evan Nemerson <evan@nemerson.com>
+ */
+
+#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)
+#if defined(JSON_HEDLEY_VERSION)
+    #undef JSON_HEDLEY_VERSION
+#endif
+#define JSON_HEDLEY_VERSION 15
+
+#if defined(JSON_HEDLEY_STRINGIFY_EX)
+    #undef JSON_HEDLEY_STRINGIFY_EX
+#endif
+#define JSON_HEDLEY_STRINGIFY_EX(x) #x
+
+#if defined(JSON_HEDLEY_STRINGIFY)
+    #undef JSON_HEDLEY_STRINGIFY
+#endif
+#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)
+
+#if defined(JSON_HEDLEY_CONCAT_EX)
+    #undef JSON_HEDLEY_CONCAT_EX
+#endif
+#define JSON_HEDLEY_CONCAT_EX(a,b) a##b
+
+#if defined(JSON_HEDLEY_CONCAT)
+    #undef JSON_HEDLEY_CONCAT
+#endif
+#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)
+
+#if defined(JSON_HEDLEY_CONCAT3_EX)
+    #undef JSON_HEDLEY_CONCAT3_EX
+#endif
+#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c
+
+#if defined(JSON_HEDLEY_CONCAT3)
+    #undef JSON_HEDLEY_CONCAT3
+#endif
+#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)
+
+#if defined(JSON_HEDLEY_VERSION_ENCODE)
+    #undef JSON_HEDLEY_VERSION_ENCODE
+#endif
+#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)
+    #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)
+    #undef JSON_HEDLEY_VERSION_DECODE_MINOR
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)
+    #undef JSON_HEDLEY_VERSION_DECODE_REVISION
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)
+
+#if defined(JSON_HEDLEY_GNUC_VERSION)
+    #undef JSON_HEDLEY_GNUC_VERSION
+#endif
+#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
+    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#elif defined(__GNUC__)
+    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)
+    #undef JSON_HEDLEY_GNUC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_GNUC_VERSION)
+    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_MSVC_VERSION)
+    #undef JSON_HEDLEY_MSVC_VERSION
+#endif
+#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
+#elif defined(_MSC_FULL_VER) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
+#elif defined(_MSC_VER) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
+    #undef JSON_HEDLEY_MSVC_VERSION_CHECK
+#endif
+#if !defined(JSON_HEDLEY_MSVC_VERSION)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
+#else
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_VERSION)
+    #undef JSON_HEDLEY_INTEL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)
+    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
+#elif defined(__INTEL_COMPILER) && !defined(__ICL)
+    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_VERSION)
+    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)
+    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_PGI_VERSION)
+    #undef JSON_HEDLEY_PGI_VERSION
+#endif
+#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
+    #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
+#endif
+
+#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)
+    #undef JSON_HEDLEY_PGI_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_PGI_VERSION)
+    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_SUNPRO_VERSION)
+    #undef JSON_HEDLEY_SUNPRO_VERSION
+#endif
+#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)
+#elif defined(__SUNPRO_C)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
+#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)
+#elif defined(__SUNPRO_CC)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
+#endif
+
+#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)
+    #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_SUNPRO_VERSION)
+    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
+    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
+#endif
+#if defined(__EMSCRIPTEN__)
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
+#endif
+
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)
+    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_ARM_VERSION)
+    #undef JSON_HEDLEY_ARM_VERSION
+#endif
+#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
+#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
+#endif
+
+#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)
+    #undef JSON_HEDLEY_ARM_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_ARM_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_IBM_VERSION)
+    #undef JSON_HEDLEY_IBM_VERSION
+#endif
+#if defined(__ibmxl__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
+#elif defined(__xlC__) && defined(__xlC_ver__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
+#elif defined(__xlC__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
+#endif
+
+#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)
+    #undef JSON_HEDLEY_IBM_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_IBM_VERSION)
+    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_VERSION)
+    #undef JSON_HEDLEY_TI_VERSION
+#endif
+#if \
+    defined(__TI_COMPILER_VERSION__) && \
+    ( \
+      defined(__TMS470__) || defined(__TI_ARM__) || \
+      defined(__MSP430__) || \
+      defined(__TMS320C2000__) \
+    )
+#if (__TI_COMPILER_VERSION__ >= 16000000)
+    #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+#endif
+
+#if defined(JSON_HEDLEY_TI_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_VERSION)
+    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
+    #undef JSON_HEDLEY_TI_CL2000_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)
+    #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
+    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL430_VERSION)
+    #undef JSON_HEDLEY_TI_CL430_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
+    #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL430_VERSION)
+    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
+    #undef JSON_HEDLEY_TI_ARMCL_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))
+    #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
+    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
+    #undef JSON_HEDLEY_TI_CL6X_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)
+    #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
+    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
+    #undef JSON_HEDLEY_TI_CL7X_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)
+    #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
+    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
+    #undef JSON_HEDLEY_TI_CLPRU_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)
+    #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
+    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_CRAY_VERSION)
+    #undef JSON_HEDLEY_CRAY_VERSION
+#endif
+#if defined(_CRAYC)
+    #if defined(_RELEASE_PATCHLEVEL)
+        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
+    #else
+        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
+    #endif
+#endif
+
+#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)
+    #undef JSON_HEDLEY_CRAY_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_CRAY_VERSION)
+    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_IAR_VERSION)
+    #undef JSON_HEDLEY_IAR_VERSION
+#endif
+#if defined(__IAR_SYSTEMS_ICC__)
+    #if __VER__ > 1000
+        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
+    #else
+        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)
+    #endif
+#endif
+
+#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)
+    #undef JSON_HEDLEY_IAR_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_IAR_VERSION)
+    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TINYC_VERSION)
+    #undef JSON_HEDLEY_TINYC_VERSION
+#endif
+#if defined(__TINYC__)
+    #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
+#endif
+
+#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)
+    #undef JSON_HEDLEY_TINYC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TINYC_VERSION)
+    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_DMC_VERSION)
+    #undef JSON_HEDLEY_DMC_VERSION
+#endif
+#if defined(__DMC__)
+    #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
+#endif
+
+#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)
+    #undef JSON_HEDLEY_DMC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_DMC_VERSION)
+    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_COMPCERT_VERSION)
+    #undef JSON_HEDLEY_COMPCERT_VERSION
+#endif
+#if defined(__COMPCERT_VERSION__)
+    #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
+#endif
+
+#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)
+    #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_COMPCERT_VERSION)
+    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_PELLES_VERSION)
+    #undef JSON_HEDLEY_PELLES_VERSION
+#endif
+#if defined(__POCC__)
+    #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)
+    #undef JSON_HEDLEY_PELLES_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_PELLES_VERSION)
+    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #undef JSON_HEDLEY_MCST_LCC_VERSION
+#endif
+#if defined(__LCC__) && defined(__LCC_MINOR__)
+    #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)
+#endif
+
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)
+    #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_VERSION)
+    #undef JSON_HEDLEY_GCC_VERSION
+#endif
+#if \
+    defined(JSON_HEDLEY_GNUC_VERSION) && \
+    !defined(__clang__) && \
+    !defined(JSON_HEDLEY_INTEL_VERSION) && \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_ARM_VERSION) && \
+    !defined(JSON_HEDLEY_CRAY_VERSION) && \
+    !defined(JSON_HEDLEY_TI_VERSION) && \
+    !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL430_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \
+    !defined(__COMPCERT__) && \
+    !defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION
+#endif
+
+#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)
+    #undef JSON_HEDLEY_GCC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_GCC_VERSION)
+    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_ATTRIBUTE
+#endif
+#if \
+  defined(__has_attribute) && \
+  ( \
+    (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \
+  )
+#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
+#else
+#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
+#endif
+#if defined(__has_attribute)
+    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
+#endif
+#if defined(__has_attribute)
+    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
+#endif
+#if \
+    defined(__has_cpp_attribute) && \
+    defined(__cplusplus) && \
+    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)
+    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
+#endif
+#if !defined(__cplusplus) || !defined(__has_cpp_attribute)
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
+#elif \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_IAR_VERSION) && \
+    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \
+    (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)
+#else
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
+#endif
+#if defined(__has_cpp_attribute) && defined(__cplusplus)
+    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
+#endif
+#if defined(__has_cpp_attribute) && defined(__cplusplus)
+    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_BUILTIN)
+    #undef JSON_HEDLEY_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)
+    #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)
+    #undef JSON_HEDLEY_GCC_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_FEATURE)
+    #undef JSON_HEDLEY_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_HAS_FEATURE(feature) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)
+    #undef JSON_HEDLEY_GNUC_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)
+    #undef JSON_HEDLEY_GCC_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_EXTENSION)
+    #undef JSON_HEDLEY_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)
+    #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)
+    #undef JSON_HEDLEY_GCC_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_WARNING)
+    #undef JSON_HEDLEY_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_HAS_WARNING(warning) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)
+    #undef JSON_HEDLEY_GNUC_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_WARNING)
+    #undef JSON_HEDLEY_GCC_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
+    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
+    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
+#else
+    #define JSON_HEDLEY_PRAGMA(value)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
+    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
+#endif
+#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
+    #undef JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
+    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
+#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH
+    #define JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+
+/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
+   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
+#endif
+#if defined(__cplusplus)
+#  if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat")
+#    if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions")
+#      if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions")
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      else
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      endif
+#    else
+#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#    endif
+#  endif
+#endif
+#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x
+#endif
+
+#if defined(JSON_HEDLEY_CONST_CAST)
+    #undef JSON_HEDLEY_CONST_CAST
+#endif
+#if defined(__cplusplus)
+#  define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))
+#elif \
+  JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \
+        JSON_HEDLEY_DIAGNOSTIC_PUSH \
+        JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \
+        ((T) (expr)); \
+        JSON_HEDLEY_DIAGNOSTIC_POP \
+    }))
+#else
+#  define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_REINTERPRET_CAST)
+    #undef JSON_HEDLEY_REINTERPRET_CAST
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))
+#else
+    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_STATIC_CAST)
+    #undef JSON_HEDLEY_STATIC_CAST
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))
+#else
+    #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_CPP_CAST)
+    #undef JSON_HEDLEY_CPP_CAST
+#endif
+#if defined(__cplusplus)
+#  if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast")
+#    define JSON_HEDLEY_CPP_CAST(T, expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
+    ((T) (expr)) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)
+#    define JSON_HEDLEY_CPP_CAST(T, expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("diag_suppress=Pe137") \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  else
+#    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))
+#  endif
+#else
+#  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445")
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098")
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097")
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunused-function")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#endif
+
+#if defined(JSON_HEDLEY_DEPRECATED)
+    #undef JSON_HEDLEY_DEPRECATED
+#endif
+#if defined(JSON_HEDLEY_DEPRECATED_FOR)
+    #undef JSON_HEDLEY_DEPRECATED_FOR
+#endif
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
+#elif \
+    (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
+#elif defined(__cplusplus) && (__cplusplus >= 201402L)
+    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated")
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
+#else
+    #define JSON_HEDLEY_DEPRECATED(since)
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
+#endif
+
+#if defined(JSON_HEDLEY_UNAVAILABLE)
+    #undef JSON_HEDLEY_UNAVAILABLE
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
+#else
+    #define JSON_HEDLEY_UNAVAILABLE(available_since)
+#endif
+
+#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)
+    #undef JSON_HEDLEY_WARN_UNUSED_RESULT
+#endif
+#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)
+    #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
+#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+#elif defined(_Check_return_) /* SAL */
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
+#else
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)
+#endif
+
+#if defined(JSON_HEDLEY_SENTINEL)
+    #undef JSON_HEDLEY_SENTINEL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))
+#else
+    #define JSON_HEDLEY_SENTINEL(position)
+#endif
+
+#if defined(JSON_HEDLEY_NO_RETURN)
+    #undef JSON_HEDLEY_NO_RETURN
+#endif
+#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_NO_RETURN __noreturn
+#elif \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+    #define JSON_HEDLEY_NO_RETURN _Noreturn
+#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+    #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
+#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
+    #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
+    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
+#else
+    #define JSON_HEDLEY_NO_RETURN
+#endif
+
+#if defined(JSON_HEDLEY_NO_ESCAPE)
+    #undef JSON_HEDLEY_NO_ESCAPE
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)
+    #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))
+#else
+    #define JSON_HEDLEY_NO_ESCAPE
+#endif
+
+#if defined(JSON_HEDLEY_UNREACHABLE)
+    #undef JSON_HEDLEY_UNREACHABLE
+#endif
+#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)
+    #undef JSON_HEDLEY_UNREACHABLE_RETURN
+#endif
+#if defined(JSON_HEDLEY_ASSUME)
+    #undef JSON_HEDLEY_ASSUME
+#endif
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
+#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
+    #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
+#elif \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
+    #if defined(__cplusplus)
+        #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)
+    #else
+        #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)
+    #endif
+#endif
+#if \
+    (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()
+#elif defined(JSON_HEDLEY_ASSUME)
+    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
+#endif
+#if !defined(JSON_HEDLEY_ASSUME)
+    #if defined(JSON_HEDLEY_UNREACHABLE)
+        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))
+    #else
+        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)
+    #endif
+#endif
+#if defined(JSON_HEDLEY_UNREACHABLE)
+    #if  \
+        JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
+        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))
+    #else
+        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()
+    #endif
+#else
+    #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)
+#endif
+#if !defined(JSON_HEDLEY_UNREACHABLE)
+    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
+#endif
+
+JSON_HEDLEY_DIAGNOSTIC_PUSH
+#if JSON_HEDLEY_HAS_WARNING("-Wpedantic")
+    #pragma clang diagnostic ignored "-Wpedantic"
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus)
+    #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0)
+    #if defined(__clang__)
+        #pragma clang diagnostic ignored "-Wvariadic-macros"
+    #elif defined(JSON_HEDLEY_GCC_VERSION)
+        #pragma GCC diagnostic ignored "-Wvariadic-macros"
+    #endif
+#endif
+#if defined(JSON_HEDLEY_NON_NULL)
+    #undef JSON_HEDLEY_NON_NULL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
+    #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+    #define JSON_HEDLEY_NON_NULL(...)
+#endif
+JSON_HEDLEY_DIAGNOSTIC_POP
+
+#if defined(JSON_HEDLEY_PRINTF_FORMAT)
+    #undef JSON_HEDLEY_PRINTF_FORMAT
+#endif
+#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
+#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(format) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
+#else
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
+#endif
+
+#if defined(JSON_HEDLEY_CONSTEXPR)
+    #undef JSON_HEDLEY_CONSTEXPR
+#endif
+#if defined(__cplusplus)
+    #if __cplusplus >= 201103L
+        #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)
+    #endif
+#endif
+#if !defined(JSON_HEDLEY_CONSTEXPR)
+    #define JSON_HEDLEY_CONSTEXPR
+#endif
+
+#if defined(JSON_HEDLEY_PREDICT)
+    #undef JSON_HEDLEY_PREDICT
+#endif
+#if defined(JSON_HEDLEY_LIKELY)
+    #undef JSON_HEDLEY_LIKELY
+#endif
+#if defined(JSON_HEDLEY_UNLIKELY)
+    #undef JSON_HEDLEY_UNLIKELY
+#endif
+#if defined(JSON_HEDLEY_UNPREDICTABLE)
+    #undef JSON_HEDLEY_UNPREDICTABLE
+#endif
+#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)
+    #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
+#endif
+#if \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability)  __builtin_expect_with_probability(!!(expr),    0   , (probability))
+#  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )
+#  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )
+#elif \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \
+  JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PREDICT(expr, expected, probability) \
+    (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \
+    (__extension__ ({ \
+        double hedley_probability_ = (probability); \
+        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \
+    }))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \
+    (__extension__ ({ \
+        double hedley_probability_ = (probability); \
+        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \
+    }))
+#  define JSON_HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)
+#  define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
+#else
+#  define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))
+#  define JSON_HEDLEY_LIKELY(expr) (!!(expr))
+#  define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))
+#endif
+#if !defined(JSON_HEDLEY_UNPREDICTABLE)
+    #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)
+#endif
+
+#if defined(JSON_HEDLEY_MALLOC)
+    #undef JSON_HEDLEY_MALLOC
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_MALLOC __declspec(restrict)
+#else
+    #define JSON_HEDLEY_MALLOC
+#endif
+
+#if defined(JSON_HEDLEY_PURE)
+    #undef JSON_HEDLEY_PURE
+#endif
+#if \
+  JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PURE __attribute__((__pure__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+#  define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data")
+#elif defined(__cplusplus) && \
+    ( \
+      JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \
+      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \
+    )
+#  define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;")
+#else
+#  define JSON_HEDLEY_PURE
+#endif
+
+#if defined(JSON_HEDLEY_CONST)
+    #undef JSON_HEDLEY_CONST
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(const) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_CONST __attribute__((__const__))
+#elif \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_CONST _Pragma("no_side_effect")
+#else
+    #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE
+#endif
+
+#if defined(JSON_HEDLEY_RESTRICT)
+    #undef JSON_HEDLEY_RESTRICT
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
+    #define JSON_HEDLEY_RESTRICT restrict
+#elif \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_RESTRICT __restrict
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
+    #define JSON_HEDLEY_RESTRICT _Restrict
+#else
+    #define JSON_HEDLEY_RESTRICT
+#endif
+
+#if defined(JSON_HEDLEY_INLINE)
+    #undef JSON_HEDLEY_INLINE
+#endif
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    (defined(__cplusplus) && (__cplusplus >= 199711L))
+    #define JSON_HEDLEY_INLINE inline
+#elif \
+    defined(JSON_HEDLEY_GCC_VERSION) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)
+    #define JSON_HEDLEY_INLINE __inline__
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_INLINE __inline
+#else
+    #define JSON_HEDLEY_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_ALWAYS_INLINE)
+    #undef JSON_HEDLEY_ALWAYS_INLINE
+#endif
+#if \
+  JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+  JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE __forceinline
+#elif defined(__cplusplus) && \
+    ( \
+      JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+      JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+      JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+      JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \
+    )
+#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced")
+#else
+#  define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_NEVER_INLINE)
+    #undef JSON_HEDLEY_NEVER_INLINE
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never")
+#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
+    #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
+    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
+#else
+    #define JSON_HEDLEY_NEVER_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_PRIVATE)
+    #undef JSON_HEDLEY_PRIVATE
+#endif
+#if defined(JSON_HEDLEY_PUBLIC)
+    #undef JSON_HEDLEY_PUBLIC
+#endif
+#if defined(JSON_HEDLEY_IMPORT)
+    #undef JSON_HEDLEY_IMPORT
+#endif
+#if defined(_WIN32) || defined(__CYGWIN__)
+#  define JSON_HEDLEY_PRIVATE
+#  define JSON_HEDLEY_PUBLIC   __declspec(dllexport)
+#  define JSON_HEDLEY_IMPORT   __declspec(dllimport)
+#else
+#  if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+    ( \
+      defined(__TI_EABI__) && \
+      ( \
+        (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \
+      ) \
+    ) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#    define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden")))
+#    define JSON_HEDLEY_PUBLIC  __attribute__((__visibility__("default")))
+#  else
+#    define JSON_HEDLEY_PRIVATE
+#    define JSON_HEDLEY_PUBLIC
+#  endif
+#  define JSON_HEDLEY_IMPORT    extern
+#endif
+
+#if defined(JSON_HEDLEY_NO_THROW)
+    #undef JSON_HEDLEY_NO_THROW
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
+    #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
+#else
+    #define JSON_HEDLEY_NO_THROW
+#endif
+
+#if defined(JSON_HEDLEY_FALL_THROUGH)
+    #undef JSON_HEDLEY_FALL_THROUGH
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)
+    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)
+    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])
+#elif defined(__fallthrough) /* SAL */
+    #define JSON_HEDLEY_FALL_THROUGH __fallthrough
+#else
+    #define JSON_HEDLEY_FALL_THROUGH
+#endif
+
+#if defined(JSON_HEDLEY_RETURNS_NON_NULL)
+    #undef JSON_HEDLEY_RETURNS_NON_NULL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
+#elif defined(_Ret_notnull_) /* SAL */
+    #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_
+#else
+    #define JSON_HEDLEY_RETURNS_NON_NULL
+#endif
+
+#if defined(JSON_HEDLEY_ARRAY_PARAM)
+    #undef JSON_HEDLEY_ARRAY_PARAM
+#endif
+#if \
+    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+    !defined(__STDC_NO_VLA__) && \
+    !defined(__cplusplus) && \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_TINYC_VERSION)
+    #define JSON_HEDLEY_ARRAY_PARAM(name) (name)
+#else
+    #define JSON_HEDLEY_ARRAY_PARAM(name)
+#endif
+
+#if defined(JSON_HEDLEY_IS_CONSTANT)
+    #undef JSON_HEDLEY_IS_CONSTANT
+#endif
+#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)
+    #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
+#endif
+/* JSON_HEDLEY_IS_CONSTEXPR_ is for
+   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
+#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
+    #undef JSON_HEDLEY_IS_CONSTEXPR_
+#endif
+#if \
+    JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)
+#endif
+#if !defined(__cplusplus)
+#  if \
+       JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \
+       JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+       JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+       JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+       JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
+       JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)
+#if defined(__INTPTR_TYPE__)
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
+#else
+    #include <stdint.h>
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
+#endif
+#  elif \
+       ( \
+          defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+          !defined(JSON_HEDLEY_SUNPRO_VERSION) && \
+          !defined(JSON_HEDLEY_PGI_VERSION) && \
+          !defined(JSON_HEDLEY_IAR_VERSION)) || \
+       (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
+       JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
+       JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \
+       JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
+       JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)
+#if defined(__INTPTR_TYPE__)
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
+#else
+    #include <stdint.h>
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
+#endif
+#  elif \
+       defined(JSON_HEDLEY_GCC_VERSION) || \
+       defined(JSON_HEDLEY_INTEL_VERSION) || \
+       defined(JSON_HEDLEY_TINYC_VERSION) || \
+       defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \
+       JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \
+       defined(JSON_HEDLEY_TI_CL2000_VERSION) || \
+       defined(JSON_HEDLEY_TI_CL6X_VERSION) || \
+       defined(JSON_HEDLEY_TI_CL7X_VERSION) || \
+       defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \
+       defined(__clang__)
+#    define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \
+        sizeof(void) != \
+        sizeof(*( \
+                  1 ? \
+                  ((void*) ((expr) * 0L) ) : \
+((struct { char v[sizeof(void) * 2]; } *) 1) \
+                ) \
+              ) \
+                                            )
+#  endif
+#endif
+#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
+    #if !defined(JSON_HEDLEY_IS_CONSTANT)
+        #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)
+    #endif
+    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))
+#else
+    #if !defined(JSON_HEDLEY_IS_CONSTANT)
+        #define JSON_HEDLEY_IS_CONSTANT(expr) (0)
+    #endif
+    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)
+#endif
+
+#if defined(JSON_HEDLEY_BEGIN_C_DECLS)
+    #undef JSON_HEDLEY_BEGIN_C_DECLS
+#endif
+#if defined(JSON_HEDLEY_END_C_DECLS)
+    #undef JSON_HEDLEY_END_C_DECLS
+#endif
+#if defined(JSON_HEDLEY_C_DECL)
+    #undef JSON_HEDLEY_C_DECL
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" {
+    #define JSON_HEDLEY_END_C_DECLS }
+    #define JSON_HEDLEY_C_DECL extern "C"
+#else
+    #define JSON_HEDLEY_BEGIN_C_DECLS
+    #define JSON_HEDLEY_END_C_DECLS
+    #define JSON_HEDLEY_C_DECL
+#endif
+
+#if defined(JSON_HEDLEY_STATIC_ASSERT)
+    #undef JSON_HEDLEY_STATIC_ASSERT
+#endif
+#if \
+  !defined(__cplusplus) && ( \
+      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
+      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
+      JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
+      JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+      defined(_Static_assert) \
+    )
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
+#elif \
+  (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
+#else
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message)
+#endif
+
+#if defined(JSON_HEDLEY_NULL)
+    #undef JSON_HEDLEY_NULL
+#endif
+#if defined(__cplusplus)
+    #if __cplusplus >= 201103L
+        #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)
+    #elif defined(NULL)
+        #define JSON_HEDLEY_NULL NULL
+    #else
+        #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)
+    #endif
+#elif defined(NULL)
+    #define JSON_HEDLEY_NULL NULL
+#else
+    #define JSON_HEDLEY_NULL ((void*) 0)
+#endif
+
+#if defined(JSON_HEDLEY_MESSAGE)
+    #undef JSON_HEDLEY_MESSAGE
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+#  define JSON_HEDLEY_MESSAGE(msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
+    JSON_HEDLEY_PRAGMA(message msg) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#elif \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)
+#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#else
+#  define JSON_HEDLEY_MESSAGE(msg)
+#endif
+
+#if defined(JSON_HEDLEY_WARNING)
+    #undef JSON_HEDLEY_WARNING
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+#  define JSON_HEDLEY_WARNING(msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
+    JSON_HEDLEY_PRAGMA(clang warning msg) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#elif \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \
+  JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#else
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
+#endif
+
+#if defined(JSON_HEDLEY_REQUIRE)
+    #undef JSON_HEDLEY_REQUIRE
+#endif
+#if defined(JSON_HEDLEY_REQUIRE_MSG)
+    #undef JSON_HEDLEY_REQUIRE_MSG
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)
+#  if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat")
+#    define JSON_HEDLEY_REQUIRE(expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+    __attribute__((diagnose_if(!(expr), #expr, "error"))) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+    __attribute__((diagnose_if(!(expr), msg, "error"))) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  else
+#    define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error")))
+#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error")))
+#  endif
+#else
+#  define JSON_HEDLEY_REQUIRE(expr)
+#  define JSON_HEDLEY_REQUIRE_MSG(expr,msg)
+#endif
+
+#if defined(JSON_HEDLEY_FLAGS)
+    #undef JSON_HEDLEY_FLAGS
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion"))
+    #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
+#else
+    #define JSON_HEDLEY_FLAGS
+#endif
+
+#if defined(JSON_HEDLEY_FLAGS_CAST)
+    #undef JSON_HEDLEY_FLAGS_CAST
+#endif
+#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)
+#  define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \
+        JSON_HEDLEY_DIAGNOSTIC_PUSH \
+        _Pragma("warning(disable:188)") \
+        ((T) (expr)); \
+        JSON_HEDLEY_DIAGNOSTIC_POP \
+    }))
+#else
+#  define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)
+#endif
+
+#if defined(JSON_HEDLEY_EMPTY_BASES)
+    #undef JSON_HEDLEY_EMPTY_BASES
+#endif
+#if \
+    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)
+#else
+    #define JSON_HEDLEY_EMPTY_BASES
+#endif
+
+/* Remaining macros are deprecated. */
+
+#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)
+    #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
+#else
+    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)
+    #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
+#endif
+#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)
+    #undef JSON_HEDLEY_CLANG_HAS_FEATURE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)
+    #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
+#endif
+#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)
+    #undef JSON_HEDLEY_CLANG_HAS_WARNING
+#endif
+#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)
+
+#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */
diff --git a/wpiutil/src/main/native/thirdparty/json/include/wpi/thirdparty/hedley/hedley_undef.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/thirdparty/hedley/hedley_undef.h
new file mode 100644
index 0000000..d0c58ff
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/thirdparty/hedley/hedley_undef.h
@@ -0,0 +1,158 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#undef JSON_HEDLEY_ALWAYS_INLINE
+#undef JSON_HEDLEY_ARM_VERSION
+#undef JSON_HEDLEY_ARM_VERSION_CHECK
+#undef JSON_HEDLEY_ARRAY_PARAM
+#undef JSON_HEDLEY_ASSUME
+#undef JSON_HEDLEY_BEGIN_C_DECLS
+#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
+#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
+#undef JSON_HEDLEY_CLANG_HAS_FEATURE
+#undef JSON_HEDLEY_CLANG_HAS_WARNING
+#undef JSON_HEDLEY_COMPCERT_VERSION
+#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
+#undef JSON_HEDLEY_CONCAT
+#undef JSON_HEDLEY_CONCAT3
+#undef JSON_HEDLEY_CONCAT3_EX
+#undef JSON_HEDLEY_CONCAT_EX
+#undef JSON_HEDLEY_CONST
+#undef JSON_HEDLEY_CONSTEXPR
+#undef JSON_HEDLEY_CONST_CAST
+#undef JSON_HEDLEY_CPP_CAST
+#undef JSON_HEDLEY_CRAY_VERSION
+#undef JSON_HEDLEY_CRAY_VERSION_CHECK
+#undef JSON_HEDLEY_C_DECL
+#undef JSON_HEDLEY_DEPRECATED
+#undef JSON_HEDLEY_DEPRECATED_FOR
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#undef JSON_HEDLEY_DIAGNOSTIC_POP
+#undef JSON_HEDLEY_DIAGNOSTIC_PUSH
+#undef JSON_HEDLEY_DMC_VERSION
+#undef JSON_HEDLEY_DMC_VERSION_CHECK
+#undef JSON_HEDLEY_EMPTY_BASES
+#undef JSON_HEDLEY_EMSCRIPTEN_VERSION
+#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
+#undef JSON_HEDLEY_END_C_DECLS
+#undef JSON_HEDLEY_FLAGS
+#undef JSON_HEDLEY_FLAGS_CAST
+#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_GCC_HAS_BUILTIN
+#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_GCC_HAS_EXTENSION
+#undef JSON_HEDLEY_GCC_HAS_FEATURE
+#undef JSON_HEDLEY_GCC_HAS_WARNING
+#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
+#undef JSON_HEDLEY_GCC_VERSION
+#undef JSON_HEDLEY_GCC_VERSION_CHECK
+#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_GNUC_HAS_BUILTIN
+#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_GNUC_HAS_EXTENSION
+#undef JSON_HEDLEY_GNUC_HAS_FEATURE
+#undef JSON_HEDLEY_GNUC_HAS_WARNING
+#undef JSON_HEDLEY_GNUC_VERSION
+#undef JSON_HEDLEY_GNUC_VERSION_CHECK
+#undef JSON_HEDLEY_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_HAS_BUILTIN
+#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
+#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_HAS_EXTENSION
+#undef JSON_HEDLEY_HAS_FEATURE
+#undef JSON_HEDLEY_HAS_WARNING
+#undef JSON_HEDLEY_IAR_VERSION
+#undef JSON_HEDLEY_IAR_VERSION_CHECK
+#undef JSON_HEDLEY_IBM_VERSION
+#undef JSON_HEDLEY_IBM_VERSION_CHECK
+#undef JSON_HEDLEY_IMPORT
+#undef JSON_HEDLEY_INLINE
+#undef JSON_HEDLEY_INTEL_CL_VERSION
+#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
+#undef JSON_HEDLEY_INTEL_VERSION
+#undef JSON_HEDLEY_INTEL_VERSION_CHECK
+#undef JSON_HEDLEY_IS_CONSTANT
+#undef JSON_HEDLEY_IS_CONSTEXPR_
+#undef JSON_HEDLEY_LIKELY
+#undef JSON_HEDLEY_MALLOC
+#undef JSON_HEDLEY_MCST_LCC_VERSION
+#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
+#undef JSON_HEDLEY_MESSAGE
+#undef JSON_HEDLEY_MSVC_VERSION
+#undef JSON_HEDLEY_MSVC_VERSION_CHECK
+#undef JSON_HEDLEY_NEVER_INLINE
+#undef JSON_HEDLEY_NON_NULL
+#undef JSON_HEDLEY_NO_ESCAPE
+#undef JSON_HEDLEY_NO_RETURN
+#undef JSON_HEDLEY_NO_THROW
+#undef JSON_HEDLEY_NULL
+#undef JSON_HEDLEY_PELLES_VERSION
+#undef JSON_HEDLEY_PELLES_VERSION_CHECK
+#undef JSON_HEDLEY_PGI_VERSION
+#undef JSON_HEDLEY_PGI_VERSION_CHECK
+#undef JSON_HEDLEY_PREDICT
+#undef JSON_HEDLEY_PRINTF_FORMAT
+#undef JSON_HEDLEY_PRIVATE
+#undef JSON_HEDLEY_PUBLIC
+#undef JSON_HEDLEY_PURE
+#undef JSON_HEDLEY_REINTERPRET_CAST
+#undef JSON_HEDLEY_REQUIRE
+#undef JSON_HEDLEY_REQUIRE_CONSTEXPR
+#undef JSON_HEDLEY_REQUIRE_MSG
+#undef JSON_HEDLEY_RESTRICT
+#undef JSON_HEDLEY_RETURNS_NON_NULL
+#undef JSON_HEDLEY_SENTINEL
+#undef JSON_HEDLEY_STATIC_ASSERT
+#undef JSON_HEDLEY_STATIC_CAST
+#undef JSON_HEDLEY_STRINGIFY
+#undef JSON_HEDLEY_STRINGIFY_EX
+#undef JSON_HEDLEY_SUNPRO_VERSION
+#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
+#undef JSON_HEDLEY_TINYC_VERSION
+#undef JSON_HEDLEY_TINYC_VERSION_CHECK
+#undef JSON_HEDLEY_TI_ARMCL_VERSION
+#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL2000_VERSION
+#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL430_VERSION
+#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL6X_VERSION
+#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL7X_VERSION
+#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CLPRU_VERSION
+#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
+#undef JSON_HEDLEY_TI_VERSION
+#undef JSON_HEDLEY_TI_VERSION_CHECK
+#undef JSON_HEDLEY_UNAVAILABLE
+#undef JSON_HEDLEY_UNLIKELY
+#undef JSON_HEDLEY_UNPREDICTABLE
+#undef JSON_HEDLEY_UNREACHABLE
+#undef JSON_HEDLEY_UNREACHABLE_RETURN
+#undef JSON_HEDLEY_VERSION
+#undef JSON_HEDLEY_VERSION_DECODE_MAJOR
+#undef JSON_HEDLEY_VERSION_DECODE_MINOR
+#undef JSON_HEDLEY_VERSION_DECODE_REVISION
+#undef JSON_HEDLEY_VERSION_ENCODE
+#undef JSON_HEDLEY_WARNING
+#undef JSON_HEDLEY_WARN_UNUSED_RESULT
+#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
+#undef JSON_HEDLEY_FALL_THROUGH
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
index dbf41ab..d9aed15 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
@@ -6,25 +6,41 @@
  *
  *===------------------------------------------------------------------------=*/
 /*
- * Copyright 2001-2004 Unicode, Inc.
+ * Copyright © 1991-2015 Unicode, Inc. All rights reserved.
+ * Distributed under the Terms of Use in
+ * http://www.unicode.org/copyright.html.
  *
- * Disclaimer
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of the Unicode data files and any associated documentation
+ * (the "Data Files") or Unicode software and any associated documentation
+ * (the "Software") to deal in the Data Files or Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of
+ * the Data Files or Software, and to permit persons to whom the Data Files
+ * or Software are furnished to do so, provided that
+ * (a) this copyright and permission notice appear with all copies
+ * of the Data Files or Software,
+ * (b) this copyright and permission notice appear in associated
+ * documentation, and
+ * (c) there is clear notice in each modified Data File or in the Software
+ * as well as in the documentation associated with the Data File(s) or
+ * Software that the data or software has been modified.
  *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+ * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+ * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THE DATA FILES OR SOFTWARE.
  *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale,
+ * use or other dealings in these Data Files or Software without prior
+ * written authorization of the copyright holder.
  */
 
 /* ---------------------------------------------------------------------
@@ -422,6 +438,16 @@
     return isLegalUTF8(source, length);
 }
 
+/*
+ * Exported function to return the size of the first utf-8 code unit sequence,
+ * Or 0 if the sequence is not valid;
+ */
+unsigned getUTF8SequenceSize(const UTF8 *source, const UTF8 *sourceEnd) {
+  int length = trailingBytesForUTF8[*source] + 1;
+  return (length <= sourceEnd - source && isLegalUTF8(source, length)) ? length
+                                                                       : 0;
+}
+
 /* --------------------------------------------------------------------- */
 
 static unsigned
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
index e95c04f..10267ef 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
@@ -6,11 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <span>
 #include "wpi/ConvertUTF.h"
 #include "wpi/SmallVector.h"
 #include "wpi/ErrorHandling.h"
 #include "wpi/SwapByteOrder.h"
+#include <span>
 #include <string>
 #include <string_view>
 #include <vector>
@@ -35,31 +35,31 @@
     const UTF8 *sourceStart = (const UTF8*)Source.data();
     // FIXME: Make the type of the result buffer correct instead of
     // using reinterpret_cast.
-    UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
+    UTF16 *targetStart = reinterpret_cast<UTF16 *>(ResultPtr);
     ConversionFlags flags = strictConversion;
-    result = ConvertUTF8toUTF16(
-        &sourceStart, sourceStart + Source.size(),
-        &targetStart, targetStart + Source.size(), flags);
+    result =
+        ConvertUTF8toUTF16(&sourceStart, sourceStart + Source.size(),
+                           &targetStart, targetStart + Source.size(), flags);
     if (result == conversionOK)
-      ResultPtr = reinterpret_cast<char*>(targetStart);
+      ResultPtr = reinterpret_cast<char *>(targetStart);
     else
       ErrorPtr = sourceStart;
   } else if (WideCharWidth == 4) {
-    const UTF8 *sourceStart = (const UTF8*)Source.data();
+    const UTF8 *sourceStart = (const UTF8 *)Source.data();
     // FIXME: Make the type of the result buffer correct instead of
     // using reinterpret_cast.
-    UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
+    UTF32 *targetStart = reinterpret_cast<UTF32 *>(ResultPtr);
     ConversionFlags flags = strictConversion;
-    result = ConvertUTF8toUTF32(
-        &sourceStart, sourceStart + Source.size(),
-        &targetStart, targetStart + Source.size(), flags);
+    result =
+        ConvertUTF8toUTF32(&sourceStart, sourceStart + Source.size(),
+                           &targetStart, targetStart + Source.size(), flags);
     if (result == conversionOK)
-      ResultPtr = reinterpret_cast<char*>(targetStart);
+      ResultPtr = reinterpret_cast<char *>(targetStart);
     else
       ErrorPtr = sourceStart;
   }
-  assert((result != targetExhausted)
-         && "ConvertUTF8toUTFXX exhausted target buffer");
+  assert((result != targetExhausted) &&
+         "ConvertUTF8toUTFXX exhausted target buffer");
   return result == conversionOK;
 }
 
@@ -68,20 +68,18 @@
   const UTF32 *SourceEnd = SourceStart + 1;
   UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
   UTF8 *TargetEnd = TargetStart + 4;
-  ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
-                                           &TargetStart, TargetEnd,
-                                           strictConversion);
+  ConversionResult CR = ConvertUTF32toUTF8(
+      &SourceStart, SourceEnd, &TargetStart, TargetEnd, strictConversion);
   if (CR != conversionOK)
     return false;
 
-  ResultPtr = reinterpret_cast<char*>(TargetStart);
+  ResultPtr = reinterpret_cast<char *>(TargetStart);
   return true;
 }
 
 bool hasUTF16ByteOrderMark(std::span<const char> S) {
-  return (S.size() >= 2 &&
-          ((S[0] == '\xff' && S[1] == '\xfe') ||
-           (S[0] == '\xfe' && S[1] == '\xff')));
+  return (S.size() >= 2 && ((S[0] == '\xff' && S[1] == '\xfe') ||
+                            (S[0] == '\xfe' && S[1] == '\xff')));
 }
 
 bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
@@ -105,7 +103,7 @@
   if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
     ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
     for (UTF16 &I : ByteSwapped)
-      I = wpi::ByteSwap_16(I);
+      I = wpi::byteswap<uint16_t>(I);
     Src = &ByteSwapped[0];
     SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
   }
@@ -135,11 +133,69 @@
   return true;
 }
 
-bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out)
-{
+bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out) {
   return convertUTF16ToUTF8String(
       std::span<const char>(reinterpret_cast<const char *>(Src.data()),
-      Src.size() * sizeof(UTF16)), Out);
+                           Src.size() * sizeof(UTF16)),
+      Out);
+}
+
+bool convertUTF32ToUTF8String(std::span<const char> SrcBytes, std::string &Out) {
+  assert(Out.empty());
+
+  // Error out on an uneven byte count.
+  if (SrcBytes.size() % 4)
+    return false;
+
+  // Avoid OOB by returning early on empty input.
+  if (SrcBytes.empty())
+    return true;
+
+  const UTF32 *Src = reinterpret_cast<const UTF32 *>(&*SrcBytes.begin());
+  const UTF32 *SrcEnd = reinterpret_cast<const UTF32 *>(&*SrcBytes.begin() + SrcBytes.size());
+
+  assert((uintptr_t)Src % sizeof(UTF32) == 0);
+
+  // Byteswap if necessary.
+  std::vector<UTF32> ByteSwapped;
+  if (Src[0] == UNI_UTF32_BYTE_ORDER_MARK_SWAPPED) {
+    ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
+    for (UTF32 &I : ByteSwapped)
+      I = wpi::byteswap<uint32_t>(I);
+    Src = &ByteSwapped[0];
+    SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
+  }
+
+  // Skip the BOM for conversion.
+  if (Src[0] == UNI_UTF32_BYTE_ORDER_MARK_NATIVE)
+    Src++;
+
+  // Just allocate enough space up front.  We'll shrink it later.  Allocate
+  // enough that we can fit a null terminator without reallocating.
+  Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
+  UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]);
+  UTF8 *DstEnd = Dst + Out.size();
+
+  ConversionResult CR =
+      ConvertUTF32toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
+  assert(CR != targetExhausted);
+
+  if (CR != conversionOK) {
+    Out.clear();
+    return false;
+  }
+
+  Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]);
+  Out.push_back(0);
+  Out.pop_back();
+  return true;
+}
+
+bool convertUTF32ToUTF8String(std::span<const UTF32> Src, std::string &Out) {
+  return convertUTF32ToUTF8String(
+      std::span<const char>(reinterpret_cast<const char *>(Src.data()),
+                           Src.size() * sizeof(UTF32)),
+      Out);
 }
 
 bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
index 5beeb38..72cdf09 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
@@ -237,14 +237,17 @@
 #endif
   // Read into Buffer until we hit EOF.
   do {
-    buffer.resize_for_overwrite(buffer.size() + ChunkSize);
+    size_t prevSize = buffer.size();
+    buffer.resize_for_overwrite(prevSize + ChunkSize);
 #ifdef _WIN32
-    if (!ReadFile(f, buffer.end(), ChunkSize, &readBytes, nullptr)) {
+    if (!ReadFile(f, buffer.begin() + prevSize, ChunkSize, &readBytes,
+                  nullptr)) {
       ec = mapWindowsError(GetLastError());
       return nullptr;
     }
 #else
-    readBytes = sys::RetryAfterSignal(-1, ::read, f, buffer.end(), ChunkSize);
+    readBytes = sys::RetryAfterSignal(-1, ::read, f, buffer.begin() + prevSize,
+                                      ChunkSize);
     if (readBytes == -1) {
       ec = std::error_code(errno, std::generic_category());
       return nullptr;
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
index 04f4e06..803523a 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
@@ -99,14 +99,30 @@
   // In theory 2*capacity can overflow if the capacity is 64 bit, but the
   // original capacity would never be large enough for this to be a problem.
   size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
-  return (std::min)((std::max)(NewCapacity, MinSize), MaxSize);
+  return std::clamp(NewCapacity, MinSize, MaxSize);
+}
+
+void *SmallVectorBase::replaceAllocation(void *NewElts, size_t TSize,
+                                                 size_t NewCapacity,
+                                                 size_t VSize) {
+  void *NewEltsReplace = wpi::safe_malloc(NewCapacity * TSize);
+  if (VSize)
+    memcpy(NewEltsReplace, NewElts, VSize * TSize);
+  free(NewElts);
+  return NewEltsReplace;
 }
 
 // Note: Moving this function into the header may cause performance regression.
-void *SmallVectorBase::mallocForGrow(size_t MinSize, size_t TSize,
+void *SmallVectorBase::mallocForGrow(void *FirstEl, size_t MinSize,
+                                             size_t TSize,
                                              size_t &NewCapacity) {
   NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
-  return wpi::safe_malloc(NewCapacity * TSize);
+  // Even if capacity is not 0 now, if the vector was originally created with
+  // capacity 0, it's possible for the malloc to return FirstEl.
+  void *NewElts = wpi::safe_malloc(NewCapacity * TSize);
+  if (NewElts == FirstEl)
+    NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
+  return NewElts;
 }
 
 // Note: Moving this function into the header may cause performance regression.
@@ -115,13 +131,17 @@
   size_t NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
   void *NewElts;
   if (BeginX == FirstEl) {
-    NewElts = safe_malloc(NewCapacity * TSize);
+    NewElts = wpi::safe_malloc(NewCapacity * TSize);
+    if (NewElts == FirstEl)
+      NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
 
     // Copy the elements over.  No need to run dtors on PODs.
     memcpy(NewElts, this->BeginX, size() * TSize);
   } else {
     // If this wasn't grown from the inline copy, grow the allocated space.
-    NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
+    NewElts = wpi::safe_realloc(this->BeginX, NewCapacity * TSize);
+    if (NewElts == FirstEl)
+      NewElts = replaceAllocation(NewElts, TSize, NewCapacity, size());
   }
 
   this->BeginX = NewElts;
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
index 2405f2f..de41aea 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
@@ -11,14 +11,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "wpi/StringMap.h"
-#include "wpi/DJB.h"
 #include "wpi/MathExtras.h"
+#include "wpi/ReverseIteration.h"
+#include "wpi/xxhash.h"
 
 using namespace wpi;
 
 /// Returns the number of buckets to allocate to ensure that the DenseMap can
 /// accommodate \p NumEntries without need to grow().
-static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
+static inline unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
   // Ensure that "NumEntries * 4 < NumBuckets * 3"
   if (NumEntries == 0)
     return 0;
@@ -27,6 +28,21 @@
   return NextPowerOf2(NumEntries * 4 / 3 + 1);
 }
 
+static inline StringMapEntryBase **createTable(unsigned NewNumBuckets) {
+  auto **Table = static_cast<StringMapEntryBase **>(safe_calloc(
+      NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
+
+  // Allocate one extra bucket, set it to look filled so the iterators stop at
+  // end.
+  Table[NewNumBuckets] = (StringMapEntryBase *)2;
+  return Table;
+}
+
+static inline unsigned *getHashTable(StringMapEntryBase **TheTable,
+                                     unsigned NumBuckets) {
+  return reinterpret_cast<unsigned *>(TheTable + NumBuckets + 1);
+}
+
 StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
   ItemSize = itemSize;
 
@@ -54,15 +70,10 @@
   NumItems = 0;
   NumTombstones = 0;
 
-  TheTable = static_cast<StringMapEntryBase **>(safe_calloc(
-      NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
+  TheTable = createTable(NewNumBuckets);
 
   // Set the member only if TheTable was successfully allocated
   NumBuckets = NewNumBuckets;
-
-  // Allocate one extra bucket, set it to look filled so the iterators stop at
-  // end.
-  TheTable[NumBuckets] = (StringMapEntryBase *)2;
 }
 
 /// LookupBucketFor - Look up the bucket that the specified string should end
@@ -71,14 +82,14 @@
 /// case, the FullHashValue field of the bucket will be set to the hash value
 /// of the string.
 unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
-  unsigned HTSize = NumBuckets;
-  if (HTSize == 0) { // Hash table unallocated so far?
+  // Hash table unallocated so far?
+  if (NumBuckets == 0)
     init(16);
-    HTSize = NumBuckets;
-  }
-  unsigned FullHashValue = djbHash(Name, 0);
-  unsigned BucketNo = FullHashValue & (HTSize - 1);
-  unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
+  unsigned FullHashValue = xxh3_64bits(Name);
+  if (shouldReverseIterate())
+    FullHashValue = ~FullHashValue;
+  unsigned BucketNo = FullHashValue & (NumBuckets - 1);
+  unsigned *HashTable = getHashTable(TheTable, NumBuckets);
 
   unsigned ProbeAmt = 1;
   int FirstTombstone = -1;
@@ -117,7 +128,7 @@
     }
 
     // Okay, we didn't find the item.  Probe to the next bucket.
-    BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
+    BucketNo = (BucketNo + ProbeAmt) & (NumBuckets - 1);
 
     // Use quadratic probing, it has fewer clumping artifacts than linear
     // probing and has good cache behavior in the common case.
@@ -129,12 +140,13 @@
 /// in the map, return the bucket number of the key.  Otherwise return -1.
 /// This does not modify the map.
 int StringMapImpl::FindKey(std::string_view Key) const {
-  unsigned HTSize = NumBuckets;
-  if (HTSize == 0)
+  if (NumBuckets == 0)
     return -1; // Really empty table?
-  unsigned FullHashValue = djbHash(Key, 0);
-  unsigned BucketNo = FullHashValue & (HTSize - 1);
-  unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
+  unsigned FullHashValue = xxh3_64bits(Key);
+  if (shouldReverseIterate())
+    FullHashValue = ~FullHashValue;
+  unsigned BucketNo = FullHashValue & (NumBuckets - 1);
+  unsigned *HashTable = getHashTable(TheTable, NumBuckets);
 
   unsigned ProbeAmt = 1;
   while (true) {
@@ -161,7 +173,7 @@
     }
 
     // Okay, we didn't find the item.  Probe to the next bucket.
-    BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
+    BucketNo = (BucketNo + ProbeAmt) & (NumBuckets - 1);
 
     // Use quadratic probing, it has fewer clumping artifacts than linear
     // probing and has good cache behavior in the common case.
@@ -198,8 +210,6 @@
 /// the appropriate mod-of-hashtable-size.
 unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
   unsigned NewSize;
-  unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
-
   // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
   // the buckets are empty (meaning that many are filled with tombstones),
   // grow/rehash the table.
@@ -213,36 +223,25 @@
   }
 
   unsigned NewBucketNo = BucketNo;
-  // Allocate one extra bucket which will always be non-empty.  This allows the
-  // iterators to stop at end.
-  auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
-      NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
-
-  unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
-  NewTableArray[NewSize] = (StringMapEntryBase *)2;
+  auto **NewTableArray = createTable(NewSize);
+  unsigned *NewHashArray = getHashTable(NewTableArray, NewSize);
+  unsigned *HashTable = getHashTable(TheTable, NumBuckets);
 
   // Rehash all the items into their new buckets.  Luckily :) we already have
   // the hash values available, so we don't have to rehash any strings.
   for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
     StringMapEntryBase *Bucket = TheTable[I];
     if (Bucket && Bucket != getTombstoneVal()) {
-      // Fast case, bucket available.
+      // If the bucket is not available, probe for a spot.
       unsigned FullHash = HashTable[I];
       unsigned NewBucket = FullHash & (NewSize - 1);
-      if (!NewTableArray[NewBucket]) {
-        NewTableArray[FullHash & (NewSize - 1)] = Bucket;
-        NewHashArray[FullHash & (NewSize - 1)] = FullHash;
-        if (I == BucketNo)
-          NewBucketNo = NewBucket;
-        continue;
+      if (NewTableArray[NewBucket]) {
+        unsigned ProbeSize = 1;
+        do {
+          NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
+        } while (NewTableArray[NewBucket]);
       }
 
-      // Otherwise probe for a spot.
-      unsigned ProbeSize = 1;
-      do {
-        NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
-      } while (NewTableArray[NewBucket]);
-
       // Finally found a slot.  Fill it in.
       NewTableArray[NewBucket] = Bucket;
       NewHashArray[NewBucket] = FullHash;
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
index 01200e2..735ce48 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
@@ -83,6 +83,9 @@
   return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
 }
 
+/// Determines if the program is running on Windows 11 or Windows Server 2022.
+bool RunningWindows11OrGreater();
+
 /// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
 /// RtlGetVersion or GetVersionEx under the hood depending on what is available.
 /// GetVersionEx is deprecated, but this API exposes the build number which can
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
index a2d586b..05036a8 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
@@ -89,8 +89,15 @@
 }
 
 size_t raw_ostream::preferred_buffer_size() const {
+#ifdef _WIN32
+  // On Windows BUFSIZ is only 512 which results in more calls to write. This
+  // overhead can cause significant performance degradation. Therefore use a
+  // better default.
+  return (16 * 1024);
+#else
   // BUFSIZ is intended to be a reasonable default.
   return BUFSIZ;
+#endif
 }
 
 void raw_ostream::SetBuffered() {
@@ -237,10 +244,10 @@
   // Handle short strings specially, memcpy isn't very good at very short
   // strings.
   switch (Size) {
-  case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH;
-  case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH;
-  case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH;
-  case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH;
+  case 4: OutBufCur[3] = Ptr[3]; [[fallthrough]];
+  case 3: OutBufCur[2] = Ptr[2]; [[fallthrough]];
+  case 2: OutBufCur[1] = Ptr[1]; [[fallthrough]];
+  case 1: OutBufCur[0] = Ptr[0]; [[fallthrough]];
   case 0: break;
   default:
     memcpy(OutBufCur, Ptr, Size);
@@ -256,7 +263,6 @@
   write_impl(Ptr, Size);
 }
 
-
 template <char C>
 static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
   static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
@@ -266,12 +272,11 @@
                                C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
 
   // Usually the indentation is small, handle it with a fastpath.
-  if (NumChars < array_lengthof(Chars))
+  if (NumChars < std::size(Chars))
     return OS.write(Chars, NumChars);
 
   while (NumChars) {
-    unsigned NumToWrite = std::min(NumChars,
-                                   (unsigned)array_lengthof(Chars)-1);
+    unsigned NumToWrite = std::min(NumChars, (unsigned)std::size(Chars) - 1);
     OS.write(Chars, NumToWrite);
     NumChars -= NumToWrite;
   }
@@ -512,6 +517,14 @@
           )
         continue;
 
+#ifdef _WIN32
+      // Windows equivalents of SIGPIPE/EPIPE.
+      DWORD WinLastError = GetLastError();
+      if (WinLastError == ERROR_BROKEN_PIPE ||
+          (WinLastError == ERROR_NO_DATA && errno == EINVAL)) {
+        errno = EPIPE;
+      }
+#endif
       // Otherwise it's a non-recoverable error. Note it and quit.
       error_detected(std::error_code(errno, std::generic_category()));
       break;
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/xxhash.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/xxhash.cpp
new file mode 100644
index 0000000..323e835
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/xxhash.cpp
@@ -0,0 +1,407 @@
+/*
+*  xxHash - Fast Hash algorithm
+*  Copyright (C) 2012-2021, Yann Collet
+*
+*  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+*
+*  Redistribution and use in source and binary forms, with or without
+*  modification, are permitted provided that the following conditions are
+*  met:
+*
+*  * Redistributions of source code must retain the above copyright
+*  notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*  copyright notice, this list of conditions and the following disclaimer
+*  in the documentation and/or other materials provided with the
+*  distribution.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*  You can contact the author at :
+*  - xxHash homepage: http://www.xxhash.com
+*  - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+// xxhash64 is based on commit d2df04efcbef7d7f6886d345861e5dfda4edacc1. Removed
+// everything but a simple interface for computing xxh64.
+
+// xxh3_64bits is based on commit d5891596637d21366b9b1dcf2c0007a3edb26a9e (July
+// 2023).
+
+#include "wpi/xxhash.h"
+#include "wpi/Compiler.h"
+#include "wpi/Endian.h"
+
+#include <stdlib.h>
+
+using namespace wpi;
+using namespace support;
+
+static uint64_t rotl64(uint64_t X, size_t R) {
+  return (X << R) | (X >> (64 - R));
+}
+
+constexpr uint32_t PRIME32_1 = 0x9E3779B1;
+constexpr uint32_t PRIME32_2 = 0x85EBCA77;
+constexpr uint32_t PRIME32_3 = 0xC2B2AE3D;
+
+static const uint64_t PRIME64_1 = 11400714785074694791ULL;
+static const uint64_t PRIME64_2 = 14029467366897019727ULL;
+static const uint64_t PRIME64_3 = 1609587929392839161ULL;
+static const uint64_t PRIME64_4 = 9650029242287828579ULL;
+static const uint64_t PRIME64_5 = 2870177450012600261ULL;
+
+static uint64_t round(uint64_t Acc, uint64_t Input) {
+  Acc += Input * PRIME64_2;
+  Acc = rotl64(Acc, 31);
+  Acc *= PRIME64_1;
+  return Acc;
+}
+
+static uint64_t mergeRound(uint64_t Acc, uint64_t Val) {
+  Val = round(0, Val);
+  Acc ^= Val;
+  Acc = Acc * PRIME64_1 + PRIME64_4;
+  return Acc;
+}
+
+static uint64_t XXH64_avalanche(uint64_t hash) {
+  hash ^= hash >> 33;
+  hash *= PRIME64_2;
+  hash ^= hash >> 29;
+  hash *= PRIME64_3;
+  hash ^= hash >> 32;
+  return hash;
+}
+
+uint64_t wpi::xxHash64(std::string_view Data) {
+  size_t Len = Data.size();
+  uint64_t Seed = 0;
+  const unsigned char *P = reinterpret_cast<const unsigned char*>(Data.data());
+  const unsigned char *const BEnd = P + Data.size();
+  uint64_t H64;
+
+  if (Len >= 32) {
+    const unsigned char *const Limit = BEnd - 32;
+    uint64_t V1 = Seed + PRIME64_1 + PRIME64_2;
+    uint64_t V2 = Seed + PRIME64_2;
+    uint64_t V3 = Seed + 0;
+    uint64_t V4 = Seed - PRIME64_1;
+
+    do {
+      V1 = round(V1, endian::read64le(P));
+      P += 8;
+      V2 = round(V2, endian::read64le(P));
+      P += 8;
+      V3 = round(V3, endian::read64le(P));
+      P += 8;
+      V4 = round(V4, endian::read64le(P));
+      P += 8;
+    } while (P <= Limit);
+
+    H64 = rotl64(V1, 1) + rotl64(V2, 7) + rotl64(V3, 12) + rotl64(V4, 18);
+    H64 = mergeRound(H64, V1);
+    H64 = mergeRound(H64, V2);
+    H64 = mergeRound(H64, V3);
+    H64 = mergeRound(H64, V4);
+
+  } else {
+    H64 = Seed + PRIME64_5;
+  }
+
+  H64 += (uint64_t)Len;
+
+  while (reinterpret_cast<uintptr_t>(P) + 8 <=
+         reinterpret_cast<uintptr_t>(BEnd)) {
+    uint64_t const K1 = round(0, endian::read64le(P));
+    H64 ^= K1;
+    H64 = rotl64(H64, 27) * PRIME64_1 + PRIME64_4;
+    P += 8;
+  }
+
+  if (reinterpret_cast<uintptr_t>(P) + 4 <= reinterpret_cast<uintptr_t>(BEnd)) {
+    H64 ^= (uint64_t)(endian::read32le(P)) * PRIME64_1;
+    H64 = rotl64(H64, 23) * PRIME64_2 + PRIME64_3;
+    P += 4;
+  }
+
+  while (P < BEnd) {
+    H64 ^= (*P) * PRIME64_5;
+    H64 = rotl64(H64, 11) * PRIME64_1;
+    P++;
+  }
+
+  return XXH64_avalanche(H64);
+}
+
+uint64_t wpi::xxHash64(std::span<const uint8_t> Data) {
+  return xxHash64({(const char *)Data.data(), Data.size()});
+}
+
+constexpr size_t XXH3_SECRETSIZE_MIN = 136;
+constexpr size_t XXH_SECRET_DEFAULT_SIZE = 192;
+
+/* Pseudorandom data taken directly from FARSH */
+// clang-format off
+constexpr uint8_t kSecret[XXH_SECRET_DEFAULT_SIZE] = {
+    0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
+    0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
+    0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
+    0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
+    0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
+    0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
+    0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
+    0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
+    0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
+    0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
+    0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
+    0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
+};
+// clang-format on
+
+constexpr uint64_t PRIME_MX1 = 0x165667919E3779F9;
+constexpr uint64_t PRIME_MX2 = 0x9FB21C651E98DF25;
+
+// Calculates a 64-bit to 128-bit multiply, then XOR folds it.
+static uint64_t XXH3_mul128_fold64(uint64_t lhs, uint64_t rhs) {
+#if defined(__SIZEOF_INT128__) ||                                              \
+    (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
+  __uint128_t product = (__uint128_t)lhs * (__uint128_t)rhs;
+  return uint64_t(product) ^ uint64_t(product >> 64);
+
+#else
+  /* First calculate all of the cross products. */
+  const uint64_t lo_lo = (lhs & 0xFFFFFFFF) * (rhs & 0xFFFFFFFF);
+  const uint64_t hi_lo = (lhs >> 32) * (rhs & 0xFFFFFFFF);
+  const uint64_t lo_hi = (lhs & 0xFFFFFFFF) * (rhs >> 32);
+  const uint64_t hi_hi = (lhs >> 32) * (rhs >> 32);
+
+  /* Now add the products together. These will never overflow. */
+  const uint64_t cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
+  const uint64_t upper = (hi_lo >> 32) + (cross >> 32) + hi_hi;
+  const uint64_t lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
+
+  return upper ^ lower;
+#endif
+}
+
+constexpr size_t XXH_STRIPE_LEN = 64;
+constexpr size_t XXH_SECRET_CONSUME_RATE = 8;
+constexpr size_t XXH_ACC_NB = XXH_STRIPE_LEN / sizeof(uint64_t);
+
+static uint64_t XXH3_avalanche(uint64_t hash) {
+  hash ^= hash >> 37;
+  hash *= PRIME_MX1;
+  hash ^= hash >> 32;
+  return hash;
+}
+
+static uint64_t XXH3_len_1to3_64b(const uint8_t *input, size_t len,
+                                  const uint8_t *secret, uint64_t seed) {
+  const uint8_t c1 = input[0];
+  const uint8_t c2 = input[len >> 1];
+  const uint8_t c3 = input[len - 1];
+  uint32_t combined = ((uint32_t)c1 << 16) | ((uint32_t)c2 << 24) |
+                      ((uint32_t)c3 << 0) | ((uint32_t)len << 8);
+  uint64_t bitflip =
+      (uint64_t)(endian::read32le(secret) ^ endian::read32le(secret + 4)) +
+      seed;
+  return XXH64_avalanche(uint64_t(combined) ^ bitflip);
+}
+
+static uint64_t XXH3_len_4to8_64b(const uint8_t *input, size_t len,
+                                  const uint8_t *secret, uint64_t seed) {
+  seed ^= (uint64_t)byteswap(uint32_t(seed)) << 32;
+  const uint32_t input1 = endian::read32le(input);
+  const uint32_t input2 = endian::read32le(input + len - 4);
+  uint64_t acc =
+      (endian::read64le(secret + 8) ^ endian::read64le(secret + 16)) - seed;
+  const uint64_t input64 = (uint64_t)input2 | ((uint64_t)input1 << 32);
+  acc ^= input64;
+  // XXH3_rrmxmx(acc, len)
+  acc ^= rotl64(acc, 49) ^ rotl64(acc, 24);
+  acc *= PRIME_MX2;
+  acc ^= (acc >> 35) + (uint64_t)len;
+  acc *= PRIME_MX2;
+  return acc ^ (acc >> 28);
+}
+
+static uint64_t XXH3_len_9to16_64b(const uint8_t *input, size_t len,
+                                   const uint8_t *secret, uint64_t const seed) {
+  uint64_t input_lo =
+      (endian::read64le(secret + 24) ^ endian::read64le(secret + 32)) + seed;
+  uint64_t input_hi =
+      (endian::read64le(secret + 40) ^ endian::read64le(secret + 48)) - seed;
+  input_lo ^= endian::read64le(input);
+  input_hi ^= endian::read64le(input + len - 8);
+  uint64_t acc = uint64_t(len) + byteswap(input_lo) + input_hi +
+                 XXH3_mul128_fold64(input_lo, input_hi);
+  return XXH3_avalanche(acc);
+}
+
+LLVM_ATTRIBUTE_ALWAYS_INLINE
+static uint64_t XXH3_len_0to16_64b(const uint8_t *input, size_t len,
+                                   const uint8_t *secret, uint64_t const seed) {
+  if (LLVM_LIKELY(len > 8))
+    return XXH3_len_9to16_64b(input, len, secret, seed);
+  if (LLVM_LIKELY(len >= 4))
+    return XXH3_len_4to8_64b(input, len, secret, seed);
+  if (len != 0)
+    return XXH3_len_1to3_64b(input, len, secret, seed);
+  return XXH64_avalanche(seed ^ endian::read64le(secret + 56) ^
+                         endian::read64le(secret + 64));
+}
+
+static uint64_t XXH3_mix16B(const uint8_t *input, uint8_t const *secret,
+                            uint64_t seed) {
+  uint64_t lhs = seed;
+  uint64_t rhs = 0U - seed;
+  lhs += endian::read64le(secret);
+  rhs += endian::read64le(secret + 8);
+  lhs ^= endian::read64le(input);
+  rhs ^= endian::read64le(input + 8);
+  return XXH3_mul128_fold64(lhs, rhs);
+}
+
+/* For mid range keys, XXH3 uses a Mum-hash variant. */
+LLVM_ATTRIBUTE_ALWAYS_INLINE
+static uint64_t XXH3_len_17to128_64b(const uint8_t *input, size_t len,
+                                     const uint8_t *secret,
+                                     uint64_t const seed) {
+  uint64_t acc = len * PRIME64_1, acc_end;
+  acc += XXH3_mix16B(input + 0, secret + 0, seed);
+  acc_end = XXH3_mix16B(input + len - 16, secret + 16, seed);
+  if (len > 32) {
+    acc += XXH3_mix16B(input + 16, secret + 32, seed);
+    acc_end += XXH3_mix16B(input + len - 32, secret + 48, seed);
+    if (len > 64) {
+      acc += XXH3_mix16B(input + 32, secret + 64, seed);
+      acc_end += XXH3_mix16B(input + len - 48, secret + 80, seed);
+      if (len > 96) {
+        acc += XXH3_mix16B(input + 48, secret + 96, seed);
+        acc_end += XXH3_mix16B(input + len - 64, secret + 112, seed);
+      }
+    }
+  }
+  return XXH3_avalanche(acc + acc_end);
+}
+
+constexpr size_t XXH3_MIDSIZE_MAX = 240;
+
+LLVM_ATTRIBUTE_NOINLINE
+static uint64_t XXH3_len_129to240_64b(const uint8_t *input, size_t len,
+                                      const uint8_t *secret, uint64_t seed) {
+  constexpr size_t XXH3_MIDSIZE_STARTOFFSET = 3;
+  constexpr size_t XXH3_MIDSIZE_LASTOFFSET = 17;
+  uint64_t acc = (uint64_t)len * PRIME64_1;
+  const unsigned nbRounds = len / 16;
+  for (unsigned i = 0; i < 8; ++i)
+    acc += XXH3_mix16B(input + 16 * i, secret + 16 * i, seed);
+  acc = XXH3_avalanche(acc);
+
+  for (unsigned i = 8; i < nbRounds; ++i) {
+    acc += XXH3_mix16B(input + 16 * i,
+                       secret + 16 * (i - 8) + XXH3_MIDSIZE_STARTOFFSET, seed);
+  }
+  /* last bytes */
+  acc +=
+      XXH3_mix16B(input + len - 16,
+                  secret + XXH3_SECRETSIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
+  return XXH3_avalanche(acc);
+}
+
+LLVM_ATTRIBUTE_ALWAYS_INLINE
+static void XXH3_accumulate_512_scalar(uint64_t *acc, const uint8_t *input,
+                                       const uint8_t *secret) {
+  for (size_t i = 0; i < XXH_ACC_NB; ++i) {
+    uint64_t data_val = endian::read64le(input + 8 * i);
+    uint64_t data_key = data_val ^ endian::read64le(secret + 8 * i);
+    acc[i ^ 1] += data_val;
+    acc[i] += uint32_t(data_key) * (data_key >> 32);
+  }
+}
+
+LLVM_ATTRIBUTE_ALWAYS_INLINE
+static void XXH3_accumulate_scalar(uint64_t *acc, const uint8_t *input,
+                                   const uint8_t *secret, size_t nbStripes) {
+  for (size_t n = 0; n < nbStripes; ++n)
+    XXH3_accumulate_512_scalar(acc, input + n * XXH_STRIPE_LEN,
+                               secret + n * XXH_SECRET_CONSUME_RATE);
+}
+
+static void XXH3_scrambleAcc(uint64_t *acc, const uint8_t *secret) {
+  for (size_t i = 0; i < XXH_ACC_NB; ++i) {
+    acc[i] ^= acc[i] >> 47;
+    acc[i] ^= endian::read64le(secret + 8 * i);
+    acc[i] *= PRIME32_1;
+  }
+}
+
+static uint64_t XXH3_mix2Accs(const uint64_t *acc, const uint8_t *secret) {
+  return XXH3_mul128_fold64(acc[0] ^ endian::read64le(secret),
+                            acc[1] ^ endian::read64le(secret + 8));
+}
+
+static uint64_t XXH3_mergeAccs(const uint64_t *acc, const uint8_t *key,
+                               uint64_t start) {
+  uint64_t result64 = start;
+  for (size_t i = 0; i < 4; ++i)
+    result64 += XXH3_mix2Accs(acc + 2 * i, key + 16 * i);
+  return XXH3_avalanche(result64);
+}
+
+LLVM_ATTRIBUTE_NOINLINE
+static uint64_t XXH3_hashLong_64b(const uint8_t *input, size_t len,
+                                  const uint8_t *secret, size_t secretSize) {
+  const size_t nbStripesPerBlock =
+      (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;
+  const size_t block_len = XXH_STRIPE_LEN * nbStripesPerBlock;
+  const size_t nb_blocks = (len - 1) / block_len;
+  alignas(16) uint64_t acc[XXH_ACC_NB] = {
+      PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3,
+      PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1,
+  };
+  for (size_t n = 0; n < nb_blocks; ++n) {
+    XXH3_accumulate_scalar(acc, input + n * block_len, secret,
+                           nbStripesPerBlock);
+    XXH3_scrambleAcc(acc, secret + secretSize - XXH_STRIPE_LEN);
+  }
+
+  /* last partial block */
+  const size_t nbStripes = (len - 1 - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
+  assert(nbStripes <= secretSize / XXH_SECRET_CONSUME_RATE);
+  XXH3_accumulate_scalar(acc, input + nb_blocks * block_len, secret, nbStripes);
+
+  /* last stripe */
+  constexpr size_t XXH_SECRET_LASTACC_START = 7;
+  XXH3_accumulate_512_scalar(acc, input + len - XXH_STRIPE_LEN,
+                             secret + secretSize - XXH_STRIPE_LEN -
+                                 XXH_SECRET_LASTACC_START);
+
+  /* converge into final hash */
+  constexpr size_t XXH_SECRET_MERGEACCS_START = 11;
+  return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START,
+                        (uint64_t)len * PRIME64_1);
+}
+
+uint64_t wpi::xxh3_64bits(std::span<const uint8_t> data) {
+  auto *in = data.data();
+  size_t len = data.size();
+  if (len <= 16)
+    return XXH3_len_0to16_64b(in, len, kSecret, 0);
+  if (len <= 128)
+    return XXH3_len_17to128_64b(in, len, kSecret, 0);
+  if (len <= XXH3_MIDSIZE_MAX)
+    return XXH3_len_129to240_64b(in, len, kSecret, 0);
+  return XXH3_hashLong_64b(in, len, kSecret, sizeof(kSecret));
+}
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ADL.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ADL.h
new file mode 100644
index 0000000..3be8691
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ADL.h
@@ -0,0 +1,103 @@
+//===- llvm/ADT/ADL.h - Argument dependent lookup utilities -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_ADL_H
+#define WPIUTIL_WPI_ADL_H
+
+#include <type_traits>
+#include <iterator>
+#include <utility>
+
+namespace wpi {
+
+// Only used by compiler if both template types are the same.  Useful when
+// using SFINAE to test for the existence of member functions.
+template <typename T, T> struct SameType;
+
+namespace adl_detail {
+
+using std::begin;
+
+template <typename RangeT>
+constexpr auto begin_impl(RangeT &&range)
+    -> decltype(begin(std::forward<RangeT>(range))) {
+  return begin(std::forward<RangeT>(range));
+}
+
+using std::end;
+
+template <typename RangeT>
+constexpr auto end_impl(RangeT &&range)
+    -> decltype(end(std::forward<RangeT>(range))) {
+  return end(std::forward<RangeT>(range));
+}
+
+using std::swap;
+
+template <typename T>
+constexpr void swap_impl(T &&lhs,
+                         T &&rhs) noexcept(noexcept(swap(std::declval<T>(),
+                                                         std::declval<T>()))) {
+  swap(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
+using std::size;
+
+template <typename RangeT>
+constexpr auto size_impl(RangeT &&range)
+    -> decltype(size(std::forward<RangeT>(range))) {
+  return size(std::forward<RangeT>(range));
+}
+
+} // end namespace adl_detail
+
+/// Returns the begin iterator to \p range using `std::begin` and
+/// function found through Argument-Dependent Lookup (ADL).
+template <typename RangeT>
+constexpr auto adl_begin(RangeT &&range)
+    -> decltype(adl_detail::begin_impl(std::forward<RangeT>(range))) {
+  return adl_detail::begin_impl(std::forward<RangeT>(range));
+}
+
+/// Returns the end iterator to \p range using `std::end` and
+/// functions found through Argument-Dependent Lookup (ADL).
+template <typename RangeT>
+constexpr auto adl_end(RangeT &&range)
+    -> decltype(adl_detail::end_impl(std::forward<RangeT>(range))) {
+  return adl_detail::end_impl(std::forward<RangeT>(range));
+}
+
+/// Swaps \p lhs with \p rhs using `std::swap` and functions found through
+/// Argument-Dependent Lookup (ADL).
+template <typename T>
+constexpr void adl_swap(T &&lhs, T &&rhs) noexcept(
+    noexcept(adl_detail::swap_impl(std::declval<T>(), std::declval<T>()))) {
+  adl_detail::swap_impl(std::forward<T>(lhs), std::forward<T>(rhs));
+}
+
+/// Returns the size of \p range using `std::size` and functions found through
+/// Argument-Dependent Lookup (ADL).
+template <typename RangeT>
+constexpr auto adl_size(RangeT &&range)
+    -> decltype(adl_detail::size_impl(std::forward<RangeT>(range))) {
+  return adl_detail::size_impl(std::forward<RangeT>(range));
+}
+
+namespace detail {
+
+template <typename RangeT>
+using IterOfRange = decltype(adl_begin(std::declval<RangeT &>()));
+
+template <typename RangeT>
+using ValueOfRange =
+    std::remove_reference_t<decltype(*adl_begin(std::declval<RangeT &>()))>;
+
+} // namespace detail
+} // namespace wpi
+
+#endif // WPIUTIL_WPI_ADL_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
index 29ba16f..97a2f48 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
@@ -19,6 +19,12 @@
 #ifndef WPIUTIL_WPI_ALLOCATORBASE_H
 #define WPIUTIL_WPI_ALLOCATORBASE_H
 
+#ifdef _MSC_VER
+#define LLVM_ALLOCATORHOLDER_EMPTYBASE __declspec(empty_bases)
+#else
+#define LLVM_ALLOCATORHOLDER_EMPTYBASE
+#endif // _MSC_VER
+
 #include "wpi/Compiler.h"
 #include "wpi/MemAlloc.h"
 #include <type_traits>
@@ -72,7 +78,7 @@
 
   /// Deallocate space for a sequence of objects without constructing them.
   template <typename T>
-  std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void>
+  std::enable_if_t<!std::is_same_v<std::remove_cv_t<T>, void>, void>
   Deallocate(T *Ptr, size_t Num = 1) {
     Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
   }
@@ -99,6 +105,28 @@
   void PrintStats() const {}
 };
 
+namespace detail {
+
+template <typename Alloc> class AllocatorHolder : Alloc {
+public:
+  AllocatorHolder() = default;
+  AllocatorHolder(const Alloc &A) : Alloc(A) {}
+  AllocatorHolder(Alloc &&A) : Alloc(static_cast<Alloc &&>(A)) {}
+  Alloc &getAllocator() { return *this; }
+  const Alloc &getAllocator() const { return *this; }
+};
+
+template <typename Alloc> class AllocatorHolder<Alloc &> {
+  Alloc &A;
+
+public:
+  AllocatorHolder(Alloc &A) : A(A) {}
+  Alloc &getAllocator() { return A; }
+  const Alloc &getAllocator() const { return A; }
+};
+
+} // namespace detail
+
 } // namespace wpi
 
 #endif // WPIUTIL_WPI_ALLOCATORBASE_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Casting.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Casting.h
new file mode 100644
index 0000000..c91f1b7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Casting.h
@@ -0,0 +1,807 @@
+//===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the isa<X>(), cast<X>(), dyn_cast<X>(),
+// cast_if_present<X>(), and dyn_cast_if_present<X>() templates.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_CASTING_H
+#define WPIUTIL_WPI_CASTING_H
+
+#include "wpi/Compiler.h"
+#include "wpi/type_traits.h"
+#include <cassert>
+#include <memory>
+#include <optional>
+#include <type_traits>
+
+namespace wpi {
+
+//===----------------------------------------------------------------------===//
+// simplify_type
+//===----------------------------------------------------------------------===//
+
+/// Define a template that can be specialized by smart pointers to reflect the
+/// fact that they are automatically dereferenced, and are not involved with the
+/// template selection process...  the default implementation is a noop.
+// TODO: rename this and/or replace it with other cast traits.
+template <typename From> struct simplify_type {
+  using SimpleType = From; // The real type this represents...
+
+  // An accessor to get the real value...
+  static SimpleType &getSimplifiedValue(From &Val) { return Val; }
+};
+
+template <typename From> struct simplify_type<const From> {
+  using NonConstSimpleType = typename simplify_type<From>::SimpleType;
+  using SimpleType = typename add_const_past_pointer<NonConstSimpleType>::type;
+  using RetType =
+      typename add_lvalue_reference_if_not_pointer<SimpleType>::type;
+
+  static RetType getSimplifiedValue(const From &Val) {
+    return simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val));
+  }
+};
+
+// TODO: add this namespace once everyone is switched to using the new
+//       interface.
+// namespace detail {
+
+//===----------------------------------------------------------------------===//
+// isa_impl
+//===----------------------------------------------------------------------===//
+
+// The core of the implementation of isa<X> is here; To and From should be
+// the names of classes.  This template can be specialized to customize the
+// implementation of isa<> without rewriting it from scratch.
+template <typename To, typename From, typename Enabler = void> struct isa_impl {
+  static inline bool doit(const From &Val) { return To::classof(&Val); }
+};
+
+// Always allow upcasts, and perform no dynamic check for them.
+template <typename To, typename From>
+struct isa_impl<To, From, std::enable_if_t<std::is_base_of_v<To, From>>> {
+  static inline bool doit(const From &) { return true; }
+};
+
+template <typename To, typename From> struct isa_impl_cl {
+  static inline bool doit(const From &Val) {
+    return isa_impl<To, From>::doit(Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From> {
+  static inline bool doit(const From &Val) {
+    return isa_impl<To, From>::doit(Val);
+  }
+};
+
+template <typename To, typename From>
+struct isa_impl_cl<To, const std::unique_ptr<From>> {
+  static inline bool doit(const std::unique_ptr<From> &Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl_cl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, From *> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, From *const> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From *> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From>
+struct isa_impl_cl<To, const From *const> {
+  static inline bool doit(const From *Val) {
+    assert(Val && "isa<> used on a null pointer");
+    return isa_impl<To, From>::doit(*Val);
+  }
+};
+
+template <typename To, typename From, typename SimpleFrom>
+struct isa_impl_wrap {
+  // When From != SimplifiedType, we can simplify the type some more by using
+  // the simplify_type template.
+  static bool doit(const From &Val) {
+    return isa_impl_wrap<To, SimpleFrom,
+                         typename simplify_type<SimpleFrom>::SimpleType>::
+        doit(simplify_type<const From>::getSimplifiedValue(Val));
+  }
+};
+
+template <typename To, typename FromTy>
+struct isa_impl_wrap<To, FromTy, FromTy> {
+  // When From == SimpleType, we are as simple as we are going to get.
+  static bool doit(const FromTy &Val) {
+    return isa_impl_cl<To, FromTy>::doit(Val);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// cast_retty + cast_retty_impl
+//===----------------------------------------------------------------------===//
+
+template <class To, class From> struct cast_retty;
+
+// Calculate what type the 'cast' function should return, based on a requested
+// type of To and a source type of From.
+template <class To, class From> struct cast_retty_impl {
+  using ret_type = To &; // Normal case, return Ty&
+};
+template <class To, class From> struct cast_retty_impl<To, const From> {
+  using ret_type = const To &; // Normal case, return Ty&
+};
+
+template <class To, class From> struct cast_retty_impl<To, From *> {
+  using ret_type = To *; // Pointer arg case, return Ty*
+};
+
+template <class To, class From> struct cast_retty_impl<To, const From *> {
+  using ret_type = const To *; // Constant pointer arg case, return const Ty*
+};
+
+template <class To, class From> struct cast_retty_impl<To, const From *const> {
+  using ret_type = const To *; // Constant pointer arg case, return const Ty*
+};
+
+template <class To, class From>
+struct cast_retty_impl<To, std::unique_ptr<From>> {
+private:
+  using PointerType = typename cast_retty_impl<To, From *>::ret_type;
+  using ResultType = std::remove_pointer_t<PointerType>;
+
+public:
+  using ret_type = std::unique_ptr<ResultType>;
+};
+
+template <class To, class From, class SimpleFrom> struct cast_retty_wrap {
+  // When the simplified type and the from type are not the same, use the type
+  // simplifier to reduce the type, then reuse cast_retty_impl to get the
+  // resultant type.
+  using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
+};
+
+template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {
+  // When the simplified type is equal to the from type, use it directly.
+  using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;
+};
+
+template <class To, class From> struct cast_retty {
+  using ret_type = typename cast_retty_wrap<
+      To, From, typename simplify_type<From>::SimpleType>::ret_type;
+};
+
+//===----------------------------------------------------------------------===//
+// cast_convert_val
+//===----------------------------------------------------------------------===//
+
+// Ensure the non-simple values are converted using the simplify_type template
+// that may be specialized by smart pointers...
+//
+template <class To, class From, class SimpleFrom> struct cast_convert_val {
+  // This is not a simple type, use the template to simplify it...
+  static typename cast_retty<To, From>::ret_type doit(const From &Val) {
+    return cast_convert_val<To, SimpleFrom,
+                            typename simplify_type<SimpleFrom>::SimpleType>::
+        doit(simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val)));
+  }
+};
+
+template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {
+  // If it's a reference, switch to a pointer to do the cast and then deref it.
+  static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) {
+    return *(std::remove_reference_t<typename cast_retty<To, FromTy>::ret_type>
+                 *)&const_cast<FromTy &>(Val);
+  }
+};
+
+template <class To, class FromTy>
+struct cast_convert_val<To, FromTy *, FromTy *> {
+  // If it's a pointer, we can use c-style casting directly.
+  static typename cast_retty<To, FromTy *>::ret_type doit(const FromTy *Val) {
+    return (typename cast_retty<To, FromTy *>::ret_type) const_cast<FromTy *>(
+        Val);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// is_simple_type
+//===----------------------------------------------------------------------===//
+
+template <class X> struct is_simple_type {
+  static const bool value =
+      std::is_same_v<X, typename simplify_type<X>::SimpleType>;
+};
+
+// } // namespace detail
+
+//===----------------------------------------------------------------------===//
+// CastIsPossible
+//===----------------------------------------------------------------------===//
+
+/// This struct provides a way to check if a given cast is possible. It provides
+/// a static function called isPossible that is used to check if a cast can be
+/// performed. It should be overridden like this:
+///
+/// template<> struct CastIsPossible<foo, bar> {
+///   static inline bool isPossible(const bar &b) {
+///     return bar.isFoo();
+///   }
+/// };
+template <typename To, typename From, typename Enable = void>
+struct CastIsPossible {
+  static inline bool isPossible(const From &f) {
+    return isa_impl_wrap<
+        To, const From,
+        typename simplify_type<const From>::SimpleType>::doit(f);
+  }
+};
+
+// Needed for optional unwrapping. This could be implemented with isa_impl, but
+// we want to implement things in the new method and move old implementations
+// over. In fact, some of the isa_impl templates should be moved over to
+// CastIsPossible.
+template <typename To, typename From>
+struct CastIsPossible<To, std::optional<From>> {
+  static inline bool isPossible(const std::optional<From> &f) {
+    assert(f && "CastIsPossible::isPossible called on a nullopt!");
+    return isa_impl_wrap<
+        To, const From,
+        typename simplify_type<const From>::SimpleType>::doit(*f);
+  }
+};
+
+/// Upcasting (from derived to base) and casting from a type to itself should
+/// always be possible.
+template <typename To, typename From>
+struct CastIsPossible<To, From, std::enable_if_t<std::is_base_of_v<To, From>>> {
+  static inline bool isPossible(const From &f) { return true; }
+};
+
+//===----------------------------------------------------------------------===//
+// Cast traits
+//===----------------------------------------------------------------------===//
+
+/// All of these cast traits are meant to be implementations for useful casts
+/// that users may want to use that are outside the standard behavior. An
+/// example of how to use a special cast called `CastTrait` is:
+///
+/// template<> struct CastInfo<foo, bar> : public CastTrait<foo, bar> {};
+///
+/// Essentially, if your use case falls directly into one of the use cases
+/// supported by a given cast trait, simply inherit your special CastInfo
+/// directly from one of these to avoid having to reimplement the boilerplate
+/// `isPossible/castFailed/doCast/doCastIfPossible`. A cast trait can also
+/// provide a subset of those functions.
+
+/// This cast trait just provides castFailed for the specified `To` type to make
+/// CastInfo specializations more declarative. In order to use this, the target
+/// result type must be `To` and `To` must be constructible from `nullptr`.
+template <typename To> struct NullableValueCastFailed {
+  static To castFailed() { return To(nullptr); }
+};
+
+/// This cast trait just provides the default implementation of doCastIfPossible
+/// to make CastInfo specializations more declarative. The `Derived` template
+/// parameter *must* be provided for forwarding castFailed and doCast.
+template <typename To, typename From, typename Derived>
+struct DefaultDoCastIfPossible {
+  static To doCastIfPossible(From f) {
+    if (!Derived::isPossible(f))
+      return Derived::castFailed();
+    return Derived::doCast(f);
+  }
+};
+
+namespace detail {
+/// A helper to derive the type to use with `Self` for cast traits, when the
+/// provided CRTP derived type is allowed to be void.
+template <typename OptionalDerived, typename Default>
+using SelfType = std::conditional_t<std::is_same_v<OptionalDerived, void>,
+                                    Default, OptionalDerived>;
+} // namespace detail
+
+/// This cast trait provides casting for the specific case of casting to a
+/// value-typed object from a pointer-typed object. Note that `To` must be
+/// nullable/constructible from a pointer to `From` to use this cast.
+template <typename To, typename From, typename Derived = void>
+struct ValueFromPointerCast
+    : public CastIsPossible<To, From *>,
+      public NullableValueCastFailed<To>,
+      public DefaultDoCastIfPossible<
+          To, From *,
+          detail::SelfType<Derived, ValueFromPointerCast<To, From>>> {
+  static inline To doCast(From *f) { return To(f); }
+};
+
+/// This cast trait provides std::unique_ptr casting. It has the semantics of
+/// moving the contents of the input unique_ptr into the output unique_ptr
+/// during the cast. It's also a good example of how to implement a move-only
+/// cast.
+template <typename To, typename From, typename Derived = void>
+struct UniquePtrCast : public CastIsPossible<To, From *> {
+  using Self = detail::SelfType<Derived, UniquePtrCast<To, From>>;
+  using CastResultType = std::unique_ptr<
+      std::remove_reference_t<typename cast_retty<To, From>::ret_type>>;
+
+  static inline CastResultType doCast(std::unique_ptr<From> &&f) {
+    return CastResultType((typename CastResultType::element_type *)f.release());
+  }
+
+  static inline CastResultType castFailed() { return CastResultType(nullptr); }
+
+  static inline CastResultType doCastIfPossible(std::unique_ptr<From> &&f) {
+    if (!Self::isPossible(f))
+      return castFailed();
+    return doCast(f);
+  }
+};
+
+/// This cast trait provides std::optional<T> casting. This means that if you
+/// have a value type, you can cast it to another value type and have dyn_cast
+/// return an std::optional<T>.
+template <typename To, typename From, typename Derived = void>
+struct OptionalValueCast
+    : public CastIsPossible<To, From>,
+      public DefaultDoCastIfPossible<
+          std::optional<To>, From,
+          detail::SelfType<Derived, OptionalValueCast<To, From>>> {
+  static inline std::optional<To> castFailed() { return std::optional<To>{}; }
+
+  static inline std::optional<To> doCast(const From &f) { return To(f); }
+};
+
+/// Provides a cast trait that strips `const` from types to make it easier to
+/// implement a const-version of a non-const cast. It just removes boilerplate
+/// and reduces the amount of code you as the user need to implement. You can
+/// use it like this:
+///
+/// template<> struct CastInfo<foo, bar> {
+///   ...verbose implementation...
+/// };
+///
+/// template<> struct CastInfo<foo, const bar> : public
+///        ConstStrippingForwardingCast<foo, const bar, CastInfo<foo, bar>> {};
+///
+template <typename To, typename From, typename ForwardTo>
+struct ConstStrippingForwardingCast {
+  // Remove the pointer if it exists, then we can get rid of consts/volatiles.
+  using DecayedFrom = std::remove_cv_t<std::remove_pointer_t<From>>;
+  // Now if it's a pointer, add it back. Otherwise, we want a ref.
+  using NonConstFrom =
+      std::conditional_t<std::is_pointer_v<From>, DecayedFrom *, DecayedFrom &>;
+
+  static inline bool isPossible(const From &f) {
+    return ForwardTo::isPossible(const_cast<NonConstFrom>(f));
+  }
+
+  static inline decltype(auto) castFailed() { return ForwardTo::castFailed(); }
+
+  static inline decltype(auto) doCast(const From &f) {
+    return ForwardTo::doCast(const_cast<NonConstFrom>(f));
+  }
+
+  static inline decltype(auto) doCastIfPossible(const From &f) {
+    return ForwardTo::doCastIfPossible(const_cast<NonConstFrom>(f));
+  }
+};
+
+/// Provides a cast trait that uses a defined pointer to pointer cast as a base
+/// for reference-to-reference casts. Note that it does not provide castFailed
+/// and doCastIfPossible because a pointer-to-pointer cast would likely just
+/// return `nullptr` which could cause nullptr dereference. You can use it like
+/// this:
+///
+///   template <> struct CastInfo<foo, bar *> { ... verbose implementation... };
+///
+///   template <>
+///   struct CastInfo<foo, bar>
+///       : public ForwardToPointerCast<foo, bar, CastInfo<foo, bar *>> {};
+///
+template <typename To, typename From, typename ForwardTo>
+struct ForwardToPointerCast {
+  static inline bool isPossible(const From &f) {
+    return ForwardTo::isPossible(&f);
+  }
+
+  static inline decltype(auto) doCast(const From &f) {
+    return *ForwardTo::doCast(&f);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// CastInfo
+//===----------------------------------------------------------------------===//
+
+/// This struct provides a method for customizing the way a cast is performed.
+/// It inherits from CastIsPossible, to support the case of declaring many
+/// CastIsPossible specializations without having to specialize the full
+/// CastInfo.
+///
+/// In order to specialize different behaviors, specify different functions in
+/// your CastInfo specialization.
+/// For isa<> customization, provide:
+///
+///   `static bool isPossible(const From &f)`
+///
+/// For cast<> customization, provide:
+///
+///  `static To doCast(const From &f)`
+///
+/// For dyn_cast<> and the *_if_present<> variants' customization, provide:
+///
+///  `static To castFailed()` and `static To doCastIfPossible(const From &f)`
+///
+/// Your specialization might look something like this:
+///
+///  template<> struct CastInfo<foo, bar> : public CastIsPossible<foo, bar> {
+///    static inline foo doCast(const bar &b) {
+///      return foo(const_cast<bar &>(b));
+///    }
+///    static inline foo castFailed() { return foo(); }
+///    static inline foo doCastIfPossible(const bar &b) {
+///      if (!CastInfo<foo, bar>::isPossible(b))
+///        return castFailed();
+///      return doCast(b);
+///    }
+///  };
+
+// The default implementations of CastInfo don't use cast traits for now because
+// we need to specify types all over the place due to the current expected
+// casting behavior and the way cast_retty works. New use cases can and should
+// take advantage of the cast traits whenever possible!
+
+template <typename To, typename From, typename Enable = void>
+struct CastInfo : public CastIsPossible<To, From> {
+  using Self = CastInfo<To, From, Enable>;
+
+  using CastReturnType = typename cast_retty<To, From>::ret_type;
+
+  static inline CastReturnType doCast(const From &f) {
+    return cast_convert_val<
+        To, From,
+        typename simplify_type<From>::SimpleType>::doit(const_cast<From &>(f));
+  }
+
+  // This assumes that you can construct the cast return type from `nullptr`.
+  // This is largely to support legacy use cases - if you don't want this
+  // behavior you should specialize CastInfo for your use case.
+  static inline CastReturnType castFailed() { return CastReturnType(nullptr); }
+
+  static inline CastReturnType doCastIfPossible(const From &f) {
+    if (!Self::isPossible(f))
+      return castFailed();
+    return doCast(f);
+  }
+};
+
+/// This struct provides an overload for CastInfo where From has simplify_type
+/// defined. This simply forwards to the appropriate CastInfo with the
+/// simplified type/value, so you don't have to implement both.
+template <typename To, typename From>
+struct CastInfo<To, From, std::enable_if_t<!is_simple_type<From>::value>> {
+  using Self = CastInfo<To, From>;
+  using SimpleFrom = typename simplify_type<From>::SimpleType;
+  using SimplifiedSelf = CastInfo<To, SimpleFrom>;
+
+  static inline bool isPossible(From &f) {
+    return SimplifiedSelf::isPossible(
+        simplify_type<From>::getSimplifiedValue(f));
+  }
+
+  static inline decltype(auto) doCast(From &f) {
+    return SimplifiedSelf::doCast(simplify_type<From>::getSimplifiedValue(f));
+  }
+
+  static inline decltype(auto) castFailed() {
+    return SimplifiedSelf::castFailed();
+  }
+
+  static inline decltype(auto) doCastIfPossible(From &f) {
+    return SimplifiedSelf::doCastIfPossible(
+        simplify_type<From>::getSimplifiedValue(f));
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// Pre-specialized CastInfo
+//===----------------------------------------------------------------------===//
+
+/// Provide a CastInfo specialized for std::unique_ptr.
+template <typename To, typename From>
+struct CastInfo<To, std::unique_ptr<From>> : public UniquePtrCast<To, From> {};
+
+/// Provide a CastInfo specialized for std::optional<From>. It's assumed that if
+/// the input is std::optional<From> that the output can be std::optional<To>.
+/// If that's not the case, specialize CastInfo for your use case.
+template <typename To, typename From>
+struct CastInfo<To, std::optional<From>> : public OptionalValueCast<To, From> {
+};
+
+/// isa<X> - Return true if the parameter to the template is an instance of one
+/// of the template type arguments.  Used like this:
+///
+///  if (isa<Type>(myVal)) { ... }
+///  if (isa<Type0, Type1, Type2>(myVal)) { ... }
+template <typename To, typename From>
+[[nodiscard]] inline bool isa(const From &Val) {
+  return CastInfo<To, const From>::isPossible(Val);
+}
+
+template <typename First, typename Second, typename... Rest, typename From>
+[[nodiscard]] inline bool isa(const From &Val) {
+  return isa<First>(Val) || isa<Second, Rest...>(Val);
+}
+
+/// cast<X> - Return the argument parameter cast to the specified type.  This
+/// casting operator asserts that the type is correct, so it does not return
+/// null on failure.  It does not allow a null argument (use cast_if_present for
+/// that). It is typically used like this:
+///
+///  cast<Instruction>(myVal)->getParent()
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(const From &Val) {
+  assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+  return CastInfo<To, const From>::doCast(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(From &Val) {
+  assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+  return CastInfo<To, From>::doCast(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(From *Val) {
+  assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+  return CastInfo<To, From *>::doCast(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(std::unique_ptr<From> &&Val) {
+  assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+  return CastInfo<To, std::unique_ptr<From>>::doCast(std::move(Val));
+}
+
+//===----------------------------------------------------------------------===//
+// ValueIsPresent
+//===----------------------------------------------------------------------===//
+
+template <typename T>
+constexpr bool IsNullable =
+    std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>;
+
+/// ValueIsPresent provides a way to check if a value is, well, present. For
+/// pointers, this is the equivalent of checking against nullptr, for Optionals
+/// this is the equivalent of checking hasValue(). It also provides a method for
+/// unwrapping a value (think calling .value() on an optional).
+
+// Generic values can't *not* be present.
+template <typename T, typename Enable = void> struct ValueIsPresent {
+  using UnwrappedType = T;
+  static inline bool isPresent(const T &t) { return true; }
+  static inline decltype(auto) unwrapValue(T &t) { return t; }
+};
+
+// Optional provides its own way to check if something is present.
+template <typename T> struct ValueIsPresent<std::optional<T>> {
+  using UnwrappedType = T;
+  static inline bool isPresent(const std::optional<T> &t) {
+    return t.has_value();
+  }
+  static inline decltype(auto) unwrapValue(std::optional<T> &t) { return *t; }
+};
+
+// If something is "nullable" then we just compare it to nullptr to see if it
+// exists.
+template <typename T>
+struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> {
+  using UnwrappedType = T;
+  static inline bool isPresent(const T &t) { return t != T(nullptr); }
+  static inline decltype(auto) unwrapValue(T &t) { return t; }
+};
+
+namespace detail {
+// Convenience function we can use to check if a value is present. Because of
+// simplify_type, we have to call it on the simplified type for now.
+template <typename T> inline bool isPresent(const T &t) {
+  return ValueIsPresent<typename simplify_type<T>::SimpleType>::isPresent(
+      simplify_type<T>::getSimplifiedValue(const_cast<T &>(t)));
+}
+
+// Convenience function we can use to unwrap a value.
+template <typename T> inline decltype(auto) unwrapValue(T &t) {
+  return ValueIsPresent<T>::unwrapValue(t);
+}
+} // namespace detail
+
+/// dyn_cast<X> - Return the argument parameter cast to the specified type. This
+/// casting operator returns null if the argument is of the wrong type, so it
+/// can be used to test for a type as well as cast if successful. The value
+/// passed in must be present, if not, use dyn_cast_if_present. This should be
+/// used in the context of an if statement like this:
+///
+///  if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) {
+  assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+  return CastInfo<To, const From>::doCastIfPossible(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) {
+  assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+  return CastInfo<To, From>::doCastIfPossible(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) {
+  assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+  return CastInfo<To, From *>::doCastIfPossible(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &&Val) {
+  assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+  return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible(
+      std::forward<std::unique_ptr<From> &&>(Val));
+}
+
+/// isa_and_present<X> - Functionally identical to isa, except that a null value
+/// is accepted.
+template <typename... X, class Y>
+[[nodiscard]] inline bool isa_and_present(const Y &Val) {
+  if (!detail::isPresent(Val))
+    return false;
+  return isa<X...>(Val);
+}
+
+template <typename... X, class Y>
+[[nodiscard]] inline bool isa_and_nonnull(const Y &Val) {
+  return isa_and_present<X...>(Val);
+}
+
+/// cast_if_present<X> - Functionally identical to cast, except that a null
+/// value is accepted.
+template <class X, class Y>
+[[nodiscard]] inline auto cast_if_present(const Y &Val) {
+  if (!detail::isPresent(Val))
+    return CastInfo<X, const Y>::castFailed();
+  assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
+  return cast<X>(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y &Val) {
+  if (!detail::isPresent(Val))
+    return CastInfo<X, Y>::castFailed();
+  assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
+  return cast<X>(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y *Val) {
+  if (!detail::isPresent(Val))
+    return CastInfo<X, Y *>::castFailed();
+  assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
+  return cast<X>(detail::unwrapValue(Val));
+}
+
+template <class X, class Y>
+[[nodiscard]] inline auto cast_if_present(std::unique_ptr<Y> &&Val) {
+  if (!detail::isPresent(Val))
+    return UniquePtrCast<X, Y>::castFailed();
+  return UniquePtrCast<X, Y>::doCast(std::move(Val));
+}
+
+// Provide a forwarding from cast_or_null to cast_if_present for current
+// users. This is deprecated and will be removed in a future patch, use
+// cast_if_present instead.
+template <class X, class Y> auto cast_or_null(const Y &Val) {
+  return cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto cast_or_null(Y &Val) {
+  return cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto cast_or_null(Y *Val) {
+  return cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto cast_or_null(std::unique_ptr<Y> &&Val) {
+  return cast_if_present<X>(std::move(Val));
+}
+
+/// dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a
+/// null (or none in the case of optionals) value is accepted.
+template <class X, class Y> auto dyn_cast_if_present(const Y &Val) {
+  if (!detail::isPresent(Val))
+    return CastInfo<X, const Y>::castFailed();
+  return CastInfo<X, const Y>::doCastIfPossible(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> auto dyn_cast_if_present(Y &Val) {
+  if (!detail::isPresent(Val))
+    return CastInfo<X, Y>::castFailed();
+  return CastInfo<X, Y>::doCastIfPossible(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> auto dyn_cast_if_present(Y *Val) {
+  if (!detail::isPresent(Val))
+    return CastInfo<X, Y *>::castFailed();
+  return CastInfo<X, Y *>::doCastIfPossible(detail::unwrapValue(Val));
+}
+
+// Forwards to dyn_cast_if_present to avoid breaking current users. This is
+// deprecated and will be removed in a future patch, use
+// cast_if_present instead.
+template <class X, class Y> auto dyn_cast_or_null(const Y &Val) {
+  return dyn_cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto dyn_cast_or_null(Y &Val) {
+  return dyn_cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto dyn_cast_or_null(Y *Val) {
+  return dyn_cast_if_present<X>(Val);
+}
+
+/// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
+/// taking ownership of the input pointer iff isa<X>(Val) is true.  If the
+/// cast is successful, From refers to nullptr on exit and the casted value
+/// is returned.  If the cast is unsuccessful, the function returns nullptr
+/// and From is unchanged.
+template <class X, class Y>
+[[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
+unique_dyn_cast(std::unique_ptr<Y> &Val) {
+  if (!isa<X>(Val))
+    return nullptr;
+  return cast<X>(std::move(Val));
+}
+
+template <class X, class Y>
+[[nodiscard]] inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) {
+  return unique_dyn_cast<X, Y>(Val);
+}
+
+// unique_dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast,
+// except that a null value is accepted.
+template <class X, class Y>
+[[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
+unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) {
+  if (!Val)
+    return nullptr;
+  return unique_dyn_cast<X, Y>(Val);
+}
+
+template <class X, class Y>
+[[nodiscard]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) {
+  return unique_dyn_cast_or_null<X, Y>(Val);
+}
+
+} // end namespace wpi
+
+#endif // WPIUTIL_WPI_CASTING_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
index c98386e..121ed54 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
@@ -38,6 +38,10 @@
 # define __has_builtin(x) 0
 #endif
 
+#ifndef __has_include
+# define __has_include(x) 0
+#endif
+
 // Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
 // C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
 #ifndef LLVM_HAS_CPP_ATTRIBUTE
@@ -101,26 +105,6 @@
 #endif
 #endif
 
-/// Does the compiler support ref-qualifiers for *this?
-///
-/// Sadly, this is separate from just rvalue reference support because GCC
-/// and MSVC implemented this later than everything else. This appears to be
-/// corrected in MSVC 2019 but not MSVC 2017.
-/// FIXME: Remove LLVM_HAS_RVALUE_REFERENCE_THIS macro
-#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
-
-/// Expands to '&' if ref-qualifiers for *this are supported.
-///
-/// This can be used to provide lvalue/rvalue overrides of member functions.
-/// The rvalue override should be guarded by LLVM_HAS_RVALUE_REFERENCE_THIS
-#ifndef LLVM_LVALUE_FUNCTION
-#if LLVM_HAS_RVALUE_REFERENCE_THIS
-#define LLVM_LVALUE_FUNCTION &
-#else
-#define LLVM_LVALUE_FUNCTION
-#endif
-#endif
-
 /// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
 /// into a shared library, then the class should be private to the library and
 /// not accessible from outside it.  Can also be used to mark variables and
@@ -130,11 +114,24 @@
 /// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
 /// this attribute will be made public and visible outside of any shared library
 /// they are linked in to.
-#if __has_attribute(visibility) && !defined(__MINGW32__) &&                    \
-    !defined(__CYGWIN__) && !defined(_WIN32)
-#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
+
+#if LLVM_HAS_CPP_ATTRIBUTE(gnu::visibility)
+#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN [[gnu::visibility("hidden")]]
+#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT [[gnu::visibility("default")]]
+#elif __has_attribute(visibility)
+#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))
+#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT __attribute__((visibility("default")))
+#else
+#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN
+#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
+#endif
+
+
+#if (!(defined(_WIN32) || defined(__CYGWIN__)) ||                              \
+     (defined(__MINGW32__) && defined(__clang__)))
+#define LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_HIDDEN
 #if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
-#define LLVM_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
+#define LLVM_EXTERNAL_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #else
 #define LLVM_EXTERNAL_VISIBILITY
 #endif
@@ -159,23 +156,10 @@
 #endif
 #endif
 
-/// LLVM_NODISCARD - Warn if a type or return value is discarded.
-
-// Use the 'nodiscard' attribute in C++17 or newer mode.
-#ifndef LLVM_NODISCARD
-#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
-#define LLVM_NODISCARD [[nodiscard]]
-#elif LLVM_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
-#define LLVM_NODISCARD [[clang::warn_unused_result]]
-// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
-// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
-// Use the 'nodiscard' attribute in C++14 mode only with GCC.
-// TODO: remove this workaround when PR33518 is resolved.
-#elif defined(__GNUC__) && LLVM_HAS_CPP_ATTRIBUTE(nodiscard)
-#define LLVM_NODISCARD [[nodiscard]]
+#if defined(__clang__)
+#define LLVM_DEPRECATED(MSG, FIX) __attribute__((deprecated(MSG, FIX)))
 #else
-#define LLVM_NODISCARD
-#endif
+#define LLVM_DEPRECATED(MSG, FIX) [[deprecated(MSG)]]
 #endif
 
 // Indicate that a non-static, non-const C++ member function reinitializes
@@ -356,23 +340,18 @@
 #endif
 #endif
 
-// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
-// This macro will be removed.
-// Use C++14's attribute instead: [[deprecated("message")]]
-#ifndef LLVM_ATTRIBUTE_DEPRECATED
-#define LLVM_ATTRIBUTE_DEPRECATED(decl, message) [[deprecated(message)]] decl
-#endif
-
 /// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
 /// to an expression which states that it is undefined behavior for the
 /// compiler to reach this point.  Otherwise is not defined.
+///
+/// '#else' is intentionally left out so that other macro logic (e.g.,
+/// LLVM_ASSUME_ALIGNED and wpi_unreachable()) can detect whether
+/// LLVM_BUILTIN_UNREACHABLE has a definition.
 #ifndef LLVM_BUILTIN_UNREACHABLE
 #if __has_builtin(__builtin_unreachable) || defined(__GNUC__)
 # define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
 #elif defined(_MSC_VER)
 # define LLVM_BUILTIN_UNREACHABLE __assume(false)
-#else
-# define LLVM_BUILTIN_UNREACHABLE
 #endif
 #endif
 
@@ -454,24 +433,6 @@
 #endif
 #endif
 
-/// \macro LLVM_PTR_SIZE
-/// A constant integer equivalent to the value of sizeof(void*).
-/// Generally used in combination with alignas or when doing computation in the
-/// preprocessor.
-#ifndef LLVM_PTR_SIZE
-#ifdef __SIZEOF_POINTER__
-# define LLVM_PTR_SIZE __SIZEOF_POINTER__
-#elif defined(_WIN64)
-# define LLVM_PTR_SIZE 8
-#elif defined(_WIN32)
-# define LLVM_PTR_SIZE 4
-#elif defined(_MSC_VER)
-# error "could not determine LLVM_PTR_SIZE as a constant int for MSVC"
-#else
-# define LLVM_PTR_SIZE sizeof(void *)
-#endif
-#endif
-
 /// \macro LLVM_MEMORY_SANITIZER_BUILD
 /// Whether LLVM itself is built with MemorySanitizer instrumentation.
 #if __has_feature(memory_sanitizer)
@@ -489,13 +450,34 @@
 /// Whether LLVM itself is built with AddressSanitizer instrumentation.
 #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
 # define LLVM_ADDRESS_SANITIZER_BUILD 1
+#if __has_include(<sanitizer/asan_interface.h>)
 # include <sanitizer/asan_interface.h>
 #else
+// These declarations exist to support ASan with MSVC. If MSVC eventually ships
+// asan_interface.h in their headers, then we can remove this.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif
+#else
 # define LLVM_ADDRESS_SANITIZER_BUILD 0
 # define __asan_poison_memory_region(p, size)
 # define __asan_unpoison_memory_region(p, size)
 #endif
 
+/// \macro LLVM_HWADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with HWAddressSanitizer instrumentation.
+#if __has_feature(hwaddress_sanitizer)
+#define LLVM_HWADDRESS_SANITIZER_BUILD 1
+#else
+#define LLVM_HWADDRESS_SANITIZER_BUILD 0
+#endif
+
 /// \macro LLVM_THREAD_SANITIZER_BUILD
 /// Whether LLVM itself is built with ThreadSanitizer instrumentation.
 #if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
index 436bc6d..6153d81 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
@@ -6,25 +6,41 @@
  *
  *==------------------------------------------------------------------------==*/
 /*
- * Copyright 2001-2004 Unicode, Inc.
+ * Copyright © 1991-2015 Unicode, Inc. All rights reserved.
+ * Distributed under the Terms of Use in
+ * http://www.unicode.org/copyright.html.
  *
- * Disclaimer
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of the Unicode data files and any associated documentation
+ * (the "Data Files") or Unicode software and any associated documentation
+ * (the "Software") to deal in the Data Files or Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of
+ * the Data Files or Software, and to permit persons to whom the Data Files
+ * or Software are furnished to do so, provided that
+ * (a) this copyright and permission notice appear with all copies
+ * of the Data Files or Software,
+ * (b) this copyright and permission notice appear in associated
+ * documentation, and
+ * (c) there is clear notice in each modified Data File or in the Software
+ * as well as in the documentation associated with the Data File(s) or
+ * Software that the data or software has been modified.
  *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+ * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+ * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THE DATA FILES OR SOFTWARE.
  *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale,
+ * use or other dealings in these Data Files or Software without prior
+ * written authorization of the copyright holder.
  */
 
 /* ---------------------------------------------------------------------
@@ -89,10 +105,9 @@
 #ifndef WPIUTIL_WPI_CONVERTUTF_H
 #define WPIUTIL_WPI_CONVERTUTF_H
 
-#include <span>
-
 #include <cstddef>
 #include <string>
+#include <span>
 #include <string_view>
 #include <system_error>
 
@@ -126,6 +141,9 @@
 #define UNI_UTF16_BYTE_ORDER_MARK_NATIVE  0xFEFF
 #define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
 
+#define UNI_UTF32_BYTE_ORDER_MARK_NATIVE 0x0000FEFF
+#define UNI_UTF32_BYTE_ORDER_MARK_SWAPPED 0xFFFE0000
+
 typedef enum {
   conversionOK,           /* conversion successful */
   sourceExhausted,        /* partial character in source, but hit end */
@@ -178,6 +196,8 @@
 
 Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
 
+unsigned getUTF8SequenceSize(const UTF8 *source, const UTF8 *sourceEnd);
+
 unsigned getNumBytesForUTF8(UTF8 firstByte);
 
 /*************************************************************************/
@@ -280,6 +300,24 @@
 bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out);
 
 /**
+ * Converts a stream of raw bytes assumed to be UTF32 into a UTF8 std::string.
+ *
+ * \param [in] SrcBytes A buffer of what is assumed to be UTF-32 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
+ * \returns true on success
+ */
+bool convertUTF32ToUTF8String(std::span<const char> SrcBytes, std::string &Out);
+
+/**
+ * Converts a UTF32 string into a UTF8 std::string.
+ *
+ * \param [in] Src A buffer of UTF-32 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
+ * \returns true on success
+ */
+bool convertUTF32ToUTF8String(std::span<const UTF32> Src, std::string &Out);
+
+/**
  * Converts a UTF-8 string into a UTF-16 string with native endianness.
  *
  * \returns true on success
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
deleted file mode 100644
index 2615bba..0000000
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains support for the DJ Bernstein hash function.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_DJB_H
-#define WPIUTIL_WPI_DJB_H
-
-#include <string_view>
-
-namespace wpi {
-
-/// The Bernstein hash function used by the DWARF accelerator tables.
-inline uint32_t djbHash(std::string_view Buffer, uint32_t H = 5381) {
-  for (unsigned char C : Buffer)
-    H = (H << 5) + H + C;
-  return H;
-}
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_DJB_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
index b1ffd43..2b872de 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
@@ -23,6 +23,7 @@
 #include "wpi/ReverseIteration.h"
 #include "wpi/type_traits.h"
 #include <algorithm>
+#include <bit>
 #include <cassert>
 #include <cstddef>
 #include <cstring>
@@ -95,9 +96,7 @@
     return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
   }
 
-  LLVM_NODISCARD bool empty() const {
-    return getNumEntries() == 0;
-  }
+  [[nodiscard]] bool empty() const { return getNumEntries() == 0; }
   unsigned size() const { return getNumEntries(); }
 
   /// Grow the densemap so that it can contain at least \p NumEntries items
@@ -126,7 +125,7 @@
       for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
         P->getFirst() = EmptyKey;
     } else {
-      unsigned NumEntries = getNumEntries();
+      [[maybe_unused]] unsigned NumEntries = getNumEntries();
       for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
         if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
           if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
@@ -137,15 +136,21 @@
         }
       }
       assert(NumEntries == 0 && "Node count imbalance!");
+      (void)NumEntries;
     }
     setNumEntries(0);
     setNumTombstones(0);
   }
 
+  /// Return true if the specified key is in the map, false otherwise.
+  bool contains(const_arg_type_t<KeyT> Val) const {
+    const BucketT *TheBucket;
+    return LookupBucketFor(Val, TheBucket);
+  }
+
   /// Return 1 if the specified key is in the map, 0 otherwise.
   size_type count(const_arg_type_t<KeyT> Val) const {
-    const BucketT *TheBucket;
-    return LookupBucketFor(Val, TheBucket) ? 1 : 0;
+    return contains(Val) ? 1 : 0;
   }
 
   iterator find(const_arg_type_t<KeyT> Val) {
@@ -202,6 +207,14 @@
     return ValueT();
   }
 
+  /// at - Return the entry for the specified key, or abort if no such
+  /// entry exists.
+  const ValueT &at(const_arg_type_t<KeyT> Val) const {
+    auto Iter = this->find(std::move(Val));
+    assert(Iter != this->end() && "DenseMap::at failed due to a missing key");
+    return Iter->second;
+  }
+
   // Inserts key,value pair into the map if the key isn't already in the map.
   // If the key is already in the map, it returns false and doesn't update the
   // value.
@@ -300,6 +313,20 @@
       insert(*I);
   }
 
+  /// Returns the value associated to the key in the map if it exists. If it
+  /// does not exist, emplace a default value for the key and returns a
+  /// reference to the newly created value.
+  ValueT &getOrInsertDefault(KeyT &&Key) {
+    return try_emplace(Key).first->second;
+  }
+
+  /// Returns the value associated to the key in the map if it exists. If it
+  /// does not exist, emplace a default value for the key and returns a
+  /// reference to the newly created value.
+  ValueT &getOrInsertDefault(const KeyT &Key) {
+    return try_emplace(Key).first->second;
+  }
+
   bool erase(const KeyT &Val) {
     BucketT *TheBucket;
     if (!LookupBucketFor(Val, TheBucket))
@@ -906,6 +933,8 @@
 
 public:
   explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
+    if (NumInitBuckets > InlineBuckets)
+      NumInitBuckets = std::bit_ceil(NumInitBuckets);
     init(NumInitBuckets);
   }
 
@@ -1196,8 +1225,7 @@
 
 public:
   using difference_type = ptrdiff_t;
-  using value_type =
-      typename std::conditional<IsConst, const Bucket, Bucket>::type;
+  using value_type = std::conditional_t<IsConst, const Bucket, Bucket>;
   using pointer = value_type *;
   using reference = value_type &;
   using iterator_category = std::forward_iterator_tag;
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
index 0ff8fc9..9e939ef 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
@@ -18,6 +18,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <tuple>
+#include <type_traits>
 #include <utility>
 
 namespace wpi {
@@ -232,6 +233,14 @@
                                     SecondInfo::getHashValue(PairVal.second));
   }
 
+  // Expose an additional function intended to be used by other
+  // specializations of DenseMapInfo without needing to know how
+  // to combine hash values manually
+  static unsigned getHashValuePiecewise(const T &First, const U &Second) {
+    return detail::combineHashValue(FirstInfo::getHashValue(First),
+                                    SecondInfo::getHashValue(Second));
+  }
+
   static bool isEqual(const Pair &LHS, const Pair &RHS) {
     return FirstInfo::isEqual(LHS.first, RHS.first) &&
            SecondInfo::isEqual(LHS.second, RHS.second);
@@ -252,7 +261,7 @@
 
   template <unsigned I>
   static unsigned getHashValueImpl(const Tuple &values, std::false_type) {
-    using EltType = typename std::tuple_element<I, Tuple>::type;
+    using EltType = std::tuple_element_t<I, Tuple>;
     std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
     return detail::combineHashValue(
         DenseMapInfo<EltType>::getHashValue(std::get<I>(values)),
@@ -271,7 +280,7 @@
 
   template <unsigned I>
   static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::false_type) {
-    using EltType = typename std::tuple_element<I, Tuple>::type;
+    using EltType = std::tuple_element_t<I, Tuple>;
     std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
     return DenseMapInfo<EltType>::isEqual(std::get<I>(lhs), std::get<I>(rhs)) &&
            isEqualImpl<I + 1>(lhs, rhs, atEnd);
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfoVariant.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfoVariant.h
new file mode 100644
index 0000000..b2d9739
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfoVariant.h
@@ -0,0 +1,71 @@
+//===- DenseMapInfoVariant.h - Type traits for DenseMap<variant> *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines DenseMapInfo traits for DenseMap<std::variant<Ts...>>.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_DENSEMAPINFOVARIANT_H
+#define WPIUTIL_WPI_DENSEMAPINFOVARIANT_H
+
+#include "wpi/DenseMapInfo.h"
+#include <utility>
+#include <variant>
+
+namespace wpi {
+
+// Provide DenseMapInfo for variants whose all alternatives have DenseMapInfo.
+template <typename... Ts> struct DenseMapInfo<std::variant<Ts...>> {
+  using Variant = std::variant<Ts...>;
+  using FirstT = std::variant_alternative_t<0, Variant>;
+
+  static inline Variant getEmptyKey() {
+    return Variant(std::in_place_index<0>, DenseMapInfo<FirstT>::getEmptyKey());
+  }
+
+  static inline Variant getTombstoneKey() {
+    return Variant(std::in_place_index<0>,
+                   DenseMapInfo<FirstT>::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(const Variant &Val) {
+    return std::visit(
+        [&Val](auto &&Alternative) {
+          using T = std::decay_t<decltype(Alternative)>;
+          // Include index in hash to make sure same value as different
+          // alternatives don't collide.
+          return DenseMapInfo<std::pair<size_t, T>>::getHashValuePiecewise(
+              Val.index(), Alternative);
+        },
+        Val);
+  }
+
+  static bool isEqual(const Variant &LHS, const Variant &RHS) {
+    if (LHS.index() != RHS.index())
+      return false;
+    if (LHS.valueless_by_exception())
+      return true;
+    // We want to dispatch to DenseMapInfo<T>::isEqual(LHS.get(I), RHS.get(I))
+    // We know the types are the same, but std::visit(V, LHS, RHS) doesn't.
+    // We erase the type held in LHS to void*, and dispatch over RHS.
+    const void *ErasedLHS =
+        std::visit([](const auto &LHS) -> const void * { return &LHS; }, LHS);
+    return std::visit(
+        [&](const auto &RHS) -> bool {
+          using T = std::remove_cv_t<std::remove_reference_t<decltype(RHS)>>;
+          return DenseMapInfo<T>::isEqual(*static_cast<const T *>(ErasedLHS),
+                                          RHS);
+        },
+        RHS);
+  }
+};
+
+} // end namespace wpi
+
+#endif // WPIUTIL_WPI_DENSEMAPINFOVARIANT_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
index 6417c05..8cb122a 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
@@ -22,6 +22,7 @@
 namespace wpi {
 
 #ifndef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
+#define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE
 
 /// A base class for data structure classes wishing to make iterators
 /// ("handles") pointing into themselves fail-fast.  When building without
@@ -33,10 +34,10 @@
 /// is still valid.
 ///
 class DebugEpochBase {
-  uint64_t Epoch;
+  uint64_t Epoch = 0;
 
 public:
-  DebugEpochBase() : Epoch(0) {}
+  DebugEpochBase() = default;
 
   /// Calling incrementEpoch invalidates all handles pointing into the
   /// calling instance.
@@ -55,11 +56,11 @@
   /// make an iterator-invalidating modification.
   ///
   class HandleBase {
-    const uint64_t *EpochAddress;
-    uint64_t EpochAtCreation;
+    const uint64_t *EpochAddress = nullptr;
+    uint64_t EpochAtCreation = UINT64_MAX;
 
   public:
-    HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
+    HandleBase() = default;
 
     explicit HandleBase(const DebugEpochBase *Parent)
         : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
@@ -77,6 +78,11 @@
 };
 
 #else
+#ifdef _MSC_VER
+#define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE __declspec(empty_bases)
+#else
+#define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE
+#endif // _MSC_VER
 
 class DebugEpochBase {
 public:
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
index febfc37..a01ebda 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
@@ -15,7 +15,6 @@
 
 #include <cerrno>
 #include <string>
-#include <type_traits>
 
 namespace wpi {
 namespace sys {
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
index 7b43671..abc9d7d 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
@@ -44,7 +44,7 @@
   void install_fatal_error_handler(fatal_error_handler_t handler,
                                    void *user_data = nullptr);
 
-  /// Restores default error handling behavior.
+  /// Restores default error handling behaviour.
   void remove_fatal_error_handler();
 
   /// ScopedFatalErrorHandler - This is a simple helper class which just
@@ -123,19 +123,34 @@
 
 /// Marks that the current location is not supposed to be reachable.
 /// In !NDEBUG builds, prints the message and location info to stderr.
-/// In NDEBUG builds, becomes an optimizer hint that the current location
-/// is not supposed to be reachable.  On compilers that don't support
-/// such hints, prints a reduced message instead and aborts the program.
+/// In NDEBUG builds, if the platform does not support a builtin unreachable
+/// then we call an internal LLVM runtime function. Otherwise the behavior is
+/// controlled by the CMake flag
+///   -DLLVM_UNREACHABLE_OPTIMIZE
+/// * When "ON" (default) wpi_unreachable() becomes an optimizer hint
+///   that the current location is not supposed to be reachable: the hint
+///   turns such code path into undefined behavior.  On compilers that don't
+///   support such hints, prints a reduced message instead and aborts the
+///   program.
+/// * When "OFF", a builtin_trap is emitted instead of an
+//    optimizer hint or printing a reduced message.
 ///
-/// Use this instead of assert(0).  It conveys intent more clearly and
-/// allows compilers to omit some unnecessary code.
+/// Use this instead of assert(0). It conveys intent more clearly, suppresses
+/// diagnostics for unreachable code paths, and allows compilers to omit
+/// unnecessary code.
 #ifndef NDEBUG
 #define wpi_unreachable(msg) \
   ::wpi::wpi_unreachable_internal(msg, __FILE__, __LINE__)
-#elif defined(LLVM_BUILTIN_UNREACHABLE)
+#elif !defined(LLVM_BUILTIN_UNREACHABLE)
+#define wpi_unreachable(msg) ::wpi::wpi_unreachable_internal()
+#elif LLVM_UNREACHABLE_OPTIMIZE
 #define wpi_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
 #else
-#define wpi_unreachable(msg) ::wpi::wpi_unreachable_internal()
+#define wpi_unreachable(msg)                                                  \
+  do {                                                                         \
+    LLVM_BUILTIN_TRAP;                                                         \
+    LLVM_BUILTIN_UNREACHABLE;                                                  \
+  } while (false)
 #endif
 
 #endif
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
index 681b87e..8c6d847 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
@@ -37,6 +37,7 @@
 #include "wpi/STLForwardCompat.h"
 #include "wpi/MemAlloc.h"
 #include "wpi/type_traits.h"
+#include <cstddef>
 #include <cstring>
 #include <memory>
 #include <type_traits>
@@ -66,13 +67,13 @@
 
 template <typename T>
 using EnableIfTrivial =
-    std::enable_if_t<wpi::is_trivially_move_constructible<T>::value &&
+    std::enable_if_t<std::is_trivially_move_constructible<T>::value &&
                      std::is_trivially_destructible<T>::value>;
 template <typename CallableT, typename ThisT>
 using EnableUnlessSameType =
     std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>::value>;
 template <typename CallableT, typename Ret, typename... Params>
-using EnableIfCallable = std::enable_if_t<wpi::disjunction<
+using EnableIfCallable = std::enable_if_t<std::disjunction<
     std::is_void<Ret>,
     std::is_same<decltype(std::declval<CallableT>()(std::declval<Params>()...)),
                  Ret>,
@@ -106,11 +107,11 @@
   template <typename T> struct AdjustedParamTBase {
     static_assert(!std::is_reference<T>::value,
                   "references should be handled by template specialization");
-    using type = typename std::conditional<
-        wpi::is_trivially_copy_constructible<T>::value &&
-            wpi::is_trivially_move_constructible<T>::value &&
-            IsSizeLessThanThresholdT<T>::value,
-        T, T &>::type;
+    using type =
+        std::conditional_t<std::is_trivially_copy_constructible<T>::value &&
+                               std::is_trivially_move_constructible<T>::value &&
+                               IsSizeLessThanThresholdT<T>::value,
+                           T, T &>;
   };
 
   // This specialization ensures that 'AdjustedParam<V<T>&>' or
@@ -167,9 +168,7 @@
     // provide four pointers worth of storage here.
     // This is mutable as an inlined `const unique_function<void() const>` may
     // still modify its own mutable members.
-    mutable
-        typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
-            InlineStorage;
+    alignas(void*) mutable std::byte InlineStorage[InlineStorageSize];
   } StorageUnion;
 
   // A compressed pointer to either our dispatching callback or our table of
@@ -180,16 +179,15 @@
   bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
 
   bool isTrivialCallback() const {
-    return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
+    return isa<TrivialCallback *>(CallbackAndInlineFlag.getPointer());
   }
 
   CallPtrT getTrivialCallback() const {
-    return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
+    return cast<TrivialCallback *>(CallbackAndInlineFlag.getPointer())->CallPtr;
   }
 
   NonTrivialCallbacks *getNonTrivialCallbacks() const {
-    return CallbackAndInlineFlag.getPointer()
-        .template get<NonTrivialCallbacks *>();
+    return cast<NonTrivialCallbacks *>(CallbackAndInlineFlag.getPointer());
   }
 
   CallPtrT getCallPtr() const {
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
index 0d4a4c6..bdb439c 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
@@ -48,8 +48,10 @@
 #include "wpi/SwapByteOrder.h"
 #include "wpi/type_traits.h"
 #include <algorithm>
+#include <bit>
 #include <cassert>
 #include <cstring>
+#include <optional>
 #include <string>
 #include <tuple>
 #include <utility>
@@ -126,6 +128,8 @@
 template <typename T>
 hash_code hash_value(const std::basic_string<T> &arg);
 
+/// Compute a hash_code for a standard string.
+template <typename T> hash_code hash_value(const std::optional<T> &arg);
 
 /// Override the execution seed with a fixed value.
 ///
@@ -220,29 +224,30 @@
   uint64_t b = fetch64(s + 8);
   uint64_t c = fetch64(s + len - 8) * k2;
   uint64_t d = fetch64(s + len - 16) * k0;
-  return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d,
-                       a + rotate(b ^ k3, 20) - c + len + seed);
+  return hash_16_bytes(std::rotr<uint64_t>(a - b, 43) +
+                           std::rotr<uint64_t>(c ^ seed, 30) + d,
+                       a + std::rotr<uint64_t>(b ^ k3, 20) - c + len + seed);
 }
 
 inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
   uint64_t z = fetch64(s + 24);
   uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
-  uint64_t b = rotate(a + z, 52);
-  uint64_t c = rotate(a, 37);
+  uint64_t b = std::rotr<uint64_t>(a + z, 52);
+  uint64_t c = std::rotr<uint64_t>(a, 37);
   a += fetch64(s + 8);
-  c += rotate(a, 7);
+  c += std::rotr<uint64_t>(a, 7);
   a += fetch64(s + 16);
   uint64_t vf = a + z;
-  uint64_t vs = b + rotate(a, 31) + c;
+  uint64_t vs = b + std::rotr<uint64_t>(a, 31) + c;
   a = fetch64(s + 16) + fetch64(s + len - 32);
   z = fetch64(s + len - 8);
-  b = rotate(a + z, 52);
-  c = rotate(a, 37);
+  b = std::rotr<uint64_t>(a + z, 52);
+  c = std::rotr<uint64_t>(a, 37);
   a += fetch64(s + len - 24);
-  c += rotate(a, 7);
+  c += std::rotr<uint64_t>(a, 7);
   a += fetch64(s + len - 16);
   uint64_t wf = a + z;
-  uint64_t ws = b + rotate(a, 31) + c;
+  uint64_t ws = b + std::rotr<uint64_t>(a, 31) + c;
   uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
   return shift_mix((seed ^ (r * k0)) + vs) * k2;
 }
@@ -272,9 +277,13 @@
   /// seed and the first 64-byte chunk.
   /// This effectively performs the initial mix.
   static hash_state create(const char *s, uint64_t seed) {
-    hash_state state = {
-      0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49),
-      seed * k1, shift_mix(seed), 0 };
+    hash_state state = {0,
+                        seed,
+                        hash_16_bytes(seed, k1),
+                        std::rotr<uint64_t>(seed ^ k1, 49),
+                        seed * k1,
+                        shift_mix(seed),
+                        0};
     state.h6 = hash_16_bytes(state.h4, state.h5);
     state.mix(s);
     return state;
@@ -285,10 +294,10 @@
   static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
     a += fetch64(s);
     uint64_t c = fetch64(s + 24);
-    b = rotate(b + a + c, 21);
+    b = std::rotr<uint64_t>(b + a + c, 21);
     uint64_t d = a;
     a += fetch64(s + 8) + fetch64(s + 16);
-    b += rotate(a, 44) + d;
+    b += std::rotr<uint64_t>(a, 44) + d;
     a += c;
   }
 
@@ -296,11 +305,11 @@
   /// We mix all 64 bytes even when the chunk length is smaller, but we
   /// record the actual length.
   void mix(const char *s) {
-    h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
-    h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1;
+    h0 = std::rotr<uint64_t>(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
+    h1 = std::rotr<uint64_t>(h1 + h4 + fetch64(s + 48), 42) * k1;
     h0 ^= h6;
     h1 += h3 + fetch64(s + 40);
-    h2 = rotate(h2 + h5, 33) * k1;
+    h2 = std::rotr<uint64_t>(h2 + h5, 33) * k1;
     h3 = h4 * k1;
     h4 = h0 + h5;
     mix_32_bytes(s, h3, h4);
@@ -655,24 +664,8 @@
   return hash_combine(arg.first, arg.second);
 }
 
-// Implementation details for the hash_value overload for std::tuple<...>(...).
-namespace hashing {
-namespace detail {
-
-template <typename... Ts, std::size_t... Indices>
-hash_code hash_value_tuple_helper(const std::tuple<Ts...> &arg,
-                                  std::index_sequence<Indices...>) {
-  return hash_combine(std::get<Indices>(arg)...);
-}
-
-} // namespace detail
-} // namespace hashing
-
-template <typename... Ts>
-hash_code hash_value(const std::tuple<Ts...> &arg) {
-  // TODO: Use std::apply when LLVM starts using C++17.
-  return ::wpi::hashing::detail::hash_value_tuple_helper(
-      arg, typename std::index_sequence_for<Ts...>());
+template <typename... Ts> hash_code hash_value(const std::tuple<Ts...> &arg) {
+  return std::apply([](const auto &...xs) { return hash_combine(xs...); }, arg);
 }
 
 // Declared and documented above, but defined here so that any of the hashing
@@ -682,6 +675,10 @@
   return hash_combine_range(arg.begin(), arg.end());
 }
 
+template <typename T> hash_code hash_value(const std::optional<T> &arg) {
+  return arg ? hash_combine(true, *arg) : hash_value(false);
+}
+
 template <> struct DenseMapInfo<hash_code, void> {
   static inline hash_code getEmptyKey() { return hash_code(-1); }
   static inline hash_code getTombstoneKey() { return hash_code(-2); }
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
index e4706c7..ce6fe78 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
@@ -10,7 +10,7 @@
 /// This file implements a map that provides insertion order iteration. The
 /// interface is purposefully minimal. The key is assumed to be cheap to copy
 /// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in
-/// a std::vector.
+/// a SmallVector.
 ///
 //===----------------------------------------------------------------------===//
 
@@ -24,22 +24,21 @@
 #include <iterator>
 #include <type_traits>
 #include <utility>
-#include <vector>
 
 namespace wpi {
 
 /// This class implements a map that also provides access to all stored values
-/// in a deterministic order. The values are kept in a std::vector and the
+/// in a deterministic order. The values are kept in a SmallVector<*, 0> and the
 /// mapping is done with DenseMap from Keys to indexes in that vector.
-template<typename KeyT, typename ValueT,
-         typename MapType = DenseMap<KeyT, unsigned>,
-         typename VectorType = std::vector<std::pair<KeyT, ValueT>>>
+template <typename KeyT, typename ValueT,
+          typename MapType = DenseMap<KeyT, unsigned>,
+          typename VectorType = SmallVector<std::pair<KeyT, ValueT>, 0>>
 class MapVector {
   MapType Map;
   VectorType Vector;
 
   static_assert(
-      std::is_integral<typename MapType::mapped_type>::value,
+      std::is_integral_v<typename MapType::mapped_type>,
       "The mapped_type of the specified Map must be an integral type");
 
 public:
@@ -109,7 +108,7 @@
 
   // Returns a copy of the value.  Only allowed if ValueT is copyable.
   ValueT lookup(const KeyT &Key) const {
-    static_assert(std::is_copy_constructible<ValueT>::value,
+    static_assert(std::is_copy_constructible_v<ValueT>,
                   "Cannot call lookup() if ValueT is not copyable.");
     typename MapType::const_iterator Pos = Map.find(Key);
     return Pos == Map.end()? ValueT() : Vector[Pos->second].second;
@@ -140,10 +139,9 @@
     return std::make_pair(begin() + I, false);
   }
 
-  size_type count(const KeyT &Key) const {
-    typename MapType::const_iterator Pos = Map.find(Key);
-    return Pos == Map.end()? 0 : 1;
-  }
+  bool contains(const KeyT &Key) const { return Map.find(Key) != Map.end(); }
+
+  size_type count(const KeyT &Key) const { return contains(Key) ? 1 : 0; }
 
   iterator find(const KeyT &Key) {
     typename MapType::const_iterator Pos = Map.find(Key);
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
index ea669ee..ed3b2b1 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
@@ -13,204 +13,22 @@
 #ifndef WPIUTIL_WPI_MATHEXTRAS_H
 #define WPIUTIL_WPI_MATHEXTRAS_H
 
+#include "wpi/bit.h"
 #include "wpi/Compiler.h"
+#include <bit>
 #include <cassert>
 #include <climits>
-#include <cmath>
 #include <cstdint>
 #include <cstring>
 #include <limits>
 #include <type_traits>
 
-#ifdef __ANDROID_NDK__
-#include <android/api-level.h>
-#endif
-
-#ifdef _MSC_VER
-// Declare these intrinsics manually rather including intrin.h. It's very
-// expensive, and MathExtras.h is popular.
-// #include <intrin.h>
-extern "C" {
-unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
-unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
-unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
-unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
-}
-#endif
-
 namespace wpi {
 
-/// The behavior an operation has on an input of 0.
-enum ZeroBehavior {
-  /// The returned value is undefined.
-  ZB_Undefined,
-  /// The returned value is numeric_limits<T>::max()
-  ZB_Max,
-  /// The returned value is numeric_limits<T>::digits
-  ZB_Width
-};
-
-namespace detail {
-template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
-  static unsigned count(T Val, ZeroBehavior) {
-    if (!Val)
-      return std::numeric_limits<T>::digits;
-    if (Val & 0x1)
-      return 0;
-
-    // Bisection method.
-    unsigned ZeroBits = 0;
-    T Shift = std::numeric_limits<T>::digits >> 1;
-    T Mask = (std::numeric_limits<T>::max)() >> Shift;
-    while (Shift) {
-      if ((Val & Mask) == 0) {
-        Val >>= Shift;
-        ZeroBits |= Shift;
-      }
-      Shift >>= 1;
-      Mask >>= Shift;
-    }
-    return ZeroBits;
-  }
-};
-
-#if defined(__GNUC__) || defined(_MSC_VER)
-template <typename T> struct TrailingZerosCounter<T, 4> {
-  static unsigned count(T Val, ZeroBehavior ZB) {
-    if (ZB != ZB_Undefined && Val == 0)
-      return 32;
-
-#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
-    return __builtin_ctz(Val);
-#elif defined(_MSC_VER)
-    unsigned long Index;
-    _BitScanForward(&Index, Val);
-    return Index;
-#endif
-  }
-};
-
-#if !defined(_MSC_VER) || defined(_M_X64)
-template <typename T> struct TrailingZerosCounter<T, 8> {
-  static unsigned count(T Val, ZeroBehavior ZB) {
-    if (ZB != ZB_Undefined && Val == 0)
-      return 64;
-
-#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
-    return __builtin_ctzll(Val);
-#elif defined(_MSC_VER)
-    unsigned long Index;
-    _BitScanForward64(&Index, Val);
-    return Index;
-#endif
-  }
-};
-#endif
-#endif
-} // namespace detail
-
-/// Count number of 0's from the least significant bit to the most
-///   stopping at the first 1.
-///
-/// Only unsigned integral types are allowed.
-///
-/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
-///   valid arguments.
-template <typename T>
-unsigned countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
-  static_assert(std::numeric_limits<T>::is_integer &&
-                    !std::numeric_limits<T>::is_signed,
-                "Only unsigned integral types are allowed.");
-  return wpi::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
-}
-
-namespace detail {
-template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
-  static unsigned count(T Val, ZeroBehavior) {
-    if (!Val)
-      return std::numeric_limits<T>::digits;
-
-    // Bisection method.
-    unsigned ZeroBits = 0;
-    for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
-      T Tmp = Val >> Shift;
-      if (Tmp)
-        Val = Tmp;
-      else
-        ZeroBits |= Shift;
-    }
-    return ZeroBits;
-  }
-};
-
-#if defined(__GNUC__) || defined(_MSC_VER)
-template <typename T> struct LeadingZerosCounter<T, 4> {
-  static unsigned count(T Val, ZeroBehavior ZB) {
-    if (ZB != ZB_Undefined && Val == 0)
-      return 32;
-
-#if __has_builtin(__builtin_clz) || defined(__GNUC__)
-    return __builtin_clz(Val);
-#elif defined(_MSC_VER)
-    unsigned long Index;
-    _BitScanReverse(&Index, Val);
-    return Index ^ 31;
-#endif
-  }
-};
-
-#if !defined(_MSC_VER) || defined(_M_X64)
-template <typename T> struct LeadingZerosCounter<T, 8> {
-  static unsigned count(T Val, ZeroBehavior ZB) {
-    if (ZB != ZB_Undefined && Val == 0)
-      return 64;
-
-#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
-    return __builtin_clzll(Val);
-#elif defined(_MSC_VER)
-    unsigned long Index;
-    _BitScanReverse64(&Index, Val);
-    return Index ^ 63;
-#endif
-  }
-};
-#endif
-#endif
-} // namespace detail
-
-/// Count number of 0's from the most significant bit to the least
-///   stopping at the first 1.
-///
-/// Only unsigned integral types are allowed.
-///
-/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
-///   valid arguments.
-template <typename T>
-unsigned countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
-  static_assert(std::numeric_limits<T>::is_integer &&
-                    !std::numeric_limits<T>::is_signed,
-                "Only unsigned integral types are allowed.");
-  return wpi::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
-}
-
-/// Get the index of the first set bit starting from the least
-///   significant bit.
-///
-/// Only unsigned integral types are allowed.
-///
-/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
-///   valid arguments.
-template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
-  if (ZB == ZB_Max && Val == 0)
-    return (std::numeric_limits<T>::max)();
-
-  return countTrailingZeros(Val, ZB_Undefined);
-}
-
 /// Create a bitmask with the N right-most bits set to 1, and all other
 /// bits set to 0.  Only unsigned types are allowed.
 template <typename T> T maskTrailingOnes(unsigned N) {
-  static_assert(std::is_unsigned<T>::value, "Invalid type!");
+  static_assert(std::is_unsigned_v<T>, "Invalid type!");
   const unsigned Bits = CHAR_BIT * sizeof(T);
   assert(N <= Bits && "Invalid bit index");
   return N == 0 ? 0 : (T(-1) >> (Bits - N));
@@ -234,23 +52,6 @@
   return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
 }
 
-/// Get the index of the last set bit starting from the least
-///   significant bit.
-///
-/// Only unsigned integral types are allowed.
-///
-/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
-///   valid arguments.
-template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
-  if (ZB == ZB_Max && Val == 0)
-    return (std::numeric_limits<T>::max)();
-
-  // Use ^ instead of - because both gcc and llvm can remove the associated ^
-  // in the __builtin_clz intrinsic on x86.
-  return countLeadingZeros(Val, ZB_Undefined) ^
-         (std::numeric_limits<T>::digits - 1);
-}
-
 /// Macro compressed bit reversal table for 256 bits.
 ///
 /// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
@@ -265,8 +66,24 @@
 };
 
 /// Reverse the bits in \p Val.
-template <typename T>
-T reverseBits(T Val) {
+template <typename T> T reverseBits(T Val) {
+#if __has_builtin(__builtin_bitreverse8)
+  if constexpr (std::is_same_v<T, uint8_t>)
+    return __builtin_bitreverse8(Val);
+#endif
+#if __has_builtin(__builtin_bitreverse16)
+  if constexpr (std::is_same_v<T, uint16_t>)
+    return __builtin_bitreverse16(Val);
+#endif
+#if __has_builtin(__builtin_bitreverse32)
+  if constexpr (std::is_same_v<T, uint32_t>)
+    return __builtin_bitreverse32(Val);
+#endif
+#if __has_builtin(__builtin_bitreverse64)
+  if constexpr (std::is_same_v<T, uint64_t>)
+    return __builtin_bitreverse64(Val);
+#endif
+
   unsigned char in[sizeof(Val)];
   unsigned char out[sizeof(Val)];
   std::memcpy(in, &Val, sizeof(Val));
@@ -276,34 +93,6 @@
   return Val;
 }
 
-#if __has_builtin(__builtin_bitreverse8)
-template<>
-inline uint8_t reverseBits<uint8_t>(uint8_t Val) {
-  return __builtin_bitreverse8(Val);
-}
-#endif
-
-#if __has_builtin(__builtin_bitreverse16)
-template<>
-inline uint16_t reverseBits<uint16_t>(uint16_t Val) {
-  return __builtin_bitreverse16(Val);
-}
-#endif
-
-#if __has_builtin(__builtin_bitreverse32)
-template<>
-inline uint32_t reverseBits<uint32_t>(uint32_t Val) {
-  return __builtin_bitreverse32(Val);
-}
-#endif
-
-#if __has_builtin(__builtin_bitreverse64)
-template<>
-inline uint64_t reverseBits<uint64_t>(uint64_t Val) {
-  return __builtin_bitreverse64(Val);
-}
-#endif
-
 // NOTE: The following support functions use the _32/_64 extensions instead of
 // type overloading so that signed and unsigned integers can be used without
 // ambiguity.
@@ -325,17 +114,16 @@
 
 /// Checks if an integer fits into the given bit width.
 template <unsigned N> constexpr inline bool isInt(int64_t x) {
-  return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
-}
-// Template specializations to get better code for common cases.
-template <> constexpr inline bool isInt<8>(int64_t x) {
-  return static_cast<int8_t>(x) == x;
-}
-template <> constexpr inline bool isInt<16>(int64_t x) {
-  return static_cast<int16_t>(x) == x;
-}
-template <> constexpr inline bool isInt<32>(int64_t x) {
-  return static_cast<int32_t>(x) == x;
+  if constexpr (N == 8)
+    return static_cast<int8_t>(x) == x;
+  if constexpr (N == 16)
+    return static_cast<int16_t>(x) == x;
+  if constexpr (N == 32)
+    return static_cast<int32_t>(x) == x;
+  if constexpr (N < 64)
+    return -(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1));
+  (void)x; // MSVC v19.25 warns that x is unused.
+  return true;
 }
 
 /// Checks if a signed integer is an N bit number shifted left by S.
@@ -348,34 +136,20 @@
 }
 
 /// Checks if an unsigned integer fits into the given bit width.
-///
-/// This is written as two functions rather than as simply
-///
-///   return N >= 64 || X < (UINT64_C(1) << N);
-///
-/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
-/// left too many places.
-template <unsigned N>
-constexpr inline std::enable_if_t<(N < 64), bool> isUInt(uint64_t X) {
+template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
   static_assert(N > 0, "isUInt<0> doesn't make sense");
-  return X < (UINT64_C(1) << (N));
-}
-template <unsigned N>
-constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
+  if constexpr (N == 8)
+    return static_cast<uint8_t>(x) == x;
+  if constexpr (N == 16)
+    return static_cast<uint16_t>(x) == x;
+  if constexpr (N == 32)
+    return static_cast<uint32_t>(x) == x;
+  if constexpr (N < 64)
+    return x < (UINT64_C(1) << (N));
+  (void)x; // MSVC v19.25 warns that x is unused.
   return true;
 }
 
-// Template specializations to get better code for common cases.
-template <> constexpr inline bool isUInt<8>(uint64_t x) {
-  return static_cast<uint8_t>(x) == x;
-}
-template <> constexpr inline bool isUInt<16>(uint64_t x) {
-  return static_cast<uint16_t>(x) == x;
-}
-template <> constexpr inline bool isUInt<32>(uint64_t x) {
-  return static_cast<uint32_t>(x) == x;
-}
-
 /// Checks if a unsigned integer is an N bit number shifted left by S.
 template <unsigned N, unsigned S>
 constexpr inline bool isShiftedUInt(uint64_t x) {
@@ -462,86 +236,39 @@
 /// Return true if the argument is a power of two > 0.
 /// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
 constexpr inline bool isPowerOf2_32(uint32_t Value) {
-  return Value && !(Value & (Value - 1));
+  return std::has_single_bit(Value);
 }
 
 /// Return true if the argument is a power of two > 0 (64 bit edition.)
 constexpr inline bool isPowerOf2_64(uint64_t Value) {
-  return Value && !(Value & (Value - 1));
+  return std::has_single_bit(Value);
 }
 
-/// Count the number of ones from the most significant bit to the first
-/// zero bit.
-///
-/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
-/// Only unsigned integral types are allowed.
-///
-/// \param ZB the behavior on an input of all ones. Only ZB_Width and
-/// ZB_Undefined are valid arguments.
-template <typename T>
-unsigned countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
-  static_assert(std::numeric_limits<T>::is_integer &&
-                    !std::numeric_limits<T>::is_signed,
-                "Only unsigned integral types are allowed.");
-  return countLeadingZeros<T>(~Value, ZB);
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
+/// If true, \p MaskIdx will specify the index of the lowest set bit and \p
+/// MaskLen is updated to specify the length of the mask, else neither are
+/// updated.
+inline bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
+                             unsigned &MaskLen) {
+  if (!isShiftedMask_32(Value))
+    return false;
+  MaskIdx = std::countr_zero(Value);
+  MaskLen = std::popcount(Value);
+  return true;
 }
 
-/// Count the number of ones from the least significant bit to the first
-/// zero bit.
-///
-/// Ex. countTrailingOnes(0x00FF00FF) == 8.
-/// Only unsigned integral types are allowed.
-///
-/// \param ZB the behavior on an input of all ones. Only ZB_Width and
-/// ZB_Undefined are valid arguments.
-template <typename T>
-unsigned countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
-  static_assert(std::numeric_limits<T>::is_integer &&
-                    !std::numeric_limits<T>::is_signed,
-                "Only unsigned integral types are allowed.");
-  return countTrailingZeros<T>(~Value, ZB);
-}
-
-namespace detail {
-template <typename T, std::size_t SizeOfT> struct PopulationCounter {
-  static unsigned count(T Value) {
-    // Generic version, forward to 32 bits.
-    static_assert(SizeOfT <= 4, "Not implemented!");
-#if defined(__GNUC__)
-    return __builtin_popcount(Value);
-#else
-    uint32_t v = Value;
-    v = v - ((v >> 1) & 0x55555555);
-    v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
-    return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
-#endif
-  }
-};
-
-template <typename T> struct PopulationCounter<T, 8> {
-  static unsigned count(T Value) {
-#if defined(__GNUC__)
-    return __builtin_popcountll(Value);
-#else
-    uint64_t v = Value;
-    v = v - ((v >> 1) & 0x5555555555555555ULL);
-    v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
-    v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
-    return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
-#endif
-  }
-};
-} // namespace detail
-
-/// Count the number of set bits in a value.
-/// Ex. countPopulation(0xF000F000) = 8
-/// Returns 0 if the word is zero.
-template <typename T>
-inline unsigned countPopulation(T Value) {
-  static_assert(std::numeric_limits<T>::is_integer &&
-                    !std::numeric_limits<T>::is_signed,
-                "Only unsigned integral types are allowed.");
-  return detail::PopulationCounter<T, sizeof(T)>::count(Value);
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (64 bit version.) If true, \p MaskIdx will specify the index
+/// of the lowest set bit and \p MaskLen is updated to specify the length of the
+/// mask, else neither are updated.
+inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
+                             unsigned &MaskLen) {
+  if (!isShiftedMask_64(Value))
+    return false;
+  MaskIdx = std::countr_zero(Value);
+  MaskLen = std::popcount(Value);
+  return true;
 }
 
 /// Compile time Log2.
@@ -554,90 +281,30 @@
 
 template <> constexpr inline size_t CTLog2<1>() { return 0; }
 
-/// Return the log base 2 of the specified value.
-inline double Log2(double Value) {
-#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
-  return __builtin_log(Value) / __builtin_log(2.0);
-#else
-  return std::log2(Value);
-#endif
-}
-
 /// Return the floor log base 2 of the specified value, -1 if the value is zero.
 /// (32 bit edition.)
 /// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
 inline unsigned Log2_32(uint32_t Value) {
-  return static_cast<unsigned>(31 - countLeadingZeros(Value));
+  return static_cast<unsigned>(31 - std::countl_zero(Value));
 }
 
 /// Return the floor log base 2 of the specified value, -1 if the value is zero.
 /// (64 bit edition.)
 inline unsigned Log2_64(uint64_t Value) {
-  return static_cast<unsigned>(63 - countLeadingZeros(Value));
+  return static_cast<unsigned>(63 - std::countl_zero(Value));
 }
 
 /// Return the ceil log base 2 of the specified value, 32 if the value is zero.
 /// (32 bit edition).
 /// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
 inline unsigned Log2_32_Ceil(uint32_t Value) {
-  return static_cast<unsigned>(32 - countLeadingZeros(Value - 1));
+  return static_cast<unsigned>(32 - std::countl_zero(Value - 1));
 }
 
 /// Return the ceil log base 2 of the specified value, 64 if the value is zero.
 /// (64 bit edition.)
 inline unsigned Log2_64_Ceil(uint64_t Value) {
-  return static_cast<unsigned>(64 - countLeadingZeros(Value - 1));
-}
-
-/// Return the greatest common divisor of the values using Euclid's algorithm.
-template <typename T>
-inline T greatestCommonDivisor(T A, T B) {
-  while (B) {
-    T Tmp = B;
-    B = A % B;
-    A = Tmp;
-  }
-  return A;
-}
-
-inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
-  return greatestCommonDivisor<uint64_t>(A, B);
-}
-
-/// This function takes a 64-bit integer and returns the bit equivalent double.
-inline double BitsToDouble(uint64_t Bits) {
-  double D;
-  static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
-  memcpy(&D, &Bits, sizeof(Bits));
-  return D;
-}
-
-/// This function takes a 32-bit integer and returns the bit equivalent float.
-inline float BitsToFloat(uint32_t Bits) {
-  float F;
-  static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
-  memcpy(&F, &Bits, sizeof(Bits));
-  return F;
-}
-
-/// This function takes a double and returns the bit equivalent 64-bit integer.
-/// Note that copying doubles around changes the bits of NaNs on some hosts,
-/// notably x86, so this routine cannot be used if these bits are needed.
-inline uint64_t DoubleToBits(double Double) {
-  uint64_t Bits;
-  static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
-  memcpy(&Bits, &Double, sizeof(Double));
-  return Bits;
-}
-
-/// This function takes a float and returns the bit equivalent 32-bit integer.
-/// Note that copying floats around changes the bits of NaNs on some hosts,
-/// notably x86, so this routine cannot be used if these bits are needed.
-inline uint32_t FloatToBits(float Float) {
-  uint32_t Bits;
-  static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
-  memcpy(&Bits, &Float, sizeof(Float));
-  return Bits;
+  return static_cast<unsigned>(64 - std::countl_zero(Value - 1));
 }
 
 /// A and B are either alignments or offsets. Return the minimum alignment that
@@ -653,7 +320,7 @@
 
 /// Returns the next power of two (in 64-bits) that is strictly greater than A.
 /// Returns zero on overflow.
-inline uint64_t NextPowerOf2(uint64_t A) {
+constexpr inline uint64_t NextPowerOf2(uint64_t A) {
   A |= (A >> 1);
   A |= (A >> 2);
   A |= (A >> 4);
@@ -663,13 +330,6 @@
   return A + 1;
 }
 
-/// Returns the power of two which is less than or equal to the given value.
-/// Essentially, it is a floor operation across the domain of powers of two.
-inline uint64_t PowerOf2Floor(uint64_t A) {
-  if (!A) return 0;
-  return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
-}
-
 /// Returns the power of two which is greater than or equal to the given value.
 /// Essentially, it is a ceil operation across the domain of powers of two.
 inline uint64_t PowerOf2Ceil(uint64_t A) {
@@ -681,27 +341,43 @@
 /// Returns the next integer (mod 2**64) that is greater than or equal to
 /// \p Value and is a multiple of \p Align. \p Align must be non-zero.
 ///
-/// If non-zero \p Skew is specified, the return value will be a minimal
-/// integer that is greater than or equal to \p Value and equal to
-/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
-/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
-///
 /// Examples:
 /// \code
 ///   alignTo(5, 8) = 8
 ///   alignTo(17, 8) = 24
 ///   alignTo(~0LL, 8) = 0
 ///   alignTo(321, 255) = 510
+/// \endcode
+inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
+  assert(Align != 0u && "Align can't be 0.");
+  return (Value + Align - 1) / Align * Align;
+}
+
+inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
+  assert(Align != 0 && (Align & (Align - 1)) == 0 &&
+         "Align must be a power of 2");
+  // Replace unary minus to avoid compilation error on Windows:
+  // "unary minus operator applied to unsigned type, result still unsigned"
+  uint64_t negAlign = (~Align) + 1;
+  return (Value + Align - 1) & negAlign;
+}
+
+/// If non-zero \p Skew is specified, the return value will be a minimal integer
+/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
+/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
+/// Skew mod \p A'. \p Align must be non-zero.
 ///
+/// Examples:
+/// \code
 ///   alignTo(5, 8, 7) = 7
 ///   alignTo(17, 8, 1) = 17
 ///   alignTo(~0LL, 8, 3) = 3
 ///   alignTo(321, 255, 42) = 552
 /// \endcode
-inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
+inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew) {
   assert(Align != 0u && "Align can't be 0.");
   Skew %= Align;
-  return (Value + Align - 1 - Skew) / Align * Align + Skew;
+  return alignTo(Value - Skew, Align) + Skew;
 }
 
 /// Returns the next integer (mod 2**64) that is greater than or equal to
@@ -764,7 +440,7 @@
 /// Subtract two unsigned integers, X and Y, of type T and return the absolute
 /// value of the result.
 template <typename T>
-std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
+std::enable_if_t<std::is_unsigned_v<T>, T> AbsoluteDifference(T X, T Y) {
   return X > Y ? (X - Y) : (Y - X);
 }
 
@@ -772,7 +448,7 @@
 /// maximum representable value of T on overflow.  ResultOverflowed indicates if
 /// the result is larger than the maximum representable value of type T.
 template <typename T>
-std::enable_if_t<std::is_unsigned<T>::value, T>
+std::enable_if_t<std::is_unsigned_v<T>, T>
 SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
   bool Dummy;
   bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -785,11 +461,23 @@
     return Z;
 }
 
+/// Add multiple unsigned integers of type T.  Clamp the result to the
+/// maximum representable value of T on overflow.
+template <class T, class... Ts>
+std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
+                                                         Ts... Args) {
+  bool Overflowed = false;
+  T XY = SaturatingAdd(X, Y, &Overflowed);
+  if (Overflowed)
+    return SaturatingAdd((std::numeric_limits<T>::max)(), T(1), Args...);
+  return SaturatingAdd(XY, Z, Args...);
+}
+
 /// Multiply two unsigned integers, X and Y, of type T.  Clamp the result to the
 /// maximum representable value of T on overflow.  ResultOverflowed indicates if
 /// the result is larger than the maximum representable value of type T.
 template <typename T>
-std::enable_if_t<std::is_unsigned<T>::value, T>
+std::enable_if_t<std::is_unsigned_v<T>, T>
 SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
   bool Dummy;
   bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -835,7 +523,7 @@
 /// overflow. ResultOverflowed indicates if the result is larger than the
 /// maximum representable value of type T.
 template <typename T>
-std::enable_if_t<std::is_unsigned<T>::value, T>
+std::enable_if_t<std::is_unsigned_v<T>, T>
 SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
   bool Dummy;
   bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -852,9 +540,9 @@
 
 
 /// Add two signed integers, computing the two's complement truncated result,
-/// returning true if overflow occured.
+/// returning true if overflow occurred.
 template <typename T>
-std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
+std::enable_if_t<std::is_signed_v<T>, T> AddOverflow(T X, T Y, T &Result) {
 #if __has_builtin(__builtin_add_overflow)
   return __builtin_add_overflow(X, Y, &Result);
 #else
@@ -880,7 +568,7 @@
 /// Subtract two signed integers, computing the two's complement truncated
 /// result, returning true if an overflow ocurred.
 template <typename T>
-std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
+std::enable_if_t<std::is_signed_v<T>, T> SubOverflow(T X, T Y, T &Result) {
 #if __has_builtin(__builtin_sub_overflow)
   return __builtin_sub_overflow(X, Y, &Result);
 #else
@@ -906,7 +594,7 @@
 /// Multiply two signed integers, computing the two's complement truncated
 /// result, returning true if an overflow ocurred.
 template <typename T>
-std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
+std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y, T &Result) {
   // Perform the unsigned multiplication on absolute values.
   using U = std::make_unsigned_t<T>;
   const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
index 34ff4e1..22205c9 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
@@ -19,10 +19,44 @@
 #include "wpi/type_traits.h"
 #include <cassert>
 #include <cstdint>
+#include <cstring>
 #include <limits>
 
 namespace wpi {
 
+namespace detail {
+template <typename Ptr> struct PunnedPointer {
+  static_assert(sizeof(Ptr) == sizeof(intptr_t), "");
+
+  // Asserts that allow us to let the compiler implement the destructor and
+  // copy/move constructors
+  static_assert(std::is_trivially_destructible<Ptr>::value, "");
+  static_assert(std::is_trivially_copy_constructible<Ptr>::value, "");
+  static_assert(std::is_trivially_move_constructible<Ptr>::value, "");
+
+  explicit constexpr PunnedPointer(intptr_t i = 0) { *this = i; }
+
+  constexpr intptr_t asInt() const {
+    intptr_t R = 0;
+    std::memcpy(&R, Data, sizeof(R));
+    return R;
+  }
+
+  constexpr operator intptr_t() const { return asInt(); }
+
+  constexpr PunnedPointer &operator=(intptr_t V) {
+    std::memcpy(Data, &V, sizeof(Data));
+    return *this;
+  }
+
+  Ptr *getPointerAddress() { return reinterpret_cast<Ptr *>(Data); }
+  const Ptr *getPointerAddress() const { return reinterpret_cast<Ptr *>(Data); }
+
+private:
+  alignas(Ptr) unsigned char Data[sizeof(Ptr)];
+};
+} // namespace detail
+
 template <typename T, typename Enable> struct DenseMapInfo;
 template <typename PointerT, unsigned IntBits, typename PtrTraits>
 struct PointerIntPairInfo;
@@ -46,7 +80,7 @@
 class PointerIntPair {
   // Used by MSVC visualizer and generally helpful for debugging/visualizing.
   using InfoTy = Info;
-  intptr_t Value = 0;
+  detail::PunnedPointer<PointerTy> Value;
 
 public:
   constexpr PointerIntPair() = default;
@@ -61,19 +95,19 @@
 
   IntType getInt() const { return (IntType)Info::getInt(Value); }
 
-  void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
+  void setPointer(PointerTy PtrVal) & {
     Value = Info::updatePointer(Value, PtrVal);
   }
 
-  void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
+  void setInt(IntType IntVal) & {
     Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
   }
 
-  void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
+  void initWithPointer(PointerTy PtrVal) & {
     Value = Info::updatePointer(0, PtrVal);
   }
 
-  void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
+  void setPointerAndInt(PointerTy PtrVal, IntType IntVal) & {
     Value = Info::updateInt(Info::updatePointer(0, PtrVal),
                             static_cast<intptr_t>(IntVal));
   }
@@ -86,12 +120,14 @@
     assert(Value == reinterpret_cast<intptr_t>(getPointer()) &&
            "Can only return the address if IntBits is cleared and "
            "PtrTraits doesn't change the pointer");
-    return reinterpret_cast<PointerTy *>(&Value);
+    return Value.getPointerAddress();
   }
 
-  void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
+  void *getOpaqueValue() const {
+    return reinterpret_cast<void *>(Value.asInt());
+  }
 
-  void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
+  void setFromOpaqueValue(void *Val) & {
     Value = reinterpret_cast<intptr_t>(Val);
   }
 
@@ -128,7 +164,6 @@
   }
 };
 
-
 template <typename PointerT, unsigned IntBits, typename PtrTraits>
 struct PointerIntPairInfo {
   static_assert(PtrTraits::NumLowBitsAvailable <
@@ -228,6 +263,32 @@
       PtrTraits::NumLowBitsAvailable - IntBits;
 };
 
+// Allow structured bindings on PointerIntPair.
+template <std::size_t I, typename PointerTy, unsigned IntBits, typename IntType,
+          typename PtrTraits, typename Info>
+decltype(auto)
+get(const PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info> &Pair) {
+  static_assert(I < 2);
+  if constexpr (I == 0)
+    return Pair.getPointer();
+  else
+    return Pair.getInt();
+}
+
 } // end namespace wpi
 
+namespace std {
+template <typename PointerTy, unsigned IntBits, typename IntType,
+          typename PtrTraits, typename Info>
+struct tuple_size<
+    wpi::PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>
+    : std::integral_constant<std::size_t, 2> {};
+
+template <std::size_t I, typename PointerTy, unsigned IntBits, typename IntType,
+          typename PtrTraits, typename Info>
+struct tuple_element<
+    I, wpi::PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>
+    : std::conditional<I == 0, PointerTy, IntType> {};
+} // namespace std
+
 #endif // WPIUTIL_WPI_POINTERINTPAIR_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
index cc12bbc..5053a5f 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
@@ -17,6 +17,7 @@
 
 #include "wpi/DenseMapInfo.h"
 #include "wpi/PointerIntPair.h"
+#include "wpi/Casting.h"
 #include "wpi/PointerLikeTypeTraits.h"
 #include <algorithm>
 #include <cassert>
@@ -132,6 +133,9 @@
   };
 }
 
+// This is a forward declaration of CastInfoPointerUnionImpl
+// Refer to its definition below for further details
+template <typename... PTs> struct CastInfoPointerUnionImpl;
 /// A discriminated union of two or more pointer types, with the discriminator
 /// in the low bit of the pointer.
 ///
@@ -167,6 +171,11 @@
   using First = TypeAtIndex<0, PTs...>;
   using Base = typename PointerUnion::PointerUnionMembers;
 
+  /// This is needed to give the CastInfo implementation below access
+  /// to protected members.
+  /// Refer to its definition for further details.
+  friend struct CastInfoPointerUnionImpl<PTs...>;
+
 public:
   PointerUnion() = default;
 
@@ -179,25 +188,24 @@
 
   explicit operator bool() const { return !isNull(); }
 
+  // FIXME: Replace the uses of is(), get() and dyn_cast() with
+  //        isa<T>, cast<T> and the wpi::dyn_cast<T>
+
   /// Test if the Union currently holds the type matching T.
-  template <typename T> bool is() const {
-    return this->Val.getInt() == FirstIndexOfType<T, PTs...>::value;
-  }
+  template <typename T> inline bool is() const { return isa<T>(*this); }
 
   /// Returns the value of the specified pointer type.
   ///
   /// If the specified pointer type is incorrect, assert.
-  template <typename T> T get() const {
-    assert(is<T>() && "Invalid accessor called");
-    return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer());
+  template <typename T> inline T get() const {
+    assert(isa<T>(*this) && "Invalid accessor called");
+    return cast<T>(*this);
   }
 
   /// Returns the current pointer if it is of the specified pointer type,
   /// otherwise returns null.
-  template <typename T> T dyn_cast() const {
-    if (is<T>())
-      return get<T>();
-    return T();
+  template <typename T> inline T dyn_cast() const {
+    return wpi::dyn_cast_if_present<T>(*this);
   }
 
   /// If the union is set to the first pointer type get an address pointing to
@@ -209,9 +217,9 @@
   /// If the union is set to the first pointer type get an address pointing to
   /// it.
   First *getAddrOfPtr1() {
-    assert(is<First>() && "Val is not the first pointer");
+    assert(isa<First>(*this) && "Val is not the first pointer");
     assert(
-        PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
+        PointerLikeTypeTraits<First>::getAsVoidPointer(cast<First>(*this)) ==
             this->Val.getPointer() &&
         "Can't get the address because PointerLikeTypeTraits changes the ptr");
     return const_cast<First *>(
@@ -250,6 +258,52 @@
   return lhs.getOpaqueValue() < rhs.getOpaqueValue();
 }
 
+/// We can't (at least, at this moment with C++14) declare CastInfo
+/// as a friend of PointerUnion like this:
+/// ```
+///   template<typename To>
+///   friend struct CastInfo<To, PointerUnion<PTs...>>;
+/// ```
+/// The compiler complains 'Partial specialization cannot be declared as a
+/// friend'.
+/// So we define this struct to be a bridge between CastInfo and
+/// PointerUnion.
+template <typename... PTs> struct CastInfoPointerUnionImpl {
+  using From = PointerUnion<PTs...>;
+
+  template <typename To> static inline bool isPossible(From &F) {
+    return F.Val.getInt() == FirstIndexOfType<To, PTs...>::value;
+  }
+
+  template <typename To> static To doCast(From &F) {
+    assert(isPossible<To>(F) && "cast to an incompatible type!");
+    return PointerLikeTypeTraits<To>::getFromVoidPointer(F.Val.getPointer());
+  }
+};
+
+// Specialization of CastInfo for PointerUnion
+template <typename To, typename... PTs>
+struct CastInfo<To, PointerUnion<PTs...>>
+    : public DefaultDoCastIfPossible<To, PointerUnion<PTs...>,
+                                     CastInfo<To, PointerUnion<PTs...>>> {
+  using From = PointerUnion<PTs...>;
+  using Impl = CastInfoPointerUnionImpl<PTs...>;
+
+  static inline bool isPossible(From &f) {
+    return Impl::template isPossible<To>(f);
+  }
+
+  static To doCast(From &f) { return Impl::template doCast<To>(f); }
+
+  static inline To castFailed() { return To(); }
+};
+
+template <typename To, typename... PTs>
+struct CastInfo<To, const PointerUnion<PTs...>>
+    : public ConstStrippingForwardingCast<To, const PointerUnion<PTs...>,
+                                          CastInfo<To, PointerUnion<PTs...>>> {
+};
+
 // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
 // # low bits available = min(PT1bits,PT2bits)-1.
 template <typename ...PTs>
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
index f46d38d..5425cd9 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
@@ -14,5 +14,5 @@
 #endif
 }
 
-}
+} // namespace wpi
 #endif
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
index 7f8f068..02cf826 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
@@ -17,54 +17,12 @@
 #ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
 #define WPIUTIL_WPI_STLFORWARDCOMPAT_H
 
+#include <optional>
 #include <type_traits>
 
 namespace wpi {
 
 //===----------------------------------------------------------------------===//
-//     Features from C++17
-//===----------------------------------------------------------------------===//
-
-template <typename T>
-struct negation // NOLINT(readability-identifier-naming)
-    : std::integral_constant<bool, !bool(T::value)> {};
-
-template <typename...>
-struct conjunction // NOLINT(readability-identifier-naming)
-    : std::true_type {};
-template <typename B1> struct conjunction<B1> : B1 {};
-template <typename B1, typename... Bn>
-struct conjunction<B1, Bn...>
-    : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
-
-template <typename...>
-struct disjunction // NOLINT(readability-identifier-naming)
-    : std::false_type {};
-template <typename B1> struct disjunction<B1> : B1 {};
-template <typename B1, typename... Bn>
-struct disjunction<B1, Bn...>
-    : std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type {};
-
-struct in_place_t // NOLINT(readability-identifier-naming)
-{
-  explicit in_place_t() = default;
-};
-/// \warning This must not be odr-used, as it cannot be made \c inline in C++14.
-constexpr in_place_t in_place; // NOLINT(readability-identifier-naming)
-
-template <typename T>
-struct in_place_type_t // NOLINT(readability-identifier-naming)
-{
-  explicit in_place_type_t() = default;
-};
-
-template <std::size_t I>
-struct in_place_index_t // NOLINT(readability-identifier-naming)
-{
-  explicit in_place_index_t() = default;
-};
-
-//===----------------------------------------------------------------------===//
 //     Features from C++20
 //===----------------------------------------------------------------------===//
 
@@ -78,6 +36,30 @@
 using remove_cvref_t // NOLINT(readability-identifier-naming)
     = typename wpi::remove_cvref<T>::type;
 
+//===----------------------------------------------------------------------===//
+//     Features from C++23
+//===----------------------------------------------------------------------===//
+
+// TODO: Remove this in favor of std::optional<T>::transform once we switch to
+// C++23.
+template <typename T, typename Function>
+auto transformOptional(const std::optional<T> &O, const Function &F)
+    -> std::optional<decltype(F(*O))> {
+  if (O)
+    return F(*O);
+  return std::nullopt;
+}
+
+// TODO: Remove this in favor of std::optional<T>::transform once we switch to
+// C++23.
+template <typename T, typename Function>
+auto transformOptional(std::optional<T> &&O, const Function &F)
+    -> std::optional<decltype(F(*std::move(O)))> {
+  if (O)
+    return F(*std::move(O));
+  return std::nullopt;
+}
+
 } // namespace wpi
 
 #endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
index 1ada1e0..db2b471 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
@@ -89,7 +89,7 @@
 
   SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
 
-  LLVM_NODISCARD bool empty() const { return size() == 0; }
+  [[nodiscard]] bool empty() const { return size() == 0; }
   size_type size() const { return NumNonEmpty - NumTombstones; }
 
   void clear() {
@@ -264,8 +264,9 @@
 
 /// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
 template <typename PtrTy>
-class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
-                            DebugEpochBase::HandleBase {
+class LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE SmallPtrSetIterator
+    : public SmallPtrSetIteratorImpl,
+      DebugEpochBase::HandleBase {
   using PtrTraits = PointerLikeTypeTraits<PtrTy>;
 
 public:
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
index 7b1b283..699be24 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
@@ -140,6 +140,7 @@
   std::set<T, C> Set;
 
   using VIterator = typename SmallVector<T, N>::const_iterator;
+  using SIterator = typename std::set<T, C>::const_iterator;
   using mutable_iterator = typename SmallVector<T, N>::iterator;
 
   // In small mode SmallPtrSet uses linear search for the elements, so it is
@@ -148,14 +149,14 @@
   static_assert(N <= 32, "N should be small");
 
 public:
+  using key_type = T;
   using size_type = size_t;
+  using value_type = T;
   using const_iterator = SmallSetIterator<T, N, C>;
 
   SmallSet() = default;
 
-  LLVM_NODISCARD bool empty() const {
-    return Vector.empty() && Set.empty();
-  }
+  [[nodiscard]] bool empty() const { return Vector.empty() && Set.empty(); }
 
   size_type size() const {
     return isSmall() ? Vector.size() : Set.size();
@@ -172,22 +173,21 @@
   }
 
   /// insert - Insert an element into the set if it isn't already there.
-  /// Returns true if the element is inserted (it was not in the set before).
-  /// The first value of the returned pair is unused and provided for
-  /// partial compatibility with the standard library self-associative container
-  /// concept.
-  // FIXME: Add iterators that abstract over the small and large form, and then
-  // return those here.
-  std::pair<std::nullopt_t, bool> insert(const T &V) {
-    if (!isSmall())
-      return std::make_pair(std::nullopt, Set.insert(V).second);
+  /// Returns a pair. The first value of it is an iterator to the inserted
+  /// element or the existing element in the set. The second value is true
+  /// if the element is inserted (it was not in the set before).
+  std::pair<const_iterator, bool> insert(const T &V) {
+    if (!isSmall()) {
+      auto [I, Inserted] = Set.insert(V);
+      return std::make_pair(const_iterator(I), Inserted);
+    }
 
     VIterator I = vfind(V);
     if (I != Vector.end())    // Don't reinsert if it already exists.
-      return std::make_pair(std::nullopt, false);
+      return std::make_pair(const_iterator(I), false);
     if (Vector.size() < N) {
       Vector.push_back(V);
-      return std::make_pair(std::nullopt, true);
+      return std::make_pair(const_iterator(std::prev(Vector.end())), true);
     }
 
     // Otherwise, grow from vector to set.
@@ -195,8 +195,7 @@
       Set.insert(Vector.back());
       Vector.pop_back();
     }
-    Set.insert(V);
-    return std::make_pair(std::nullopt, true);
+    return std::make_pair(const_iterator(Set.insert(V).first), true);
   }
 
   template <typename IterT>
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
index 134ce67..3b4b890 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 ///
-/// /file
+/// \file
 /// This file defines the SmallVector class.
 ///
 //===----------------------------------------------------------------------===//
@@ -35,6 +35,7 @@
 #include <limits>
 #include <memory>
 #include <new>
+#include <span>
 #include <type_traits>
 #include <utility>
 
@@ -42,6 +43,11 @@
 
 template <typename IteratorT> class iterator_range;
 
+template <class Iterator>
+using EnableIfConvertibleToInputIterator = std::enable_if_t<std::is_convertible<
+    typename std::iterator_traits<Iterator>::iterator_category,
+    std::input_iterator_tag>::value>;
+
 /// This is all the stuff common to all SmallVectors.
 ///
 /// The template parameter specifies the type which should be used to hold the
@@ -67,18 +73,32 @@
   /// This is a helper for \a grow() that's out of line to reduce code
   /// duplication.  This function will report a fatal error if it can't grow at
   /// least to \p MinSize.
-  void *mallocForGrow(size_t MinSize, size_t TSize, size_t &NewCapacity);
+  void *mallocForGrow(void *FirstEl, size_t MinSize, size_t TSize,
+                      size_t &NewCapacity);
 
   /// This is an implementation of the grow() method which only works
   /// on POD-like data types and is out of line to reduce code duplication.
   /// This function will report a fatal error if it cannot increase capacity.
   void grow_pod(void *FirstEl, size_t MinSize, size_t TSize);
 
+  /// If vector was first created with capacity 0, getFirstEl() points to the
+  /// memory right after, an area unallocated. If a subsequent allocation,
+  /// that grows the vector, happens to return the same pointer as getFirstEl(),
+  /// get a new allocation, otherwise isSmall() will falsely return that no
+  /// allocation was done (true) and the memory will not be freed in the
+  /// destructor. If a VSize is given (vector size), also copy that many
+  /// elements to the new allocation - used if realloca fails to increase
+  /// space, and happens to allocate precisely at BeginX.
+  /// This is unlikely to be called often, but resolves a memory leak when the
+  /// situation does occur.
+  void *replaceAllocation(void *NewElts, size_t TSize, size_t NewCapacity,
+                          size_t VSize = 0);
+
 public:
   size_t size() const { return Size; }
   size_t capacity() const { return Capacity; }
 
-  LLVM_NODISCARD bool empty() const { return !Size; }
+  [[nodiscard]] bool empty() const { return !Size; }
 
 protected:
   /// Set the array size to \p N, which the current array must have enough
@@ -99,13 +119,14 @@
 };
 
 /// This is the part of SmallVectorTemplateBase which does not depend on whether
-/// the type T is a POD. The extra dummy template argument is used by ArrayRef
+/// the type T is a POD. The extra dummy template argument is used by std::span
 /// to avoid unnecessarily requiring T to be complete.
 template <typename T, typename = void>
 class SmallVectorTemplateCommon
     : public SmallVectorBase {
   using Base = SmallVectorBase;
 
+protected:
   /// Find the address of the first element.  For this pointer math to be valid
   /// with small-size of 0 for T with lots of alignment, it's important that
   /// SmallVectorStorage is properly-aligned even for small-size of 0.
@@ -116,7 +137,6 @@
   }
   // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
 
-protected:
   SmallVectorTemplateCommon(size_t Size) : Base(getFirstEl(), Size) {}
 
   void grow_pod(size_t MinSize, size_t TSize) {
@@ -308,8 +328,8 @@
 /// copy these types with memcpy, there is no way for the type to observe this.
 /// This catches the important case of std::pair<POD, POD>, which is not
 /// trivially assignable.
-template <typename T, bool = (is_trivially_copy_constructible<T>::value) &&
-                             (is_trivially_move_constructible<T>::value) &&
+template <typename T, bool = (std::is_trivially_copy_constructible<T>::value) &&
+                             (std::is_trivially_move_constructible<T>::value) &&
                              std::is_trivially_destructible<T>::value>
 class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
   friend class SmallVectorTemplateCommon<T>;
@@ -331,8 +351,7 @@
   /// constructing elements as needed.
   template<typename It1, typename It2>
   static void uninitialized_move(It1 I, It1 E, It2 Dest) {
-    std::uninitialized_copy(std::make_move_iterator(I),
-                            std::make_move_iterator(E), Dest);
+    std::uninitialized_move(I, E, Dest);
   }
 
   /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
@@ -349,11 +368,7 @@
 
   /// Create a new allocation big enough for \p MinSize and pass back its size
   /// in \p NewCapacity. This is the first section of \a grow().
-  T *mallocForGrow(size_t MinSize, size_t &NewCapacity) {
-    return static_cast<T *>(
-        SmallVectorBase::mallocForGrow(
-            MinSize, sizeof(T), NewCapacity));
-  }
+  T *mallocForGrow(size_t MinSize, size_t &NewCapacity);
 
   /// Move existing elements over to the new allocation \p NewElts, the middle
   /// section of \a grow().
@@ -427,6 +442,14 @@
   takeAllocationForGrow(NewElts, NewCapacity);
 }
 
+template <typename T, bool TriviallyCopyable>
+T *SmallVectorTemplateBase<T, TriviallyCopyable>::mallocForGrow(
+    size_t MinSize, size_t &NewCapacity) {
+  return static_cast<T *>(
+      SmallVectorBase::mallocForGrow(
+          this->getFirstEl(), MinSize, sizeof(T), NewCapacity));
+}
+
 // Define this out-of-line to dissuade the C++ compiler from inlining it.
 template <typename T, bool TriviallyCopyable>
 void SmallVectorTemplateBase<T, TriviallyCopyable>::moveElementsForGrow(
@@ -465,8 +488,7 @@
 
   /// Either const T& or T, depending on whether it's cheap enough to take
   /// parameters by value.
-  using ValueParamT =
-      typename std::conditional<TakesParamByValue, T, const T &>::type;
+  using ValueParamT = std::conditional_t<TakesParamByValue, T, const T &>;
 
   SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
 
@@ -494,8 +516,8 @@
   template <typename T1, typename T2>
   static void uninitialized_copy(
       T1 *I, T1 *E, T2 *Dest,
-      std::enable_if_t<std::is_same<typename std::remove_const<T1>::type,
-                                    T2>::value> * = nullptr) {
+      std::enable_if_t<std::is_same<std::remove_const_t<T1>, T2>::value> * =
+          nullptr) {
     // Use memcpy for PODs iterated by pointers (which includes SmallVector
     // iterators): std::uninitialized_copy optimizes to memmove, but we can
     // use memcpy here. Note that I and E are iterators and thus might be
@@ -654,7 +676,7 @@
     truncate(this->size() - NumItems);
   }
 
-  LLVM_NODISCARD T pop_back_val() {
+  [[nodiscard]] T pop_back_val() {
     T Result = ::std::move(this->back());
     this->pop_back();
     return Result;
@@ -663,11 +685,8 @@
   void swap(SmallVectorImpl &RHS);
 
   /// Add the specified range to the end of the SmallVector.
-  template <typename in_iter,
-            typename = std::enable_if_t<std::is_convertible<
-                typename std::iterator_traits<in_iter>::iterator_category,
-                std::input_iterator_tag>::value>>
-  void append(in_iter in_start, in_iter in_end) {
+  template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
+  void append(ItTy in_start, ItTy in_end) {
     this->assertSafeToAddRange(in_start, in_end);
     size_type NumInputs = std::distance(in_start, in_end);
     this->reserve(this->size() + NumInputs);
@@ -707,11 +726,8 @@
   // FIXME: Consider assigning over existing elements, rather than clearing &
   // re-initializing them - for all assign(...) variants.
 
-  template <typename in_iter,
-            typename = std::enable_if_t<std::is_convertible<
-                typename std::iterator_traits<in_iter>::iterator_category,
-                std::input_iterator_tag>::value>>
-  void assign(in_iter in_start, in_iter in_end) {
+  template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
+  void assign(ItTy in_start, ItTy in_end) {
     this->assertSafeToReferenceAfterClear(in_start, in_end);
     clear();
     append(in_start, in_end);
@@ -861,10 +877,7 @@
     return I;
   }
 
-  template <typename ItTy,
-            typename = std::enable_if_t<std::is_convertible<
-                typename std::iterator_traits<ItTy>::iterator_category,
-                std::input_iterator_tag>::value>>
+  template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
   iterator insert(iterator I, ItTy From, ItTy To) {
     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
     size_t InsertElt = I - this->begin();
@@ -952,6 +965,9 @@
     return std::lexicographical_compare(this->begin(), this->end(),
                                         RHS.begin(), RHS.end());
   }
+  bool operator>(const SmallVectorImpl &RHS) const { return RHS < *this; }
+  bool operator<=(const SmallVectorImpl &RHS) const { return !(*this > RHS); }
+  bool operator>=(const SmallVectorImpl &RHS) const { return !(*this < RHS); }
 };
 
 template <typename T>
@@ -1192,15 +1208,17 @@
     this->destroy_range(this->begin(), this->end());
   }
 
-  explicit SmallVector(size_t Size, const T &Value = T())
+  explicit SmallVector(size_t Size)
+    : SmallVectorImpl<T>(N) {
+    this->resize(Size);
+  }
+
+  SmallVector(size_t Size, const T &Value)
     : SmallVectorImpl<T>(N) {
     this->assign(Size, Value);
   }
 
-  template <typename ItTy,
-            typename = std::enable_if_t<std::is_convertible<
-                typename std::iterator_traits<ItTy>::iterator_category,
-                std::input_iterator_tag>::value>>
+  template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
   SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
     this->append(S, E);
   }
@@ -1212,7 +1230,13 @@
   }
 
   SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
-    this->assign(IL);
+    this->append(IL);
+  }
+
+  template <typename U,
+            typename = std::enable_if_t<std::is_convertible<U, T>::value>>
+  explicit SmallVector(std::span<const U> A) : SmallVectorImpl<T>(N) {
+    this->append(A.begin(), A.end());
   }
 
   SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
@@ -1271,8 +1295,8 @@
 
 template <typename RangeType>
 using ValueTypeFromRangeType =
-    typename std::remove_const<typename std::remove_reference<
-        decltype(*std::begin(std::declval<RangeType &>()))>::type>::type;
+    std::remove_const_t<std::remove_reference_t<decltype(*std::begin(
+        std::declval<RangeType &>()))>>;
 
 /// Given a range of type R, iterate the entire range and return a
 /// SmallVector with elements of the vector.  This is useful, for example,
@@ -1282,10 +1306,16 @@
   return {std::begin(Range), std::end(Range)};
 }
 template <typename R>
-SmallVector<ValueTypeFromRangeType<R>,
-            CalculateSmallVectorDefaultInlinedElements<
-                ValueTypeFromRangeType<R>>::value>
-to_vector(R &&Range) {
+SmallVector<ValueTypeFromRangeType<R>> to_vector(R &&Range) {
+  return {std::begin(Range), std::end(Range)};
+}
+
+template <typename Out, unsigned Size, typename R>
+SmallVector<Out, Size> to_vector_of(R &&Range) {
+  return {std::begin(Range), std::end(Range)};
+}
+
+template <typename Out, typename R> SmallVector<Out> to_vector_of(R &&Range) {
   return {std::begin(Range), std::end(Range)};
 }
 
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
index 75c637b..e07576e 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <iterator>
 #include <limits>
 #include <optional>
 #include <string>
@@ -24,6 +25,8 @@
 #include <type_traits>
 #include <utility>
 
+#include <fmt/format.h>
+
 namespace wpi {
 
 template <typename T>
@@ -721,4 +724,23 @@
 std::pair<std::string_view, std::string_view> UnescapeCString(
     std::string_view str, SmallVectorImpl<char>& buf);
 
+/**
+ * Like std::format_to_n() in that it writes at most n bytes to the output
+ * buffer, but also includes a terminating null byte in n.
+ *
+ * This is essentially a more performant replacement for std::snprintf().
+ *
+ * @param out The output buffer.
+ * @param n The size of the output buffer.
+ * @param fmt The format string.
+ * @param args The format string arguments.
+ */
+template <class OutputIt, class... Args>
+inline void format_to_n_c_str(OutputIt out, std::iter_difference_t<OutputIt> n,
+                              fmt::format_string<Args...> fmt, Args&&... args) {
+  const auto result =
+      fmt::format_to_n(out, n - 1, fmt, std::forward<Args>(args)...);
+  *result.out = '\0';
+}
+
 }  // namespace wpi
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
index c7da670..323d22e 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
@@ -111,8 +111,10 @@
 /// funky memory allocation and hashing things to make it extremely efficient,
 /// storing the string data *after* the value in the map.
 template <typename ValueTy, typename AllocatorTy = MallocAllocator>
-class StringMap : public StringMapImpl {
-  AllocatorTy Allocator;
+class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
+    : public StringMapImpl,
+      private detail::AllocatorHolder<AllocatorTy> {
+  using AllocTy = detail::AllocatorHolder<AllocatorTy>;
 
 public:
   using MapEntryTy = StringMapEntry<ValueTy>;
@@ -123,12 +125,11 @@
       : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
 
   explicit StringMap(AllocatorTy A)
-      : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {
-  }
+      : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), AllocTy(A) {}
 
   StringMap(unsigned InitialSize, AllocatorTy A)
       : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
-        Allocator(A) {}
+        AllocTy(A) {}
 
   StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
       : StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
@@ -136,11 +137,11 @@
   }
 
   StringMap(StringMap &&RHS)
-      : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
+      : StringMapImpl(std::move(RHS)), AllocTy(std::move(RHS.getAllocator())) {}
 
   StringMap(const StringMap &RHS)
       : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
-        Allocator(RHS.Allocator) {
+        AllocTy(RHS.getAllocator()) {
     if (RHS.empty())
       return;
 
@@ -159,8 +160,8 @@
         continue;
       }
 
-      TheTable[I] = MapEntryTy::Create(
-          static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
+      TheTable[I] = MapEntryTy::create(
+          static_cast<MapEntryTy *>(Bucket)->getKey(), getAllocator(),
           static_cast<MapEntryTy *>(Bucket)->getValue());
       HashTable[I] = RHSHashTable[I];
     }
@@ -175,7 +176,7 @@
 
   StringMap &operator=(StringMap RHS) {
     StringMapImpl::swap(RHS);
-    std::swap(Allocator, RHS.Allocator);
+    std::swap(getAllocator(), RHS.getAllocator());
     return *this;
   }
 
@@ -187,15 +188,14 @@
       for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
         StringMapEntryBase *Bucket = TheTable[I];
         if (Bucket && Bucket != getTombstoneVal()) {
-          static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
+          static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator());
         }
       }
     }
     free(TheTable);
   }
 
-  AllocatorTy &getAllocator() { return Allocator; }
-  const AllocatorTy &getAllocator() const { return Allocator; }
+  using AllocTy::getAllocator;
 
   using key_type = const char *;
   using mapped_type = ValueTy;
@@ -236,18 +236,29 @@
   /// lookup - Return the entry for the specified key, or a default
   /// constructed value if no such entry exists.
   ValueTy lookup(std::string_view Key) const {
-    const_iterator it = find(Key);
-    if (it != end())
-      return it->second;
+    const_iterator Iter = find(Key);
+    if (Iter != end())
+      return Iter->second;
     return ValueTy();
   }
 
+  /// at - Return the entry for the specified key, or abort if no such
+  /// entry exists.
+  const ValueTy &at(std::string_view Val) const {
+    auto Iter = this->find(std::move(Val));
+    assert(Iter != this->end() && "StringMap::at failed due to a missing key");
+    return Iter->second;
+  }
+
   /// Lookup the ValueTy for the \p Key, or create a default constructed value
   /// if the key is not in the map.
   ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
 
+  /// contains - Return true if the element is in the map, false otherwise.
+  bool contains(std::string_view Key) const { return find(Key) != end(); }
+
   /// count - Return 1 if the element is in the map, 0 otherwise.
-  size_type count(std::string_view Key) const { return find(Key) == end() ? 0 : 1; }
+  size_type count(std::string_view Key) const { return contains(Key) ? 1 : 0; }
 
   template <typename InputTy>
   size_type count(const StringMapEntry<InputTy> &MapEntry) const {
@@ -331,7 +342,7 @@
   /// if and only if the insertion takes place, and the iterator component of
   /// the pair points to the element with key equivalent to the key of the pair.
   template <typename... ArgsTy>
-  std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&... Args) {
+  std::pair<iterator, bool> try_emplace(std::string_view Key, ArgsTy &&...Args) {
     unsigned BucketNo = LookupBucketFor(Key);
     StringMapEntryBase *&Bucket = TheTable[BucketNo];
     if (Bucket && Bucket != getTombstoneVal())
@@ -340,7 +351,8 @@
 
     if (Bucket == getTombstoneVal())
       --NumTombstones;
-    Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
+    Bucket =
+        MapEntryTy::create(Key, getAllocator(), std::forward<ArgsTy>(Args)...);
     ++NumItems;
     assert(NumItems + NumTombstones <= NumBuckets);
 
@@ -358,7 +370,7 @@
     for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
       StringMapEntryBase *&Bucket = TheTable[I];
       if (Bucket && Bucket != getTombstoneVal()) {
-        static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
+        static_cast<MapEntryTy *>(Bucket)->Destroy(getAllocator());
       }
       Bucket = nullptr;
     }
@@ -374,7 +386,7 @@
   void erase(iterator I) {
     MapEntryTy &V = *I;
     remove(&V);
-    V.Destroy(Allocator);
+    V.Destroy(getAllocator());
   }
 
   bool erase(std::string_view Key) {
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
index 2b33aa6..88de972 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
@@ -77,7 +77,7 @@
   explicit StringMapEntryStorage(size_t keyLength)
       : StringMapEntryBase(keyLength), second() {}
   template <typename... InitTy>
-  StringMapEntryStorage(size_t keyLength, InitTy &&... initVals)
+  StringMapEntryStorage(size_t keyLength, InitTy &&...initVals)
       : StringMapEntryBase(keyLength),
         second(std::forward<InitTy>(initVals)...) {}
   StringMapEntryStorage(StringMapEntryStorage &e) = delete;
@@ -88,9 +88,11 @@
   void setValue(const ValueTy &V) { second = V; }
 };
 
-template <> class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
+template <>
+class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
 public:
-  explicit StringMapEntryStorage(size_t keyLength, std::nullopt_t = std::nullopt)
+  explicit StringMapEntryStorage(size_t keyLength,
+                                 std::nullopt_t = std::nullopt)
       : StringMapEntryBase(keyLength) {}
   StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
 
@@ -105,6 +107,8 @@
 public:
   using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
 
+  using ValueType = ValueTy;
+
   std::string_view getKey() const {
     return std::string_view(getKeyData(), this->getKeyLength());
   }
@@ -123,7 +127,7 @@
   /// Create a StringMapEntry for the specified key construct the value using
   /// \p InitiVals.
   template <typename AllocatorTy, typename... InitTy>
-  static StringMapEntry *Create(std::string_view key, AllocatorTy &allocator,
+  static StringMapEntry *create(std::string_view key, AllocatorTy &allocator,
                                 InitTy &&... initVals) {
     return new (StringMapEntryBase::allocateWithKey(
         sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
@@ -148,6 +152,26 @@
   }
 };
 
+// Allow structured bindings on StringMapEntry.
+template <std::size_t Index, typename ValueTy>
+decltype(auto) get(const StringMapEntry<ValueTy> &E) {
+  static_assert(Index < 2);
+  if constexpr (Index == 0)
+    return E.first();
+  else
+    return E.second;
+}
+
 } // end namespace wpi
 
+namespace std {
+template <typename ValueTy>
+struct tuple_size<wpi::StringMapEntry<ValueTy>>
+    : std::integral_constant<std::size_t, 2> {};
+
+template <std::size_t I, typename ValueTy>
+struct tuple_element<I, wpi::StringMapEntry<ValueTy>>
+    : std::conditional<I == 0, std::string_view, ValueTy> {};
+} // namespace std
+
 #endif // WPIUTIL_WPI_STRINGMAPENTRY_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
index ab2791a..af7fcf9 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
@@ -14,12 +14,10 @@
 #ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
 #define WPIUTIL_WPI_SWAPBYTEORDER_H
 
+#include "wpi/bit.h"
 #include <cstddef>
 #include <cstdint>
 #include <type_traits>
-#if defined(_MSC_VER) && !defined(_DEBUG)
-#include <stdlib.h>
-#endif
 
 #if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) ||            \
     defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
@@ -48,48 +46,6 @@
 
 namespace wpi {
 
-/// ByteSwap_16 - This function returns a byte-swapped representation of
-/// the 16-bit argument.
-inline uint16_t ByteSwap_16(uint16_t value) {
-#if defined(_MSC_VER) && !defined(_DEBUG)
-  // The DLL version of the runtime lacks these functions (bug!?), but in a
-  // release build they're replaced with BSWAP instructions anyway.
-  return _byteswap_ushort(value);
-#else
-  uint16_t Hi = value << 8;
-  uint16_t Lo = value >> 8;
-  return Hi | Lo;
-#endif
-}
-
-/// This function returns a byte-swapped representation of the 32-bit argument.
-inline uint32_t ByteSwap_32(uint32_t value) {
-#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
-  return __builtin_bswap32(value);
-#elif defined(_MSC_VER) && !defined(_DEBUG)
-  return _byteswap_ulong(value);
-#else
-  uint32_t Byte0 = value & 0x000000FF;
-  uint32_t Byte1 = value & 0x0000FF00;
-  uint32_t Byte2 = value & 0x00FF0000;
-  uint32_t Byte3 = value & 0xFF000000;
-  return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
-#endif
-}
-
-/// This function returns a byte-swapped representation of the 64-bit argument.
-inline uint64_t ByteSwap_64(uint64_t value) {
-#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
-  return __builtin_bswap64(value);
-#elif defined(_MSC_VER) && !defined(_DEBUG)
-  return _byteswap_uint64(value);
-#else
-  uint64_t Hi = ByteSwap_32(uint32_t(value));
-  uint32_t Lo = ByteSwap_32(uint32_t(value >> 32));
-  return (Hi << 32) | Lo;
-#endif
-}
-
 namespace sys {
 
 #if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
@@ -100,33 +56,21 @@
 
 static const bool IsLittleEndianHost = !IsBigEndianHost;
 
-inline unsigned char  getSwappedBytes(unsigned char C) { return C; }
-inline   signed char  getSwappedBytes(signed char C) { return C; }
-inline          char  getSwappedBytes(char C) { return C; }
+inline unsigned char      getSwappedBytes(unsigned char      C) { return wpi::byteswap(C); }
+inline   signed char      getSwappedBytes( signed  char      C) { return wpi::byteswap(C); }
+inline          char      getSwappedBytes(         char      C) { return wpi::byteswap(C); }
 
-inline unsigned short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); }
-inline   signed short getSwappedBytes(  signed short C) { return ByteSwap_16(C); }
+inline unsigned short     getSwappedBytes(unsigned short     C) { return wpi::byteswap(C); }
+inline   signed short     getSwappedBytes(  signed short     C) { return wpi::byteswap(C); }
 
-inline unsigned int   getSwappedBytes(unsigned int   C) { return ByteSwap_32(C); }
-inline   signed int   getSwappedBytes(  signed int   C) { return ByteSwap_32(C); }
+inline unsigned int       getSwappedBytes(unsigned int       C) { return wpi::byteswap(C); }
+inline   signed int       getSwappedBytes(  signed int       C) { return wpi::byteswap(C); }
 
-inline unsigned long getSwappedBytes(unsigned long C) {
-  // Handle LLP64 and LP64 platforms.
-  return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
-                                     : ByteSwap_64((uint64_t)C);
-}
-inline signed long getSwappedBytes(signed long C) {
-  // Handle LLP64 and LP64 platforms.
-  return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
-                                     : ByteSwap_64((uint64_t)C);
-}
+inline unsigned long      getSwappedBytes(unsigned long      C) { return wpi::byteswap(C); }
+inline   signed long      getSwappedBytes(  signed long      C) { return wpi::byteswap(C); }
 
-inline unsigned long long getSwappedBytes(unsigned long long C) {
-  return ByteSwap_64(C);
-}
-inline signed long long getSwappedBytes(signed long long C) {
-  return ByteSwap_64(C);
-}
+inline unsigned long long getSwappedBytes(unsigned long long C) { return wpi::byteswap(C); }
+inline   signed long long getSwappedBytes(  signed long long C) { return wpi::byteswap(C); }
 
 inline float getSwappedBytes(float C) {
   union {
@@ -134,7 +78,7 @@
     float f;
   } in, out;
   in.f = C;
-  out.i = ByteSwap_32(in.i);
+  out.i = wpi::byteswap(in.i);
   return out.f;
 }
 
@@ -144,14 +88,14 @@
     double d;
   } in, out;
   in.d = C;
-  out.i = ByteSwap_64(in.i);
+  out.i = wpi::byteswap(in.i);
   return out.d;
 }
 
 template <typename T>
-inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
+inline std::enable_if_t<std::is_enum_v<T>, T> getSwappedBytes(T C) {
   return static_cast<T>(
-      getSwappedBytes(static_cast<std::underlying_type_t<T>>(C)));
+      wpi::byteswap(static_cast<std::underlying_type_t<T>>(C)));
 }
 
 template<typename T>
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
index c08ff37..02f24dd 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
@@ -16,11 +16,14 @@
 
 #include "wpi/DenseMapInfo.h"
 #include "wpi/Hashing.h"
+#include "wpi/Endian.h"
 #include <optional>
 #include <string>
 #include <tuple>
 
 namespace wpi {
+template <typename HasherT, support::endianness Endianness>
+class HashBuilderImpl;
 class raw_ostream;
 
 /// Represents a version number in the form major[.minor[.subminor[.build]]].
@@ -37,24 +40,25 @@
   unsigned HasBuild : 1;
 
 public:
-  VersionTuple()
+  constexpr VersionTuple()
       : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
         Build(0), HasBuild(false) {}
 
-  explicit VersionTuple(unsigned Major)
+  explicit constexpr VersionTuple(unsigned Major)
       : Major(Major), Minor(0), HasMinor(false), Subminor(0),
         HasSubminor(false), Build(0), HasBuild(false) {}
 
-  explicit VersionTuple(unsigned Major, unsigned Minor)
+  explicit constexpr VersionTuple(unsigned Major, unsigned Minor)
       : Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
         HasSubminor(false), Build(0), HasBuild(false) {}
 
-  explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
+  explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
+                                  unsigned Subminor)
       : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
         HasSubminor(true), Build(0), HasBuild(false) {}
 
-  explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
-                        unsigned Build)
+  explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
+                                  unsigned Subminor, unsigned Build)
       : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
         HasSubminor(true), Build(Build), HasBuild(true) {}
 
@@ -95,6 +99,12 @@
     return *this;
   }
 
+  /// Return a version tuple that contains a different major version but
+  /// everything else is the same.
+  VersionTuple withMajorReplaced(unsigned NewMajor) const {
+    return VersionTuple(NewMajor, Minor, Subminor, Build);
+  }
+
   /// Return a version tuple that contains only components that are non-zero.
   VersionTuple normalize() const {
     VersionTuple Result = *this;
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/bit.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/bit.h
new file mode 100644
index 0000000..fce6d85
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/bit.h
@@ -0,0 +1,99 @@
+//===-- llvm/ADT/bit.h - C++20 <bit> ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the C++20 <bit> header.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_BIT_H
+#define WPIUTIL_WPI_BIT_H
+
+#include "wpi/Compiler.h"
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#if !__has_builtin(__builtin_bit_cast)
+#include <cstring>
+#endif
+
+#if defined(_MSC_VER) && !defined(_DEBUG)
+#include <cstdlib>  // for _byteswap_{ushort,ulong,uint64}
+#endif
+
+namespace wpi {
+
+// This implementation of bit_cast is different from the C++20 one in two ways:
+//  - It isn't constexpr because that requires compiler support.
+//  - It requires trivially-constructible To, to avoid UB in the implementation.
+template <
+    typename To, typename From,
+    typename = std::enable_if_t<sizeof(To) == sizeof(From)>,
+    typename = std::enable_if_t<std::is_trivially_constructible<To>::value>,
+    typename = std::enable_if_t<std::is_trivially_copyable<To>::value>,
+    typename = std::enable_if_t<std::is_trivially_copyable<From>::value>>
+[[nodiscard]] inline To bit_cast(const From &from) noexcept {
+#if __has_builtin(__builtin_bit_cast)
+  return __builtin_bit_cast(To, from);
+#else
+  To to;
+  std::memcpy(&to, &from, sizeof(To));
+  return to;
+#endif
+}
+
+/// Reverses the bytes in the given integer value V.
+template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+[[nodiscard]] constexpr T byteswap(T V) noexcept {
+  if constexpr (sizeof(T) == 1) {
+    return V;
+  } else if constexpr (sizeof(T) == 2) {
+    uint16_t UV = V;
+#if defined(_MSC_VER) && !defined(_DEBUG)
+    // The DLL version of the runtime lacks these functions (bug!?), but in a
+    // release build they're replaced with BSWAP instructions anyway.
+    return _byteswap_ushort(UV);
+#else
+    uint16_t Hi = UV << 8;
+    uint16_t Lo = UV >> 8;
+    return Hi | Lo;
+#endif
+  } else if constexpr (sizeof(T) == 4) {
+    uint32_t UV = V;
+#if __has_builtin(__builtin_bswap32)
+    return __builtin_bswap32(UV);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+    return _byteswap_ulong(UV);
+#else
+    uint32_t Byte0 = UV & 0x000000FF;
+    uint32_t Byte1 = UV & 0x0000FF00;
+    uint32_t Byte2 = UV & 0x00FF0000;
+    uint32_t Byte3 = UV & 0xFF000000;
+    return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
+#endif
+  } else if constexpr (sizeof(T) == 8) {
+    uint64_t UV = V;
+#if __has_builtin(__builtin_bswap64)
+    return __builtin_bswap64(UV);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+    return _byteswap_uint64(UV);
+#else
+    uint64_t Hi = wpi::byteswap<uint32_t>(UV);
+    uint32_t Lo = wpi::byteswap<uint32_t>(UV >> 32);
+    return (Hi << 32) | Lo;
+#endif
+  } else {
+    static_assert(!sizeof(T *), "Don't know how to handle the given type.");
+    return 0;
+  }
+}
+
+} // namespace wpi
+
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
index ce0e4ee..afb7343 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
@@ -18,10 +18,22 @@
 #ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
 #define WPIUTIL_WPI_ITERATOR_RANGE_H
 
+#include "wpi/ADL.h"
+#include <type_traits>
 #include <utility>
 
 namespace wpi {
 
+template <typename From, typename To, typename = void>
+struct explicitly_convertible : std::false_type {};
+
+template <typename From, typename To>
+struct explicitly_convertible<
+    From, To,
+    std::void_t<decltype(static_cast<To>(
+        std::declval<std::add_rvalue_reference_t<From>>()))>> : std::true_type {
+};
+
 /// A range adaptor for a pair of iterators.
 ///
 /// This just wraps two iterators into a range-compatible interface. Nothing
@@ -31,12 +43,19 @@
   IteratorT begin_iterator, end_iterator;
 
 public:
-  //TODO: Add SFINAE to test that the Container's iterators match the range's
-  //      iterators.
+#if __GNUC__ == 7
+  // Be careful no to break gcc-7 on the mlir target.
+  // See https://github.com/llvm/llvm-project/issues/63843
   template <typename Container>
+#else
+  template <typename Container,
+            std::enable_if_t<explicitly_convertible<
+                detail::IterOfRange<Container>, IteratorT>::value> * = nullptr>
+#endif
   iterator_range(Container &&c)
-  //TODO: Consider ADL/non-member begin/end calls.
-      : begin_iterator(c.begin()), end_iterator(c.end()) {}
+      : begin_iterator(adl_begin(std::forward<Container>(c))),
+        end_iterator(adl_end(std::forward<Container>(c))) {
+  }
   iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
       : begin_iterator(std::move(begin_iterator)),
         end_iterator(std::move(end_iterator)) {}
@@ -46,6 +65,9 @@
   bool empty() const { return begin_iterator == end_iterator; }
 };
 
+template <typename Container>
+iterator_range(Container &&) -> iterator_range<detail::IterOfRange<Container>>;
+
 /// Convenience function for iterating over sub-ranges.
 ///
 /// This provides a bit of syntactic sugar to make using sub-ranges
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
index 350262b..06ff206 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
@@ -14,15 +14,14 @@
 #define WPIUTIL_WPI_RAW_OSTREAM_H
 
 #include "wpi/SmallVector.h"
-#include <span>
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <optional>
+#include <span>
 #include <string>
-#if __cplusplus > 201402L
 #include <string_view>
-#endif
 #include <system_error>
 #include <type_traits>
 #include <vector>
@@ -229,6 +228,20 @@
     return *this;
   }
 
+#if defined(__cpp_char8_t)
+  // When using `char8_t *` integers or pointers are written to the ostream
+  // instead of UTF-8 code as one might expect. This might lead to unexpected
+  // behavior, especially as `u8""` literals are of type `char8_t*` instead of
+  // type `char_t*` from C++20 onwards. Thus we disallow using them with
+  // raw_ostreams.
+  // If you have u8"" literals to stream, you can rewrite them as ordinary
+  // literals with escape sequences
+  // e.g.  replace `u8"\u00a0"` by `"\xc2\xa0"`
+  // or use `reinterpret_cast`:
+  // e.g. replace `u8"\u00a0"` by `reinterpret_cast<const char *>(u8"\u00a0")`
+  raw_ostream &operator<<(const char8_t *Str) = delete;
+#endif
+
   raw_ostream &operator<<(const char *Str) {
     // Inline fast path, particularly for constant strings where a sufficiently
     // smart compiler will simplify strlen.
@@ -343,6 +356,11 @@
     SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
   }
 
+  /// Force-set the number of bytes in the raw_ostream buffer.
+  void SetNumBytesInBuffer(size_t Size) {
+    OutBufCur = OutBufStart + Size;
+  }
+
   /// Return an efficient buffer size for the underlying output mechanism.
   virtual size_t preferred_buffer_size() const;
 
@@ -374,8 +392,8 @@
 /// Call the appropriate insertion operator, given an rvalue reference to a
 /// raw_ostream object and return a stream of the same type as the argument.
 template <typename OStream, typename T>
-std::enable_if_t<!std::is_reference<OStream>::value &&
-                     std::is_base_of<raw_ostream, OStream>::value,
+std::enable_if_t<!std::is_reference_v<OStream> &&
+                     std::is_base_of_v<raw_ostream, OStream>,
                  OStream &&>
 operator<<(OStream &&OS, const T &Value) {
   OS << Value;
@@ -734,7 +752,7 @@
   raw_ostream &OS;
   SmallVector<char, 0> Buffer;
 
-  virtual void anchor() override;
+  void anchor() override;
 
 public:
   buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
@@ -745,7 +763,7 @@
   std::unique_ptr<raw_ostream> OS;
   SmallVector<char, 0> Buffer;
 
-  virtual void anchor() override;
+  void anchor() override;
 
 public:
   buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
index 53e18d3..d74fd0f 100644
--- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
@@ -32,11 +32,11 @@
 
 public:
   static const bool value =
-      !std::is_class<UnderlyingT>::value && // Filter conversion operators.
-      !std::is_pointer<UnderlyingT>::value &&
-      !std::is_floating_point<UnderlyingT>::value &&
-      (std::is_enum<UnderlyingT>::value ||
-       std::is_convertible<UnderlyingT, unsigned long long>::value);
+      !std::is_class_v<UnderlyingT> && // Filter conversion operators.
+      !std::is_pointer_v<UnderlyingT> &&
+      !std::is_floating_point_v<UnderlyingT> &&
+      (std::is_enum_v<UnderlyingT> ||
+       std::is_convertible_v<UnderlyingT, unsigned long long>);
 };
 
 /// If T is a pointer, just return it. If it is not, return T&.
@@ -45,7 +45,7 @@
 
 template <typename T>
 struct add_lvalue_reference_if_not_pointer<
-    T, std::enable_if_t<std::is_pointer<T>::value>> {
+    T, std::enable_if_t<std::is_pointer_v<T>>> {
   using type = T;
 };
 
@@ -55,7 +55,7 @@
 struct add_const_past_pointer { using type = const T; };
 
 template <typename T>
-struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
+struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer_v<T>>> {
   using type = const std::remove_pointer_t<T> *;
 };
 
@@ -64,27 +64,11 @@
   using type = const T &;
 };
 template <typename T>
-struct const_pointer_or_const_ref<T,
-                                  std::enable_if_t<std::is_pointer<T>::value>> {
+struct const_pointer_or_const_ref<T, std::enable_if_t<std::is_pointer_v<T>>> {
   using type = typename add_const_past_pointer<T>::type;
 };
 
 namespace detail {
-/// Internal utility to detect trivial copy construction.
-template<typename T> union copy_construction_triviality_helper {
-    T t;
-    copy_construction_triviality_helper() = default;
-    copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
-    ~copy_construction_triviality_helper() = default;
-};
-/// Internal utility to detect trivial move construction.
-template<typename T> union move_construction_triviality_helper {
-    T t;
-    move_construction_triviality_helper() = default;
-    move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
-    ~move_construction_triviality_helper() = default;
-};
-
 template<class T>
 union trivial_helper {
     T t;
@@ -92,13 +76,6 @@
 
 } // end namespace detail
 
-template <typename T>
-using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;
-
-template <typename T>
-using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
-
-
 } // end namespace wpi
 
 #endif // WPIUTIL_WPI_TYPE_TRAITS_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/xxhash.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/xxhash.h
new file mode 100644
index 0000000..e0284bc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/xxhash.h
@@ -0,0 +1,56 @@
+/*
+   xxHash - Extremely Fast Hash algorithm
+   Header File
+   Copyright (C) 2012-2016, Yann Collet.
+
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+       * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the
+   distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   You can contact the author at :
+   - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+/* based on revision d2df04efcbef7d7f6886d345861e5dfda4edacc1 Removed
+ * everything but a simple interface for computing XXh64. */
+
+#ifndef WPIUTIL_WPI_XXHASH_H
+#define WPIUTIL_WPI_XXHASH_H
+
+#include <stdint.h>
+
+#include <span>
+#include <string_view>
+
+namespace wpi {
+uint64_t xxHash64(std::string_view Data);
+uint64_t xxHash64(std::span<const uint8_t> Data);
+
+uint64_t xxh3_64bits(std::span<const uint8_t> data);
+inline uint64_t xxh3_64bits(std::string_view data) {
+  return xxh3_64bits(std::span(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+}
+}
+
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/aligned_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/aligned_allocator.hpp
index 8118ec4..3083a40 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/aligned_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/aligned_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_ALIGNED_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_ALIGNED_ALLOCATOR_HPP_INCLUDED
@@ -52,7 +51,7 @@
             aligned_allocator& operator=(aligned_allocator&& other) noexcept
             {
                 allocator_type::operator=(detail::move(other));
-                min_alignment_          = other.min_alignment_;
+                min_alignment_ = other.min_alignment_;
                 return *this;
             }
             /// @}
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_storage.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_storage.hpp
index 8dab2e0..dc90672 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_storage.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_storage.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_ALLOCATOR_STORAGE_HPP_INCLUDED
 #define WPI_MEMORY_ALLOCATOR_STORAGE_HPP_INCLUDED
@@ -126,7 +125,7 @@
                 WPI_REQUIRES(
                     (!std::is_base_of<allocator_storage, typename std::decay<Alloc>::type>::value))>
             allocator_storage(Alloc&& alloc,
-                              WPI_SFINAE(new storage_policy(detail::forward<Alloc>(alloc))))
+                              WPI_SFINAE(new storage_policy(std::declval<Alloc>())))
             : storage_policy(detail::forward<Alloc>(alloc))
             {
             }
@@ -136,8 +135,10 @@
             /// \requires The expression <tt>new storage_policy(other.get_allocator())</tt> must be well-formed,
             /// otherwise this constructor does not participate in overload resolution.
             template <class OtherPolicy>
-            allocator_storage(const allocator_storage<OtherPolicy, Mutex>& other,
-                              WPI_SFINAE(new storage_policy(other.get_allocator())))
+            allocator_storage(
+                const allocator_storage<OtherPolicy, Mutex>& other,
+                WPI_SFINAE(new storage_policy(
+                    std::declval<const allocator_storage<OtherPolicy, Mutex>&>().get_allocator())))
             : storage_policy(other.get_allocator())
             {
             }
@@ -165,7 +166,7 @@
             /// @{
             /// \effects Copies the \c allocator_storage object.
             /// \requires The \c StoragePolicy must be copyable.
-            allocator_storage(const allocator_storage&) = default;
+            allocator_storage(const allocator_storage&)            = default;
             allocator_storage& operator=(const allocator_storage&) = default;
             /// @}
 
@@ -296,9 +297,9 @@
                 return detail::lock_allocator(get_allocator(), static_cast<actual_mutex&>(*this));
             }
 
-            auto lock() const noexcept -> WPI_IMPL_DEFINED(decltype(
-                detail::lock_allocator(std::declval<const storage_policy>().get_allocator(),
-                                       std::declval<actual_mutex&>())))
+            auto lock() const noexcept -> WPI_IMPL_DEFINED(decltype(detail::lock_allocator(
+                std::declval<const storage_policy>().get_allocator(),
+                std::declval<actual_mutex&>())))
             {
                 return detail::lock_allocator(get_allocator(), static_cast<actual_mutex&>(*this));
             }
@@ -552,9 +553,9 @@
         {
             using storage = detail::reference_storage_impl<
                 typename allocator_traits<RawAllocator>::allocator_type,
-                decltype(
-                    detail::reference_type(typename allocator_traits<RawAllocator>::is_stateful{},
-                                           is_shared_allocator<RawAllocator>{}))>;
+                decltype(detail::reference_type(typename allocator_traits<
+                                                    RawAllocator>::is_stateful{},
+                                                is_shared_allocator<RawAllocator>{}))>;
 
         public:
             using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
@@ -580,7 +581,7 @@
             /// @{
             /// \effects Copies the \c allocator_reference object.
             /// Only copies the pointer to it in the stateful case.
-            reference_storage(const reference_storage&) noexcept = default;
+            reference_storage(const reference_storage&) noexcept            = default;
             reference_storage& operator=(const reference_storage&) noexcept = default;
             /// @}
 
@@ -795,9 +796,9 @@
             : public base_allocator,
               private detail::reference_storage_impl<
                   typename allocator_traits<RawAllocator>::allocator_type,
-                  decltype(
-                      detail::reference_type(typename allocator_traits<RawAllocator>::is_stateful{},
-                                             is_shared_allocator<RawAllocator>{}))>
+                  decltype(detail::reference_type(typename allocator_traits<
+                                                      RawAllocator>::is_stateful{},
+                                                  is_shared_allocator<RawAllocator>{}))>
             {
                 using traits     = allocator_traits<RawAllocator>;
                 using composable = is_composable_allocator<typename traits::allocator_type>;
@@ -805,7 +806,7 @@
                     typename allocator_traits<RawAllocator>::allocator_type,
                     decltype(detail::reference_type(typename allocator_traits<
                                                         RawAllocator>::is_stateful{},
-                                                    is_shared_allocator<RawAllocator>{}))>;
+                                                       is_shared_allocator<RawAllocator>{}))>;
 
             public:
                 // non stateful
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_traits.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_traits.hpp
index 47b6ffb..0e23c63 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_traits.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_traits.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED
 #define WPI_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED
@@ -375,12 +374,12 @@
 
             template <typename T>
             struct has_invalid_alloc_function
-            : std::is_same<decltype(
-                               traits_detail::allocate_node(traits_detail::full_concept{},
-                                                            std::declval<typename allocator_traits<
-                                                                T>::allocator_type&>(),
-                                                            0, 0)),
-                           traits_detail::error>
+            : std::is_same<
+                  decltype(traits_detail::allocate_node(traits_detail::full_concept{},
+                                                        std::declval<typename allocator_traits<
+                                                            T>::allocator_type&>(),
+                                                        0, 0)),
+                  traits_detail::error>
             {
             };
 
@@ -564,13 +563,12 @@
 
             template <typename T>
             struct has_invalid_try_dealloc_function
-            : std::is_same<
-                  decltype(
-                      traits_detail::try_deallocate_node(traits_detail::full_concept{},
-                                                         std::declval<typename allocator_traits<
-                                                             T>::allocator_type&>(),
-                                                         nullptr, 0, 0)),
-                  traits_detail::error>
+            : std::is_same<decltype(traits_detail::
+                                        try_deallocate_node(traits_detail::full_concept{},
+                                                            std::declval<typename allocator_traits<
+                                                                T>::allocator_type&>(),
+                                                            nullptr, 0, 0)),
+                           traits_detail::error>
             {
             };
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config.hpp
index 067ecd2..40681bd 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 /// \file
 /// Configuration macros.
@@ -140,7 +139,7 @@
 /// Set to `1` to disable automatic lifetime managment of the per-thread stack,
 /// requires managing it through the \ref wpi::memory::temporary_stack_initializer.
 /// Set to `0` to disable the per-thread stack completely.
-/// \ref get_temporary_stack() will abort the program upon call.
+/// \ref wpi::memory::get_temporary_stack() will abort the program upon call.
 /// \ingroup allocator
 #define WPI_MEMORY_TEMPORARY_STACK_MODE 2
 #endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/container.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/container.hpp
index fd1547f..8f8eee5 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/container.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/container.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_CONTAINER_HPP_INCLUDED
 #define WPI_MEMORY_CONTAINER_HPP_INCLUDED
@@ -276,8 +275,9 @@
         /// @{
 
         /// Contains the node size of a node based STL container with a specific type.
-        /// These classes are auto-generated and only available if the tools are build and without
-        /// cross-compiling.
+        ///
+        /// This trait is auto-generated and may not be available depending on the build configuration,
+        /// especially when doing cross compilation.
         template <typename T>
         struct forward_list_node_size : std::integral_constant<std::size_t, implementation_defined>
         {
@@ -314,25 +314,30 @@
         {
         };
 
-        /// \copydoc forward_list_node_size
+        /// Contains the node size of a node based STL container with a specific type.
+        ///
+        /// This trait is auto-generated and may not be available depending on the build configuration,
+        /// especially when doing cross compilation.
+        ///
+        /// \notes `T` is always the `value_type` of the container, e.g. `std::pair<const Key, Value>`.
         template <typename T>
         struct map_node_size : std::integral_constant<std::size_t, implementation_defined>
         {
         };
 
-        /// \copydoc forward_list_node_size
+        /// \copydoc map_node_size
         template <typename T>
         struct multimap_node_size : std::integral_constant<std::size_t, implementation_defined>
         {
         };
 
-        /// \copydoc forward_list_node_size
+        /// \copydoc map_node_size
         template <typename T>
         struct unordered_map_node_size : std::integral_constant<std::size_t, implementation_defined>
         {
         };
 
-        /// \copydoc forward_list_node_size
+        /// \copydoc map_node_size
         template <typename T>
         struct unordered_multimap_node_size
         : std::integral_constant<std::size_t, implementation_defined>
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/debugging.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/debugging.hpp
index b04050f..580696a 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/debugging.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/debugging.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DEBUGGING_HPP_INCLUDED
 #define WPI_MEMORY_DEBUGGING_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/default_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/default_allocator.hpp
index 107a641..4d78abb 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/default_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/default_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DEFAULT_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_DEFAULT_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/deleter.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/deleter.hpp
index 01c967c..dd0298b 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/deleter.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/deleter.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DELETER_HPP_INCLUDED
 #define WPI_MEMORY_DELETER_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/align.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/align.hpp
index 99d6bcc..5a06340 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/align.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/align.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_ALIGN_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_ALIGN_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/assert.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/assert.hpp
index b8a7372..620d07b 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/assert.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/assert.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_ASSERT_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_ASSERT_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/container_node_sizes.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/container_node_sizes.hpp
index 37949ca..34d6d65 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/container_node_sizes.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/container_node_sizes.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_CONTAINER_NODE_SIZES_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_CONTAINER_NODE_SIZES_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/debug_helpers.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/debug_helpers.hpp
index 3ef2eed..1decb72 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/debug_helpers.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/debug_helpers.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DEBUG_HELPERS_HPP_INCLUDED
 #define WPI_MEMORY_DEBUG_HELPERS_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ebo_storage.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ebo_storage.hpp
index de53f7f..640d844 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ebo_storage.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ebo_storage.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_EBO_STORAGE_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_EBO_STORAGE_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list.hpp
index 612706d..4c91324 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAILL_FREE_LIST_HPP_INCLUDED
 #define WPI_MEMORY_DETAILL_FREE_LIST_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list_array.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list_array.hpp
index ec57e1e..17cd1fa 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list_array.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list_array.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_FREE_LIST_ARRAY_HPP
 #define WPI_MEMORY_DETAIL_FREE_LIST_ARRAY_HPP
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ilog2.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ilog2.hpp
index 5cf125a..eb4e4f3 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ilog2.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ilog2.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_ILOG2_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_ILOG2_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/lowlevel_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/lowlevel_allocator.hpp
index 2ac45a5..beb8c36 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/lowlevel_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/lowlevel_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_LOWLEVEL_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_LOWLEVEL_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/memory_stack.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/memory_stack.hpp
index e49d480..3d38dba 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/memory_stack.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/memory_stack.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/small_free_list.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/small_free_list.hpp
index 682417d..1ea31fc 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/small_free_list.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/small_free_list.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_SMALL_FREE_LIST_HPP_INCLUDED
 #define WPI_MEMORY_DETAIL_SMALL_FREE_LIST_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/utility.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/utility.hpp
index c746fa2..b33aa16 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/utility.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/utility.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_DETAIL_UTILITY_HPP
 #define WPI_MEMORY_DETAIL_UTILITY_HPP
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/error.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/error.hpp
index 5ff99cf..3d2f2fa 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/error.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/error.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 /// \file
 /// The exception classes.
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/fallback_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/fallback_allocator.hpp
index 3bf530e..456e84e 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/fallback_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/fallback_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_FALLBACK_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_FALLBACK_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/heap_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/heap_allocator.hpp
index 0724937..803a705 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/heap_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/heap_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_HEAP_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_HEAP_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/iteration_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/iteration_allocator.hpp
index d35a927..fafb72c 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/iteration_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/iteration_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_ITERATION_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_ITERATION_ALLOCATOR_HPP_INCLUDED
@@ -77,8 +76,8 @@
             iteration_allocator& operator=(iteration_allocator&& other) noexcept
             {
                 allocator_type::operator=(detail::move(other));
-                block_                  = other.block_;
-                cur_                    = other.cur_;
+                block_ = other.block_;
+                cur_   = other.cur_;
 
                 for (auto i = 0u; i != N; ++i)
                     stacks_[i] = detail::move(other.stacks_[i]);
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/joint_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/joint_allocator.hpp
index db67d46..540bbd1 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/joint_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/joint_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_JOINT_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_JOINT_ALLOCATOR_HPP_INCLUDED
@@ -515,7 +514,7 @@
             {
             }
 
-            joint_allocator(const joint_allocator& other) noexcept = default;
+            joint_allocator(const joint_allocator& other) noexcept            = default;
             joint_allocator& operator=(const joint_allocator& other) noexcept = default;
 
             /// \effects Allocates a node with given properties.
@@ -709,7 +708,7 @@
             }
 
             joint_array& operator=(const joint_array&) = delete;
-            joint_array& operator=(joint_array&&) = delete;
+            joint_array& operator=(joint_array&&)      = delete;
 
             //=== accessors ===//
             /// @{
@@ -810,7 +809,7 @@
                         stack_->unwind(objects_);
                 }
 
-                builder(builder&&) = delete;
+                builder(builder&&)            = delete;
                 builder& operator=(builder&&) = delete;
 
                 template <typename... Args>
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/malloc_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/malloc_allocator.hpp
index 3be9820..a5da1f4 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/malloc_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/malloc_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MALLOC_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_MALLOC_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_arena.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_arena.hpp
index a634993..c4469e8 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_arena.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_arena.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
 #define WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
@@ -548,7 +547,7 @@
                 if (block_size_)
                 {
                     auto         mem = traits::allocate_array(get_allocator(), block_size_, 1,
-                                                      detail::max_alignment);
+                                                              detail::max_alignment);
                     memory_block block(mem, block_size_);
                     block_size_ = 0u;
                     return block;
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool.hpp
index 09c2b66..2823686 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MEMORY_POOL_HPP_INCLUDED
 #define WPI_MEMORY_MEMORY_POOL_HPP_INCLUDED
@@ -103,8 +102,8 @@
             memory_pool& operator=(memory_pool&& other) noexcept
             {
                 leak_checker::operator=(detail::move(other));
-                arena_                = detail::move(other.arena_);
-                free_list_            = detail::move(other.free_list_);
+                arena_     = detail::move(other.arena_);
+                free_list_ = detail::move(other.free_list_);
                 return *this;
             }
             /// @}
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_collection.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_collection.hpp
index 294dd0a..0bd0248 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_collection.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_collection.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MEMORY_POOL_COLLECTION_HPP_INCLUDED
 #define WPI_MEMORY_MEMORY_POOL_COLLECTION_HPP_INCLUDED
@@ -76,8 +75,7 @@
             /// the size of the initial memory block and other constructor arguments for the \concept{concept_blockallocator,BlockAllocator}.
             /// The \c BucketDistribution controls how many free lists are created,
             /// but unlike in \ref memory_pool all free lists are initially empty and the first memory block queued.
-            /// \requires \c max_node_size must be a valid \concept{concept_node,node} size
-            /// and \c block_size must be non-zero.
+            /// \requires \c block_size must be non-zero and \c max_node_size must be a valid \concept{concept_node,node} size and smaller than \c block_size divided by the number of pools.
             template <typename... Args>
             memory_pool_collection(std::size_t max_node_size, std::size_t block_size,
                                    Args&&... args)
@@ -85,6 +83,7 @@
               stack_(allocate_block()),
               pools_(stack_, block_end(), max_node_size)
             {
+                detail::check_allocation_size<bad_node_size>(max_node_size, def_capacity(), info());
             }
 
             /// \effects Destroys the \ref memory_pool_collection by returning all memory blocks,
@@ -107,9 +106,9 @@
             memory_pool_collection& operator=(memory_pool_collection&& other) noexcept
             {
                 leak_checker::operator=(detail::move(other));
-                arena_                = detail::move(other.arena_);
-                stack_                = detail::move(other.stack_);
-                pools_                = detail::move(other.pools_);
+                arena_ = detail::move(other.arena_);
+                stack_ = detail::move(other.stack_);
+                pools_ = detail::move(other.pools_);
                 return *this;
             }
             /// @}
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_type.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_type.hpp
index a7c8ff8..7ebe4a5 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_type.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_type.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MEMORY_POOL_TYPE_HPP_INCLUDED
 #define WPI_MEMORY_MEMORY_POOL_TYPE_HPP_INCLUDED
@@ -28,7 +27,7 @@
         };
 
         /// Tag type defining a memory pool optimized for arrays.
-        /// It keeps the nodes oredered inside the free list and searches the list for an appropriate memory block.
+        /// It keeps the nodes ordered inside the free list and searches the list for an appropriate memory block.
         /// Array allocations are still pretty slow, if the array gets big enough it can get slower than \c new.
         /// Node allocations are still fast, unless there is deallocation in random order.
         /// \note Use this tag type only if you really need to have a memory pool!
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_resource_adapter.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_resource_adapter.hpp
index e805f9b..8428bb2 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_resource_adapter.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_resource_adapter.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MEMORY_RESOURCE_ADAPTER_HPP_INCLUDED
 #define WPI_MEMORY_MEMORY_RESOURCE_ADAPTER_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_stack.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_stack.hpp
index 4c9f524..0c9d896 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_stack.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_stack.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_MEMORY_STACK_HPP_INCLUDED
 #define WPI_MEMORY_MEMORY_STACK_HPP_INCLUDED
@@ -203,7 +202,8 @@
                         arena_.deallocate_block();
 
                     detail::debug_check_pointer(
-                        [&] {
+                        [&]
+                        {
                             auto cur = arena_.current_block();
                             return m.end == static_cast<char*>(cur.memory) + cur.size;
                         },
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/namespace_alias.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/namespace_alias.hpp
index bf2b95d..4af20c1 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/namespace_alias.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/namespace_alias.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_NAMESPACE_ALIAS_HPP_INCLUDED
 #define WPI_MEMORY_NAMESPACE_ALIAS_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/new_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/new_allocator.hpp
index 8e24f2f..0beec00 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/new_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/new_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_NEW_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_NEW_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/segregator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/segregator.hpp
index fcd02ac..ae06f83 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/segregator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/segregator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_SEGREGATOR_HPP_INCLUDED
 #define WPI_MEMORY_SEGREGATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/smart_ptr.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/smart_ptr.hpp
index 877efd7..016f31b 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/smart_ptr.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/smart_ptr.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_SMART_PTR_HPP_INCLUDED
 #define WPI_MEMORY_SMART_PTR_HPP_INCLUDED
@@ -192,18 +191,6 @@
                                                detail::forward<RawAllocator>(alloc)),
                                            detail::forward<Args>(args)...);
         }
-
-#if !defined(DOXYGEN)
-#include "detail/container_node_sizes.hpp"
-#else
-        /// Contains the node size needed for a `std::shared_ptr`.
-        /// These classes are auto-generated and only available if the tools are build and without cross-compiling.
-        /// \ingroup adapter
-        template <typename T>
-        struct shared_ptr_node_size : std::integral_constant<std::size_t, implementation_defined>
-        {
-        };
-#endif
     } // namespace memory
 } // namespace wpi
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/static_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/static_allocator.hpp
index efbbf73..33242f9 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/static_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/static_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_STATIC_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_STATIC_ALLOCATOR_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/std_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/std_allocator.hpp
index f727a1c..18262eb 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/std_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/std_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
@@ -134,7 +133,8 @@
                 // MSVC seems to ignore access rights in decltype SFINAE below
                 // use this to prevent this constructor being chosen instead of move/copy for types inheriting from it
                 WPI_REQUIRES((!std::is_base_of<std_allocator, RawAlloc>::value))>
-            std_allocator(RawAlloc& alloc, WPI_SFINAE(alloc_reference(alloc))) noexcept
+            std_allocator(RawAlloc& alloc,
+                          WPI_SFINAE(alloc_reference(std::declval<RawAlloc&>()))) noexcept
             : alloc_reference(alloc)
             {
             }
@@ -149,7 +149,8 @@
                 // MSVC seems to ignore access rights in decltype SFINAE below
                 // use this to prevent this constructor being chosen instead of move/copy for types inheriting from it
                 WPI_REQUIRES((!std::is_base_of<std_allocator, RawAlloc>::value))>
-            std_allocator(const RawAlloc& alloc, WPI_SFINAE(alloc_reference(alloc))) noexcept
+            std_allocator(const RawAlloc& alloc, WPI_SFINAE(alloc_reference(
+                                                     std::declval<const RawAlloc&>()))) noexcept
             : alloc_reference(alloc)
             {
             }
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/temporary_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/temporary_allocator.hpp
index 7eba76f..6d5d73f 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/temporary_allocator.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/temporary_allocator.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_TEMPORARY_ALLOCATOR_HPP_INCLUDED
 #define WPI_MEMORY_TEMPORARY_ALLOCATOR_HPP_INCLUDED
@@ -195,7 +194,7 @@
             /// \effects Destroys the per-thread stack if it isn't already destroyed.
             ~temporary_stack_initializer() noexcept;
 
-            temporary_stack_initializer(temporary_stack_initializer&&) = delete;
+            temporary_stack_initializer(temporary_stack_initializer&&)            = delete;
             temporary_stack_initializer& operator=(temporary_stack_initializer&&) = delete;
         };
 
@@ -229,7 +228,7 @@
 
             ~temporary_allocator() noexcept;
 
-            temporary_allocator(temporary_allocator&&) = delete;
+            temporary_allocator(temporary_allocator&&)            = delete;
             temporary_allocator& operator=(temporary_allocator&&) = delete;
 
             /// \effects Allocates memory from the internal \ref memory_stack by forwarding to it.
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/threading.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/threading.hpp
index 0314ea4..82629ec 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/threading.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/threading.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_THREADING_HPP_INCLUDED
 #define WPI_MEMORY_THREADING_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/tracking.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/tracking.hpp
index ccbc343..4742a4c 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/tracking.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/tracking.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_TRACKING_HPP_INCLUDED
 #define WPI_MEMORY_TRACKING_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/virtual_memory.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/virtual_memory.hpp
index 33d82f7..360ca78 100644
--- a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/virtual_memory.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/virtual_memory.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_VIRTUAL_MEMORY_HPP_INCLUDED
 #define WPI_MEMORY_VIRTUAL_MEMORY_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/debugging.cpp b/wpiutil/src/main/native/thirdparty/memory/src/debugging.cpp
index be1b033..f3ab89c 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/debugging.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/debugging.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/debugging.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp
index e1c4f2a..920e13f 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/detail/align.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp
index 497f7f8..d1d9028 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/detail/assert.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/debug_helpers.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/debug_helpers.cpp
index b5afb20..405c85f 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/debug_helpers.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/debug_helpers.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/detail/debug_helpers.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list.cpp
index 2ca7034..5ac3950 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/detail/free_list.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_array.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_array.cpp
index f4658da..3a103f5 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_array.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_array.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/detail/free_list_array.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_utils.hpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_utils.hpp
index a752837..106e129 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_utils.hpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_utils.hpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #ifndef WPI_MEMORY_SRC_DETAIL_FREE_LIST_UTILS_HPP_INCLUDED
 #define WPI_MEMORY_SRC_DETAIL_FREE_LIST_UTILS_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/small_free_list.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/small_free_list.cpp
index 3508daa..08be312 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/detail/small_free_list.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/small_free_list.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/detail/small_free_list.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/error.cpp b/wpiutil/src/main/native/thirdparty/memory/src/error.cpp
index 6261819..f5ef53c 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/error.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/error.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/error.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp
index 0f559bd..32d1236 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/heap_allocator.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp
index c174c13..411eba6 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/iteration_allocator.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp
index f54817a..f5783c7 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/config.hpp"
 #if WPI_HOSTED_IMPLEMENTATION
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/memory_arena.cpp b/wpiutil/src/main/native/thirdparty/memory/src/memory_arena.cpp
index d8454be..148ed31 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/memory_arena.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_arena.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/memory_arena.hpp"
 
@@ -42,7 +41,7 @@
     auto address = static_cast<const char*>(ptr);
     for (auto cur = head_; cur; cur = cur->prev)
     {
-        auto mem = static_cast<char*>(static_cast<void*>(cur));
+        auto mem = static_cast<char*>(static_cast<void*>(cur)) + implementation_offset();
         if (address >= mem && address < mem + cur->usable_size)
             return true;
     }
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp
index 5a5e5ab..47951be 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/memory_pool.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/memory_pool_collection.cpp b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool_collection.cpp
index 6366811..550f740 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/memory_pool_collection.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool_collection.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/memory_pool_collection.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp b/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp
index 8db5728..753cfe5 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/memory_stack.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp
index 2791182..d23edf5 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/new_allocator.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp
index 15a88bf..fbc12cc 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/static_allocator.hpp"
 
@@ -38,9 +37,9 @@
 
 void static_block_allocator::deallocate_block(memory_block block) noexcept
 {
-    detail::
-        debug_check_pointer([&] { return static_cast<char*>(block.memory) + block.size == cur_; },
-                            info(), block.memory);
+    detail::debug_check_pointer([&]
+                                { return static_cast<char*>(block.memory) + block.size == cur_; },
+                                info(), block.memory);
     cur_ -= block_size_;
 }
 
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp
index fa85e99..de4d7ed 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/temporary_allocator.hpp"
 
@@ -216,9 +215,8 @@
 
 namespace
 {
-    WPI_THREAD_LOCAL alignas(
-        temporary_stack) char temporary_stack_storage[sizeof(temporary_stack)];
-    WPI_THREAD_LOCAL bool is_created = false;
+    thread_local alignas(temporary_stack) char temporary_stack_storage[sizeof(temporary_stack)];
+    thread_local bool is_created = false;
 
     temporary_stack& get() noexcept
     {
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp b/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp
index fd7960f..1f54812 100644
--- a/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp
+++ b/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp
@@ -1,6 +1,5 @@
-// Copyright (C) 2015-2021 Müller <jonathanmueller.dev@gmail.com>
-// This file is subject to the license terms in the LICENSE file
-// found in the top-level directory of this distribution.
+// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
+// SPDX-License-Identifier: Zlib
 
 #include "wpi/memory/virtual_memory.hpp"
 
diff --git a/wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h b/wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
index 870c26b..504a7b0 100644
--- a/wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
+++ b/wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
@@ -24,7 +24,7 @@
  */
 
 /*
- * This is the MPack 1.1 amalgamation package.
+ * This is the MPack 1.1.1 amalgamation package.
  *
  * http://github.com/ludocode/mpack
  */
@@ -38,6 +38,11 @@
 #include "mpack-config.h"
 #endif
 
+/**
+ * @defgroup mpack MPack
+ * MPack is a C implementation of an encoder and decoder for the MessagePack
+ * serialization format.
+ */
 
 /* mpack/mpack-platform.h.h */
 
@@ -62,7 +67,8 @@
 
 
 /**
- * @defgroup config Configuration Options
+ * @defgroup mpack_config Configuration Options
+ * @ingroup mpack
  *
  * Defines the MPack configuration options.
  *
@@ -1880,7 +1886,8 @@
 
 
 /**
- * @defgroup common Tags and Common Elements
+ * @defgroup mpack_common Tags and Common Elements
+ * @ingroup mpack
  *
  * Contains types, constants and functions shared by both the encoding
  * and decoding portions of MPack.
@@ -1892,7 +1899,7 @@
 
 #define MPACK_VERSION_MAJOR 1  /**< The major version number of MPack. */
 #define MPACK_VERSION_MINOR 1  /**< The minor version number of MPack. */
-#define MPACK_VERSION_PATCH 0  /**< The patch version number of MPack. */
+#define MPACK_VERSION_PATCH 1  /**< The patch version number of MPack. */
 
 /** A number containing the version number of MPack for comparison purposes. */
 #define MPACK_VERSION ((MPACK_VERSION_MAJOR * 10000) + \
@@ -3056,7 +3063,8 @@
 #endif
 
 /**
- * @defgroup writer Write API
+ * @defgroup mpack_writer Write API
+ * @ingroup mpack
  *
  * The MPack Write API encodes structured data of a fixed (hardcoded) schema to MessagePack.
  *
@@ -3779,7 +3787,7 @@
 /**
  * Starts building an array.
  *
- * Elements must follow, and mpack_complete_map() must be called when done. The
+ * Elements must follow, and mpack_complete_array() must be called when done. The
  * number of elements is determined automatically.
  *
  * If you know ahead of time the number of elements in the array, it is more
@@ -4361,7 +4369,8 @@
 #define MPACK_READER_SMALL_FRACTION_DENOMINATOR 32
 
 /**
- * @defgroup reader Reader API
+ * @defgroup mpack_reader Reader API
+ * @ingroup mpack
  *
  * The MPack Reader API contains functions for imperatively reading dynamically
  * typed data from a MessagePack stream.
@@ -5303,7 +5312,8 @@
 #endif
 
 /**
- * @defgroup expect Expect API
+ * @defgroup mpack_expect Expect API
+ * @ingroup mpack
  *
  * The MPack Expect API allows you to easily read MessagePack data when you
  * expect it to follow a predefined schema.
@@ -6770,7 +6780,8 @@
 #if MPACK_NODE
 
 /**
- * @defgroup node Node API
+ * @defgroup mpack_node Node API
+ * @ingroup mpack
  *
  * The MPack Node API allows you to parse a chunk of MessagePack into a
  * dynamically typed data structure, providing random access to the parsed
@@ -7719,7 +7730,7 @@
  *
  * This returns zero if the tree is in an error state.
  *
- * If this node is not a str, bin or map, @ref mpack_error_type is raised and zero
+ * If this node is not a str, bin or ext, @ref mpack_error_type is raised and zero
  * is returned.
  */
 uint32_t mpack_node_data_len(mpack_node_t node);
@@ -7759,7 +7770,7 @@
  *
  * The pointer is valid as long as the data backing the tree is valid.
  *
- * If this node is not of a str, bin or map, @ref mpack_error_type is raised, and
+ * If this node is not of a str, bin or ext, @ref mpack_error_type is raised, and
  * @c NULL is returned.
  *
  * @see mpack_node_copy_cstr()
diff --git a/wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp b/wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
index af5fbd0..1c70ae2 100644
--- a/wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
+++ b/wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
@@ -24,7 +24,7 @@
  */
 
 /*
- * This is the MPack 1.1 amalgamation package.
+ * This is the MPack 1.1.1 amalgamation package.
  *
  * http://github.com/ludocode/mpack
  */
@@ -427,7 +427,7 @@
         const char* prefix, size_t prefix_size)
 {
     mpack_assert(mpack_tag_type(&tag) == mpack_type_bin);
-    size_t length = (size_t)mpack_snprintf(buffer, buffer_size, "<binary data of length %u", tag.v.l);
+    size_t length = (size_t)mpack_snprintf(buffer, buffer_size, "<binary data of length %" PRIu32 "", tag.v.l);
     mpack_tag_debug_complete_bin_ext(tag, length, buffer, buffer_size, prefix, prefix_size);
 }
 
@@ -436,7 +436,7 @@
         const char* prefix, size_t prefix_size)
 {
     mpack_assert(mpack_tag_type(&tag) == mpack_type_ext);
-    size_t length = (size_t)mpack_snprintf(buffer, buffer_size, "<ext data of type %i and length %u",
+    size_t length = (size_t)mpack_snprintf(buffer, buffer_size, "<ext data of type %i and length %" PRIu32 "",
             mpack_tag_ext_exttype(&tag), mpack_tag_ext_length(&tag));
     mpack_tag_debug_complete_bin_ext(tag, length, buffer, buffer_size, prefix, prefix_size);
 }
@@ -477,7 +477,7 @@
             return;
 
         case mpack_type_str:
-            mpack_snprintf(buffer, buffer_size, "<string of %u bytes>", tag.v.l);
+            mpack_snprintf(buffer, buffer_size, "<string of %" PRIu32 " bytes>", tag.v.l);
             return;
         case mpack_type_bin:
             mpack_tag_debug_pseudo_json_bin(tag, buffer, buffer_size, prefix, prefix_size);
@@ -489,10 +489,10 @@
         #endif
 
         case mpack_type_array:
-            mpack_snprintf(buffer, buffer_size, "<array of %u elements>", tag.v.n);
+            mpack_snprintf(buffer, buffer_size, "<array of %" PRIu32 " elements>", tag.v.n);
             return;
         case mpack_type_map:
-            mpack_snprintf(buffer, buffer_size, "<map of %u key-value pairs>", tag.v.n);
+            mpack_snprintf(buffer, buffer_size, "<map of %" PRIu32 " key-value pairs>", tag.v.n);
             return;
     }
 
@@ -544,22 +544,22 @@
             #endif
             return;
         case mpack_type_str:
-            mpack_snprintf(buffer, buffer_size, "str of %u bytes", tag.v.l);
+            mpack_snprintf(buffer, buffer_size, "str of %" PRIu32 " bytes", tag.v.l);
             return;
         case mpack_type_bin:
-            mpack_snprintf(buffer, buffer_size, "bin of %u bytes", tag.v.l);
+            mpack_snprintf(buffer, buffer_size, "bin of %" PRIu32 " bytes", tag.v.l);
             return;
         #if MPACK_EXTENSIONS
         case mpack_type_ext:
-            mpack_snprintf(buffer, buffer_size, "ext of type %i, %u bytes",
+            mpack_snprintf(buffer, buffer_size, "ext of type %i, %" PRIu32 " bytes",
                     mpack_tag_ext_exttype(&tag), mpack_tag_ext_length(&tag));
             return;
         #endif
         case mpack_type_array:
-            mpack_snprintf(buffer, buffer_size, "array of %u elements", tag.v.n);
+            mpack_snprintf(buffer, buffer_size, "array of %" PRIu32 " elements", tag.v.n);
             return;
         case mpack_type_map:
-            mpack_snprintf(buffer, buffer_size, "map of %u key-value pairs", tag.v.n);
+            mpack_snprintf(buffer, buffer_size, "map of %" PRIu32 " key-value pairs", tag.v.n);
             return;
     }
 
@@ -1039,7 +1039,7 @@
         if (build->nested_compound_elements == 0) {
             if (build->type != mpack_type_map) {
                 ++build->count;
-                mpack_log("adding element to build %p, now %u elements\n", (void*)build, build->count);
+                mpack_log("adding element to build %p, now %" PRIu32 " elements\n", (void*)build, build->count);
             } else if (build->key_needs_value) {
                 build->key_needs_value = false;
                 ++build->count;
@@ -1494,6 +1494,46 @@
     mpack_track_destroy(&writer->track, writer->error != mpack_ok);
     #endif
 
+    #if MPACK_BUILDER
+    mpack_builder_t* builder = &writer->builder;
+    if (builder->current_build != NULL) {
+        // A builder is open!
+
+        // Flag an error, if there's not already an error. You can only skip
+        // closing any open compound types if a write error occurred. If there
+        // wasn't already an error, it's a bug, which will assert in debug.
+        if (mpack_writer_error(writer) == mpack_ok) {
+            mpack_break("writer cannot be destroyed with an incomplete builder unless "
+                    "an error was flagged!");
+            mpack_writer_flag_error(writer, mpack_error_bug);
+        }
+
+        // Free any remaining builder pages
+        mpack_builder_page_t* page = builder->pages;
+        #if MPACK_BUILDER_INTERNAL_STORAGE
+        mpack_assert(page == (mpack_builder_page_t*)builder->internal);
+        page = page->next;
+        #endif
+        while (page != NULL) {
+            mpack_builder_page_t* next = page->next;
+            MPACK_FREE(page);
+            page = next;
+        }
+
+        // Restore the stashed pointers. The teardown function may need to free
+        // them (e.g. mpack_growable_writer_teardown().)
+        writer->buffer = builder->stash_buffer;
+        writer->position = builder->stash_position;
+        writer->end = builder->stash_end;
+
+        // Note: It's not necessary to clean up the current_build or other
+        // pointers at this point because we're guaranteed to be in an error
+        // state already so a user error callback can't longjmp out. This
+        // destroy function will complete no matter what so it doesn't matter
+        // what junk is left in the writer.
+    }
+    #endif
+
     // flush any outstanding data
     if (mpack_writer_error(writer) == mpack_ok && mpack_writer_buffer_used(writer) != 0 && writer->flush != NULL) {
         writer->flush(writer, writer->buffer, mpack_writer_buffer_used(writer));
@@ -2022,7 +2062,7 @@
     #endif
 
     if (nanoseconds > MPACK_TIMESTAMP_NANOSECONDS_MAX) {
-        mpack_break("timestamp nanoseconds out of bounds: %u", nanoseconds);
+        mpack_break("timestamp nanoseconds out of bounds: %" PRIu32 , nanoseconds);
         mpack_writer_flag_error(writer, mpack_error_bug);
         return;
     }
@@ -2165,7 +2205,7 @@
  */
 
 void mpack_write_str(mpack_writer_t* writer, const char* data, uint32_t count) {
-    mpack_assert(data != NULL, "data for string of length %i is NULL", (int)count);
+    mpack_assert(count == 0 || data != NULL, "data for string of length %i is NULL", (int)count);
 
     #if MPACK_OPTIMIZE_FOR_SIZE
     mpack_writer_track_element(writer);
@@ -2220,7 +2260,7 @@
 }
 
 void mpack_write_bin(mpack_writer_t* writer, const char* data, uint32_t count) {
-    mpack_assert(data != NULL, "data pointer for bin of %i bytes is NULL", (int)count);
+    mpack_assert(count == 0 || data != NULL, "data pointer for bin of %i bytes is NULL", (int)count);
     mpack_start_bin(writer, count);
     mpack_write_bytes(writer, data, count);
     mpack_finish_bin(writer);
@@ -2228,7 +2268,7 @@
 
 #if MPACK_EXTENSIONS
 void mpack_write_ext(mpack_writer_t* writer, int8_t exttype, const char* data, uint32_t count) {
-    mpack_assert(data != NULL, "data pointer for ext of type %i and %i bytes is NULL", exttype, (int)count);
+    mpack_assert(count == 0 || data != NULL, "data pointer for ext of type %i and %i bytes is NULL", exttype, (int)count);
     mpack_start_ext(writer, exttype, count);
     mpack_write_bytes(writer, data, count);
     mpack_finish_ext(writer);
@@ -2236,7 +2276,7 @@
 #endif
 
 void mpack_write_bytes(mpack_writer_t* writer, const char* data, size_t count) {
-    mpack_assert(data != NULL, "data pointer for %i bytes is NULL", (int)count);
+    mpack_assert(count == 0 || data != NULL, "data pointer for %i bytes is NULL", (int)count);
     mpack_writer_track_bytes(writer, count);
     mpack_write_native(writer, data, count);
 }
@@ -2257,7 +2297,7 @@
 }
 
 void mpack_write_utf8(mpack_writer_t* writer, const char* str, uint32_t length) {
-    mpack_assert(str != NULL, "data for string of length %i is NULL", (int)length);
+    mpack_assert(length == 0 || str != NULL, "data for string of length %i is NULL", (int)length);
     if (!mpack_utf8_check(str, length)) {
         mpack_writer_flag_error(writer, mpack_error_invalid);
         return;
@@ -2557,6 +2597,16 @@
 static void mpack_builder_resolve(mpack_writer_t* writer) {
     mpack_builder_t* builder = &writer->builder;
 
+    // We should not have gotten here if we are in an error state. If an error
+    // occurs with an open builder, the writer will free the open builder pages
+    // when destroyed.
+    mpack_assert(mpack_writer_error(writer) == mpack_ok, "can't resolve in error state!");
+
+    // We don't want the user to longjmp out of any I/O errors while we are
+    // walking the page list, so defer error callbacks to after we're done.
+    mpack_writer_error_t error_fn = writer->error_fn;
+    writer->error_fn = NULL;
+
     // The starting page is the internal storage (if we have it), otherwise
     // it's the first page in the array
     mpack_builder_page_t* page =
@@ -2589,13 +2639,13 @@
 
     // Walk the list of builds, writing everything out in the buffer. Note that
     // we don't check for errors anywhere. The lower-level write functions will
-    // all check for errors. We need to walk all pages anyway to free them, so
-    // there's not much point in optimizing an error path at the expense of the
-    // normal path.
+    // all check for errors and do nothing after an error occurs. We need to
+    // walk all pages anyway to free them, so there's not much point in
+    // optimizing an error path at the expense of the normal path.
     while (true) {
 
         // write out the container tag
-        mpack_log("writing out an %s with count %u followed by %zi bytes\n",
+        mpack_log("writing out an %s with count %" PRIu32 " followed by %zi bytes\n",
                 mpack_type_to_string(build->type), build->count, build->bytes);
         switch (build->type) {
             case mpack_type_map:
@@ -2645,7 +2695,7 @@
 
         // now see if we can find another build.
         offset = mpack_builder_align_build(offset);
-        if (offset + sizeof(mpack_build_t) >= mpack_builder_page_size(writer, page)) {
+        if (offset + sizeof(mpack_build_t) > mpack_builder_page_size(writer, page)) {
             mpack_log("not enough room in this page for another build\n");
             mpack_builder_page_t* next_page = page->next;
             mpack_builder_free_page(writer, page);
@@ -2671,13 +2721,18 @@
     }
 
     mpack_log("done resolve.\n");
+
+    // We can now restore the error handler and call it if an error occurred.
+    writer->error_fn = error_fn;
+    if (writer->error_fn && mpack_writer_error(writer) != mpack_ok)
+        writer->error_fn(writer, writer->error);
 }
 
 static void mpack_builder_complete(mpack_writer_t* writer, mpack_type_t type) {
+    mpack_writer_track_pop_builder(writer, type);
     if (mpack_writer_error(writer) != mpack_ok)
         return;
 
-    mpack_writer_track_pop_builder(writer, type);
     mpack_builder_t* builder = &writer->builder;
     mpack_assert(builder->current_build != NULL, "no build in progress!");
     mpack_assert(builder->latest_build != NULL, "missing latest build!");
@@ -3120,7 +3175,7 @@
     // check if we have enough in the buffer already
     size_t left = (size_t)(reader->end - reader->data);
     if (left >= count) {
-        mpack_log("skipping %u bytes still in buffer\n", (uint32_t)count);
+        mpack_log("skipping %" PRIu32 " bytes still in buffer\n", (uint32_t)count);
         reader->data += count;
         return;
     }
@@ -5013,7 +5068,7 @@
             return false;
         }
 
-        mpack_log("read %u more bytes\n", (uint32_t)read);
+        mpack_log("read %" PRIu32 " more bytes\n", (uint32_t)read);
         tree->data_length += read;
         tree->parser.possible_nodes_left += read;
     } while (tree->parser.possible_nodes_left < bytes);
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/any.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/any.h
new file mode 100644
index 0000000..92ea2bb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/any.h
@@ -0,0 +1,157 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_ANY_H__
+#define GOOGLE_PROTOBUF_ANY_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class FieldDescriptor;
+class Message;
+
+namespace internal {
+
+extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
+extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
+extern const char kTypeGoogleProdComPrefix[];  // "type.googleprod.com/".
+
+std::string GetTypeUrl(StringPiece message_name,
+                       StringPiece type_url_prefix);
+
+// Helper class used to implement google::protobuf::Any.
+class PROTOBUF_EXPORT AnyMetadata {
+  typedef ArenaStringPtr UrlType;
+  typedef ArenaStringPtr ValueType;
+ public:
+  // AnyMetadata does not take ownership of "type_url" and "value".
+  constexpr AnyMetadata(UrlType* type_url, ValueType* value)
+      : type_url_(type_url), value_(value) {}
+
+  // Packs a message using the default type URL prefix: "type.googleapis.com".
+  // The resulted type URL will be "type.googleapis.com/<message_full_name>".
+  // Returns false if serializing the message failed.
+  template <typename T>
+  bool PackFrom(Arena* arena, const T& message) {
+    return InternalPackFrom(arena, message, kTypeGoogleApisComPrefix,
+                            T::FullMessageName());
+  }
+
+  bool PackFrom(Arena* arena, const Message& message);
+
+  // Packs a message using the given type URL prefix. The type URL will be
+  // constructed by concatenating the message type's full name to the prefix
+  // with an optional "/" separator if the prefix doesn't already end with "/".
+  // For example, both PackFrom(message, "type.googleapis.com") and
+  // PackFrom(message, "type.googleapis.com/") yield the same result type
+  // URL: "type.googleapis.com/<message_full_name>".
+  // Returns false if serializing the message failed.
+  template <typename T>
+  bool PackFrom(Arena* arena, const T& message,
+                StringPiece type_url_prefix) {
+    return InternalPackFrom(arena, message, type_url_prefix,
+                            T::FullMessageName());
+  }
+
+  bool PackFrom(Arena* arena, const Message& message,
+                StringPiece type_url_prefix);
+
+  // Unpacks the payload into the given message. Returns false if the message's
+  // type doesn't match the type specified in the type URL (i.e., the full
+  // name after the last "/" of the type URL doesn't match the message's actual
+  // full name) or parsing the payload has failed.
+  template <typename T>
+  bool UnpackTo(T* message) const {
+    return InternalUnpackTo(T::FullMessageName(), message);
+  }
+
+  bool UnpackTo(Message* message) const;
+
+  // Checks whether the type specified in the type URL matches the given type.
+  // A type is considered matching if its full name matches the full name after
+  // the last "/" in the type URL.
+  template <typename T>
+  bool Is() const {
+    return InternalIs(T::FullMessageName());
+  }
+
+ private:
+  bool InternalPackFrom(Arena* arena, const MessageLite& message,
+                        StringPiece type_url_prefix,
+                        StringPiece type_name);
+  bool InternalUnpackTo(StringPiece type_name,
+                        MessageLite* message) const;
+  bool InternalIs(StringPiece type_name) const;
+
+  UrlType* type_url_;
+  ValueType* value_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
+};
+
+// Get the proto type name from Any::type_url value. For example, passing
+// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
+// *full_type_name. Returns false if the type_url does not have a "/"
+// in the type url separating the full type name.
+//
+// NOTE: this function is available publicly as a static method on the
+// generated message type: google::protobuf::Any::ParseAnyTypeUrl()
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* full_type_name);
+
+// Get the proto type name and prefix from Any::type_url value. For example,
+// passing "type.googleapis.com/rpc.QueryOrigin" will return
+// "type.googleapis.com/" in *url_prefix and "rpc.QueryOrigin" in
+// *full_type_name. Returns false if the type_url does not have a "/" in the
+// type url separating the full type name.
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* url_prefix,
+                     std::string* full_type_name);
+
+// See if message is of type google.protobuf.Any, if so, return the descriptors
+// for "type_url" and "value" fields.
+bool GetAnyFieldDescriptors(const Message& message,
+                            const FieldDescriptor** type_url_field,
+                            const FieldDescriptor** value_field);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ANY_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/any.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/any.pb.h
new file mode 100644
index 0000000..2c06052
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/any.pb.h
@@ -0,0 +1,384 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fany_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fany_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Any;
+struct AnyDefaultTypeInternal;
+PROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Any* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Any>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Any final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
+ public:
+  inline Any() : Any(nullptr) {}
+  ~Any() override;
+  explicit PROTOBUF_CONSTEXPR Any(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Any(const Any& from);
+  Any(Any&& from) noexcept
+    : Any() {
+    *this = ::std::move(from);
+  }
+
+  inline Any& operator=(const Any& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Any& operator=(Any&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Any& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Any* internal_default_instance() {
+    return reinterpret_cast<const Any*>(
+               &_Any_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  // implements Any -----------------------------------------------
+
+  bool PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message& message) {
+    GOOGLE_DCHECK_NE(&message, this);
+    return _impl_._any_metadata_.PackFrom(GetArena(), message);
+  }
+  bool PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message& message,
+                ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url_prefix) {
+    GOOGLE_DCHECK_NE(&message, this);
+    return _impl_._any_metadata_.PackFrom(GetArena(), message, type_url_prefix);
+  }
+  bool UnpackTo(::PROTOBUF_NAMESPACE_ID::Message* message) const {
+    return _impl_._any_metadata_.UnpackTo(message);
+  }
+  static bool GetAnyFieldDescriptors(
+      const ::PROTOBUF_NAMESPACE_ID::Message& message,
+      const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
+      const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field);
+  template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
+  bool PackFrom(const T& message) {
+    return _impl_._any_metadata_.PackFrom<T>(GetArena(), message);
+  }
+  template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
+  bool PackFrom(const T& message,
+                ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url_prefix) {
+    return _impl_._any_metadata_.PackFrom<T>(GetArena(), message, type_url_prefix);}
+  template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
+  bool UnpackTo(T* message) const {
+    return _impl_._any_metadata_.UnpackTo<T>(message);
+  }
+  template<typename T> bool Is() const {
+    return _impl_._any_metadata_.Is<T>();
+  }
+  static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,
+                              std::string* full_type_name);
+  friend void swap(Any& a, Any& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Any* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Any* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Any* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Any>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Any& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Any& from) {
+    Any::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Any* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Any";
+  }
+  protected:
+  explicit Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kTypeUrlFieldNumber = 1,
+    kValueFieldNumber = 2,
+  };
+  // string type_url = 1;
+  void clear_type_url();
+  const std::string& type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_type_url();
+  PROTOBUF_NODISCARD std::string* release_type_url();
+  void set_allocated_type_url(std::string* type_url);
+  private:
+  const std::string& _internal_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_url(const std::string& value);
+  std::string* _internal_mutable_type_url();
+  public:
+
+  // bytes value = 2;
+  void clear_value();
+  const std::string& value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_value();
+  PROTOBUF_NODISCARD std::string* release_value();
+  void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Any)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_url_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata _any_metadata_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fany_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Any
+
+// string type_url = 1;
+inline void Any::clear_type_url() {
+  _impl_.type_url_.ClearToEmpty();
+}
+inline const std::string& Any::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
+  return _internal_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Any::set_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
+}
+inline std::string* Any::mutable_type_url() {
+  std::string* _s = _internal_mutable_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
+  return _s;
+}
+inline const std::string& Any::_internal_type_url() const {
+  return _impl_.type_url_.Get();
+}
+inline void Any::_internal_set_type_url(const std::string& value) {
+  
+  _impl_.type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Any::_internal_mutable_type_url() {
+  
+  return _impl_.type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Any::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
+  return _impl_.type_url_.Release();
+}
+inline void Any::set_allocated_type_url(std::string* type_url) {
+  if (type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.type_url_.SetAllocated(type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_url_.IsDefault()) {
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
+}
+
+// bytes value = 2;
+inline void Any::clear_value() {
+  _impl_.value_.ClearToEmpty();
+}
+inline const std::string& Any::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
+  return _internal_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Any::set_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.value)
+}
+inline std::string* Any::mutable_value() {
+  std::string* _s = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
+  return _s;
+}
+inline const std::string& Any::_internal_value() const {
+  return _impl_.value_.Get();
+}
+inline void Any::_internal_set_value(const std::string& value) {
+  
+  _impl_.value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Any::_internal_mutable_value() {
+  
+  return _impl_.value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Any::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.value)
+  return _impl_.value_.Release();
+}
+inline void Any::set_allocated_value(std::string* value) {
+  if (value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.value_.SetAllocated(value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.value_.IsDefault()) {
+    _impl_.value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/api.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/api.pb.h
new file mode 100644
index 0000000..2c45489
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/api.pb.h
@@ -0,0 +1,1437 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fapi_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fapi_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/source_context.pb.h>
+#include <google/protobuf/type.pb.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fapi_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fapi_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Api;
+struct ApiDefaultTypeInternal;
+PROTOBUF_EXPORT extern ApiDefaultTypeInternal _Api_default_instance_;
+class Method;
+struct MethodDefaultTypeInternal;
+PROTOBUF_EXPORT extern MethodDefaultTypeInternal _Method_default_instance_;
+class Mixin;
+struct MixinDefaultTypeInternal;
+PROTOBUF_EXPORT extern MixinDefaultTypeInternal _Mixin_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Api* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Api>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Method* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Method>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Mixin* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Mixin>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Api final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Api) */ {
+ public:
+  inline Api() : Api(nullptr) {}
+  ~Api() override;
+  explicit PROTOBUF_CONSTEXPR Api(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Api(const Api& from);
+  Api(Api&& from) noexcept
+    : Api() {
+    *this = ::std::move(from);
+  }
+
+  inline Api& operator=(const Api& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Api& operator=(Api&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Api& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Api* internal_default_instance() {
+    return reinterpret_cast<const Api*>(
+               &_Api_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Api& a, Api& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Api* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Api* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Api* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Api>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Api& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Api& from) {
+    Api::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Api* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Api";
+  }
+  protected:
+  explicit Api(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kMethodsFieldNumber = 2,
+    kOptionsFieldNumber = 3,
+    kMixinsFieldNumber = 6,
+    kNameFieldNumber = 1,
+    kVersionFieldNumber = 4,
+    kSourceContextFieldNumber = 5,
+    kSyntaxFieldNumber = 7,
+  };
+  // repeated .google.protobuf.Method methods = 2;
+  int methods_size() const;
+  private:
+  int _internal_methods_size() const;
+  public:
+  void clear_methods();
+  ::PROTOBUF_NAMESPACE_ID::Method* mutable_methods(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >*
+      mutable_methods();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Method& _internal_methods(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Method* _internal_add_methods();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Method& methods(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Method* add_methods();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >&
+      methods() const;
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  int mixins_size() const;
+  private:
+  int _internal_mixins_size() const;
+  public:
+  void clear_mixins();
+  ::PROTOBUF_NAMESPACE_ID::Mixin* mutable_mixins(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >*
+      mutable_mixins();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Mixin& _internal_mixins(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Mixin* _internal_add_mixins();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Mixin& mixins(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Mixin* add_mixins();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >&
+      mixins() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string version = 4;
+  void clear_version();
+  const std::string& version() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_version(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_version();
+  PROTOBUF_NODISCARD std::string* release_version();
+  void set_allocated_version(std::string* version);
+  private:
+  const std::string& _internal_version() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_version(const std::string& value);
+  std::string* _internal_mutable_version();
+  public:
+
+  // .google.protobuf.SourceContext source_context = 5;
+  bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
+  void clear_source_context();
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
+  void set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& _internal_source_context() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _internal_mutable_source_context();
+  public:
+  void unsafe_arena_set_allocated_source_context(
+      ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* unsafe_arena_release_source_context();
+
+  // .google.protobuf.Syntax syntax = 7;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Api)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method > methods_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin > mixins_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr version_;
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fapi_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Method final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Method) */ {
+ public:
+  inline Method() : Method(nullptr) {}
+  ~Method() override;
+  explicit PROTOBUF_CONSTEXPR Method(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Method(const Method& from);
+  Method(Method&& from) noexcept
+    : Method() {
+    *this = ::std::move(from);
+  }
+
+  inline Method& operator=(const Method& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Method& operator=(Method&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Method& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Method* internal_default_instance() {
+    return reinterpret_cast<const Method*>(
+               &_Method_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(Method& a, Method& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Method* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Method* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Method* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Method>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Method& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Method& from) {
+    Method::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Method* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Method";
+  }
+  protected:
+  explicit Method(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 6,
+    kNameFieldNumber = 1,
+    kRequestTypeUrlFieldNumber = 2,
+    kResponseTypeUrlFieldNumber = 4,
+    kRequestStreamingFieldNumber = 3,
+    kResponseStreamingFieldNumber = 5,
+    kSyntaxFieldNumber = 7,
+  };
+  // repeated .google.protobuf.Option options = 6;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string request_type_url = 2;
+  void clear_request_type_url();
+  const std::string& request_type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_request_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_request_type_url();
+  PROTOBUF_NODISCARD std::string* release_request_type_url();
+  void set_allocated_request_type_url(std::string* request_type_url);
+  private:
+  const std::string& _internal_request_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_request_type_url(const std::string& value);
+  std::string* _internal_mutable_request_type_url();
+  public:
+
+  // string response_type_url = 4;
+  void clear_response_type_url();
+  const std::string& response_type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_response_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_response_type_url();
+  PROTOBUF_NODISCARD std::string* release_response_type_url();
+  void set_allocated_response_type_url(std::string* response_type_url);
+  private:
+  const std::string& _internal_response_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_response_type_url(const std::string& value);
+  std::string* _internal_mutable_response_type_url();
+  public:
+
+  // bool request_streaming = 3;
+  void clear_request_streaming();
+  bool request_streaming() const;
+  void set_request_streaming(bool value);
+  private:
+  bool _internal_request_streaming() const;
+  void _internal_set_request_streaming(bool value);
+  public:
+
+  // bool response_streaming = 5;
+  void clear_response_streaming();
+  bool response_streaming() const;
+  void set_response_streaming(bool value);
+  private:
+  bool _internal_response_streaming() const;
+  void _internal_set_response_streaming(bool value);
+  public:
+
+  // .google.protobuf.Syntax syntax = 7;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Method)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr request_type_url_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr response_type_url_;
+    bool request_streaming_;
+    bool response_streaming_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fapi_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Mixin final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Mixin) */ {
+ public:
+  inline Mixin() : Mixin(nullptr) {}
+  ~Mixin() override;
+  explicit PROTOBUF_CONSTEXPR Mixin(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Mixin(const Mixin& from);
+  Mixin(Mixin&& from) noexcept
+    : Mixin() {
+    *this = ::std::move(from);
+  }
+
+  inline Mixin& operator=(const Mixin& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Mixin& operator=(Mixin&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Mixin& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Mixin* internal_default_instance() {
+    return reinterpret_cast<const Mixin*>(
+               &_Mixin_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Mixin& a, Mixin& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Mixin* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Mixin* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Mixin* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Mixin>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Mixin& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Mixin& from) {
+    Mixin::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Mixin* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Mixin";
+  }
+  protected:
+  explicit Mixin(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kRootFieldNumber = 2,
+  };
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string root = 2;
+  void clear_root();
+  const std::string& root() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_root(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_root();
+  PROTOBUF_NODISCARD std::string* release_root();
+  void set_allocated_root(std::string* root);
+  private:
+  const std::string& _internal_root() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_root(const std::string& value);
+  std::string* _internal_mutable_root();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Mixin)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr root_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fapi_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Api
+
+// string name = 1;
+inline void Api::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Api::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Api::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.name)
+}
+inline std::string* Api::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.name)
+  return _s;
+}
+inline const std::string& Api::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Api::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Api::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Api::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.name)
+  return _impl_.name_.Release();
+}
+inline void Api::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.name)
+}
+
+// repeated .google.protobuf.Method methods = 2;
+inline int Api::_internal_methods_size() const {
+  return _impl_.methods_.size();
+}
+inline int Api::methods_size() const {
+  return _internal_methods_size();
+}
+inline void Api::clear_methods() {
+  _impl_.methods_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Method* Api::mutable_methods(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods)
+  return _impl_.methods_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >*
+Api::mutable_methods() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods)
+  return &_impl_.methods_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Method& Api::_internal_methods(int index) const {
+  return _impl_.methods_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Method& Api::methods(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.methods)
+  return _internal_methods(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Method* Api::_internal_add_methods() {
+  return _impl_.methods_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Method* Api::add_methods() {
+  ::PROTOBUF_NAMESPACE_ID::Method* _add = _internal_add_methods();
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.methods)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Method >&
+Api::methods() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.methods)
+  return _impl_.methods_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int Api::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Api::options_size() const {
+  return _internal_options_size();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Api::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Api::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Api::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Api::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Api::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Api::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Api::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.options)
+  return _impl_.options_;
+}
+
+// string version = 4;
+inline void Api::clear_version() {
+  _impl_.version_.ClearToEmpty();
+}
+inline const std::string& Api::version() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.version)
+  return _internal_version();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Api::set_version(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.version_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.version)
+}
+inline std::string* Api::mutable_version() {
+  std::string* _s = _internal_mutable_version();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.version)
+  return _s;
+}
+inline const std::string& Api::_internal_version() const {
+  return _impl_.version_.Get();
+}
+inline void Api::_internal_set_version(const std::string& value) {
+  
+  _impl_.version_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Api::_internal_mutable_version() {
+  
+  return _impl_.version_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Api::release_version() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.version)
+  return _impl_.version_.Release();
+}
+inline void Api::set_allocated_version(std::string* version) {
+  if (version != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.version_.SetAllocated(version, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.version_.IsDefault()) {
+    _impl_.version_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.version)
+}
+
+// .google.protobuf.SourceContext source_context = 5;
+inline bool Api::_internal_has_source_context() const {
+  return this != internal_default_instance() && _impl_.source_context_ != nullptr;
+}
+inline bool Api::has_source_context() const {
+  return _internal_has_source_context();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Api::_internal_source_context() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext* p = _impl_.source_context_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceContext&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Api::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.source_context)
+  return _internal_source_context();
+}
+inline void Api::unsafe_arena_set_allocated_source_context(
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  _impl_.source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Api.source_context)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::release_source_context() {
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::unsafe_arena_release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context)
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::_internal_mutable_source_context() {
+  
+  if (_impl_.source_context_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(GetArenaForAllocation());
+    _impl_.source_context_ = p;
+  }
+  return _impl_.source_context_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Api::mutable_source_context() {
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _msg = _internal_mutable_source_context();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context)
+  return _msg;
+}
+inline void Api::set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  if (source_context) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(source_context));
+    if (message_arena != submessage_arena) {
+      source_context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_context, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.source_context_ = source_context;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.source_context)
+}
+
+// repeated .google.protobuf.Mixin mixins = 6;
+inline int Api::_internal_mixins_size() const {
+  return _impl_.mixins_.size();
+}
+inline int Api::mixins_size() const {
+  return _internal_mixins_size();
+}
+inline void Api::clear_mixins() {
+  _impl_.mixins_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Mixin* Api::mutable_mixins(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins)
+  return _impl_.mixins_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >*
+Api::mutable_mixins() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins)
+  return &_impl_.mixins_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Mixin& Api::_internal_mixins(int index) const {
+  return _impl_.mixins_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Mixin& Api::mixins(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins)
+  return _internal_mixins(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Mixin* Api::_internal_add_mixins() {
+  return _impl_.mixins_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Mixin* Api::add_mixins() {
+  ::PROTOBUF_NAMESPACE_ID::Mixin* _add = _internal_add_mixins();
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Mixin >&
+Api::mixins() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins)
+  return _impl_.mixins_;
+}
+
+// .google.protobuf.Syntax syntax = 7;
+inline void Api::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Api::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Api::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.syntax)
+  return _internal_syntax();
+}
+inline void Api::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Api::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Method
+
+// string name = 1;
+inline void Method::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Method::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Method::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.name)
+}
+inline std::string* Method::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.name)
+  return _s;
+}
+inline const std::string& Method::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Method::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Method::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Method::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.name)
+  return _impl_.name_.Release();
+}
+inline void Method::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.name)
+}
+
+// string request_type_url = 2;
+inline void Method::clear_request_type_url() {
+  _impl_.request_type_url_.ClearToEmpty();
+}
+inline const std::string& Method::request_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_type_url)
+  return _internal_request_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Method::set_request_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.request_type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_type_url)
+}
+inline std::string* Method::mutable_request_type_url() {
+  std::string* _s = _internal_mutable_request_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.request_type_url)
+  return _s;
+}
+inline const std::string& Method::_internal_request_type_url() const {
+  return _impl_.request_type_url_.Get();
+}
+inline void Method::_internal_set_request_type_url(const std::string& value) {
+  
+  _impl_.request_type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Method::_internal_mutable_request_type_url() {
+  
+  return _impl_.request_type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Method::release_request_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url)
+  return _impl_.request_type_url_.Release();
+}
+inline void Method::set_allocated_request_type_url(std::string* request_type_url) {
+  if (request_type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.request_type_url_.SetAllocated(request_type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.request_type_url_.IsDefault()) {
+    _impl_.request_type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.request_type_url)
+}
+
+// bool request_streaming = 3;
+inline void Method::clear_request_streaming() {
+  _impl_.request_streaming_ = false;
+}
+inline bool Method::_internal_request_streaming() const {
+  return _impl_.request_streaming_;
+}
+inline bool Method::request_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_streaming)
+  return _internal_request_streaming();
+}
+inline void Method::_internal_set_request_streaming(bool value) {
+  
+  _impl_.request_streaming_ = value;
+}
+inline void Method::set_request_streaming(bool value) {
+  _internal_set_request_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_streaming)
+}
+
+// string response_type_url = 4;
+inline void Method::clear_response_type_url() {
+  _impl_.response_type_url_.ClearToEmpty();
+}
+inline const std::string& Method::response_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_type_url)
+  return _internal_response_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Method::set_response_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.response_type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_type_url)
+}
+inline std::string* Method::mutable_response_type_url() {
+  std::string* _s = _internal_mutable_response_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.response_type_url)
+  return _s;
+}
+inline const std::string& Method::_internal_response_type_url() const {
+  return _impl_.response_type_url_.Get();
+}
+inline void Method::_internal_set_response_type_url(const std::string& value) {
+  
+  _impl_.response_type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Method::_internal_mutable_response_type_url() {
+  
+  return _impl_.response_type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Method::release_response_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url)
+  return _impl_.response_type_url_.Release();
+}
+inline void Method::set_allocated_response_type_url(std::string* response_type_url) {
+  if (response_type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.response_type_url_.SetAllocated(response_type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.response_type_url_.IsDefault()) {
+    _impl_.response_type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.response_type_url)
+}
+
+// bool response_streaming = 5;
+inline void Method::clear_response_streaming() {
+  _impl_.response_streaming_ = false;
+}
+inline bool Method::_internal_response_streaming() const {
+  return _impl_.response_streaming_;
+}
+inline bool Method::response_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_streaming)
+  return _internal_response_streaming();
+}
+inline void Method::_internal_set_response_streaming(bool value) {
+  
+  _impl_.response_streaming_ = value;
+}
+inline void Method::set_response_streaming(bool value) {
+  _internal_set_response_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_streaming)
+}
+
+// repeated .google.protobuf.Option options = 6;
+inline int Method::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Method::options_size() const {
+  return _internal_options_size();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Method::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Method::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Method::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Method::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Method::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Method::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Method.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Method::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Method.options)
+  return _impl_.options_;
+}
+
+// .google.protobuf.Syntax syntax = 7;
+inline void Method::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Method::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Method::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.syntax)
+  return _internal_syntax();
+}
+inline void Method::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Method::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Mixin
+
+// string name = 1;
+inline void Mixin::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Mixin::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Mixin::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name)
+}
+inline std::string* Mixin::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name)
+  return _s;
+}
+inline const std::string& Mixin::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Mixin::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Mixin::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Mixin::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name)
+  return _impl_.name_.Release();
+}
+inline void Mixin::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name)
+}
+
+// string root = 2;
+inline void Mixin::clear_root() {
+  _impl_.root_.ClearToEmpty();
+}
+inline const std::string& Mixin::root() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
+  return _internal_root();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Mixin::set_root(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.root_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root)
+}
+inline std::string* Mixin::mutable_root() {
+  std::string* _s = _internal_mutable_root();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root)
+  return _s;
+}
+inline const std::string& Mixin::_internal_root() const {
+  return _impl_.root_.Get();
+}
+inline void Mixin::_internal_set_root(const std::string& value) {
+  
+  _impl_.root_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Mixin::_internal_mutable_root() {
+  
+  return _impl_.root_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Mixin::release_root() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root)
+  return _impl_.root_.Release();
+}
+inline void Mixin::set_allocated_root(std::string* root) {
+  if (root != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.root_.SetAllocated(root, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.root_.IsDefault()) {
+    _impl_.root_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fapi_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arena.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arena.h
new file mode 100644
index 0000000..3b5f16c
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arena.h
@@ -0,0 +1,851 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines an Arena allocator for better allocation performance.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_H__
+#define GOOGLE_PROTOBUF_ARENA_H__
+
+
+#include <limits>
+#include <type_traits>
+#include <utility>
+#if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
+// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
+#include <exception>
+#include <typeinfo>
+namespace std {
+using type_info = ::type_info;
+}
+#else
+#include <typeinfo>
+#endif
+
+#include <type_traits>
+#include <google/protobuf/arena_impl.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+struct ArenaOptions;  // defined below
+class Arena;    // defined below
+class Message;  // defined in message.h
+class MessageLite;
+template <typename Key, typename T>
+class Map;
+
+namespace arena_metrics {
+
+void EnableArenaMetrics(ArenaOptions* options);
+
+}  // namespace arena_metrics
+
+namespace TestUtil {
+class ReflectionTester;  // defined in test_util.h
+}  // namespace TestUtil
+
+namespace internal {
+
+struct ArenaTestPeer;        // defined in arena_test_util.h
+class InternalMetadata;      // defined in metadata_lite.h
+class LazyField;             // defined in lazy_field.h
+class EpsCopyInputStream;    // defined in parse_context.h
+class RepeatedPtrFieldBase;  // defined in repeated_ptr_field.h
+
+template <typename Type>
+class GenericTypeHandler;  // defined in repeated_field.h
+
+inline PROTOBUF_ALWAYS_INLINE
+void* AlignTo(void* ptr, size_t align) {
+  return reinterpret_cast<void*>(
+      (reinterpret_cast<uintptr_t>(ptr) + align - 1) & (~align + 1));
+}
+
+// Templated cleanup methods.
+template <typename T>
+void arena_destruct_object(void* object) {
+  reinterpret_cast<T*>(object)->~T();
+}
+
+template <bool destructor_skippable, typename T>
+struct ObjectDestructor {
+  constexpr static void (*destructor)(void*) = &arena_destruct_object<T>;
+};
+
+template <typename T>
+struct ObjectDestructor<true, T> {
+  constexpr static void (*destructor)(void*) = nullptr;
+};
+
+template <typename T>
+void arena_delete_object(void* object) {
+  delete reinterpret_cast<T*>(object);
+}
+}  // namespace internal
+
+// ArenaOptions provides optional additional parameters to arena construction
+// that control its block-allocation behavior.
+struct ArenaOptions {
+  // This defines the size of the first block requested from the system malloc.
+  // Subsequent block sizes will increase in a geometric series up to a maximum.
+  size_t start_block_size;
+
+  // This defines the maximum block size requested from system malloc (unless an
+  // individual arena allocation request occurs with a size larger than this
+  // maximum). Requested block sizes increase up to this value, then remain
+  // here.
+  size_t max_block_size;
+
+  // An initial block of memory for the arena to use, or NULL for none. If
+  // provided, the block must live at least as long as the arena itself. The
+  // creator of the Arena retains ownership of the block after the Arena is
+  // destroyed.
+  char* initial_block;
+
+  // The size of the initial block, if provided.
+  size_t initial_block_size;
+
+  // A function pointer to an alloc method that returns memory blocks of size
+  // requested. By default, it contains a ptr to the malloc function.
+  //
+  // NOTE: block_alloc and dealloc functions are expected to behave like
+  // malloc and free, including Asan poisoning.
+  void* (*block_alloc)(size_t);
+  // A function pointer to a dealloc method that takes ownership of the blocks
+  // from the arena. By default, it contains a ptr to a wrapper function that
+  // calls free.
+  void (*block_dealloc)(void*, size_t);
+
+  ArenaOptions()
+      : start_block_size(internal::AllocationPolicy::kDefaultStartBlockSize),
+        max_block_size(internal::AllocationPolicy::kDefaultMaxBlockSize),
+        initial_block(NULL),
+        initial_block_size(0),
+        block_alloc(nullptr),
+        block_dealloc(nullptr),
+        make_metrics_collector(nullptr) {}
+
+ private:
+  // If make_metrics_collector is not nullptr, it will be called at Arena init
+  // time. It may return a pointer to a collector instance that will be notified
+  // of interesting events related to the arena.
+  internal::ArenaMetricsCollector* (*make_metrics_collector)();
+
+  internal::ArenaMetricsCollector* MetricsCollector() const {
+    return make_metrics_collector ? (*make_metrics_collector)() : nullptr;
+  }
+
+  internal::AllocationPolicy AllocationPolicy() const {
+    internal::AllocationPolicy res;
+    res.start_block_size = start_block_size;
+    res.max_block_size = max_block_size;
+    res.block_alloc = block_alloc;
+    res.block_dealloc = block_dealloc;
+    res.metrics_collector = MetricsCollector();
+    return res;
+  }
+
+  friend void arena_metrics::EnableArenaMetrics(ArenaOptions*);
+
+  friend class Arena;
+  friend class ArenaOptionsTestFriend;
+};
+
+// Support for non-RTTI environments. (The metrics hooks API uses type
+// information.)
+#if PROTOBUF_RTTI
+#define RTTI_TYPE_ID(type) (&typeid(type))
+#else
+#define RTTI_TYPE_ID(type) (NULL)
+#endif
+
+// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
+// with new/delete, and improves performance by aggregating allocations into
+// larger blocks and freeing allocations all at once. Protocol messages are
+// allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
+// are automatically freed when the arena is destroyed.
+//
+// This is a thread-safe implementation: multiple threads may allocate from the
+// arena concurrently. Destruction is not thread-safe and the destructing
+// thread must synchronize with users of the arena first.
+//
+// An arena provides two allocation interfaces: CreateMessage<T>, which works
+// for arena-enabled proto2 message types as well as other types that satisfy
+// the appropriate protocol (described below), and Create<T>, which works for
+// any arbitrary type T. CreateMessage<T> is better when the type T supports it,
+// because this interface (i) passes the arena pointer to the created object so
+// that its sub-objects and internal allocations can use the arena too, and (ii)
+// elides the object's destructor call when possible. Create<T> does not place
+// any special requirements on the type T, and will invoke the object's
+// destructor when the arena is destroyed.
+//
+// The arena message allocation protocol, required by
+// CreateMessage<T>(Arena* arena, Args&&... args), is as follows:
+//
+// - The type T must have (at least) two constructors: a constructor callable
+//   with `args` (without `arena`), called when a T is allocated on the heap;
+//   and a constructor callable with `Arena* arena, Args&&... args`, called when
+//   a T is allocated on an arena. If the second constructor is called with a
+//   NULL arena pointer, it must be equivalent to invoking the first
+//   (`args`-only) constructor.
+//
+// - The type T must have a particular type trait: a nested type
+//   |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
+//   such type trait exists, then the instantiation CreateMessage<T> will fail
+//   to compile.
+//
+// - The type T *may* have the type trait |DestructorSkippable_|. If this type
+//   trait is present in the type, then its destructor will not be called if and
+//   only if it was passed a non-NULL arena pointer. If this type trait is not
+//   present on the type, then its destructor is always called when the
+//   containing arena is destroyed.
+//
+// This protocol is implemented by all arena-enabled proto2 message classes as
+// well as protobuf container types like RepeatedPtrField and Map. The protocol
+// is internal to protobuf and is not guaranteed to be stable. Non-proto types
+// should not rely on this protocol.
+class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
+ public:
+  // Default constructor with sensible default options, tuned for average
+  // use-cases.
+  inline Arena() : impl_() {}
+
+  // Construct an arena with default options, except for the supplied
+  // initial block. It is more efficient to use this constructor
+  // instead of passing ArenaOptions if the only configuration needed
+  // by the caller is supplying an initial block.
+  inline Arena(char* initial_block, size_t initial_block_size)
+      : impl_(initial_block, initial_block_size) {}
+
+  // Arena constructor taking custom options. See ArenaOptions above for
+  // descriptions of the options available.
+  explicit Arena(const ArenaOptions& options)
+      : impl_(options.initial_block, options.initial_block_size,
+              options.AllocationPolicy()) {}
+
+  // Block overhead.  Use this as a guide for how much to over-allocate the
+  // initial block if you want an allocation of size N to fit inside it.
+  //
+  // WARNING: if you allocate multiple objects, it is difficult to guarantee
+  // that a series of allocations will fit in the initial block, especially if
+  // Arena changes its alignment guarantees in the future!
+  static const size_t kBlockOverhead =
+      internal::ThreadSafeArena::kBlockHeaderSize +
+      internal::ThreadSafeArena::kSerialArenaSize;
+
+  inline ~Arena() {}
+
+  // TODO(protobuf-team): Fix callers to use constructor and delete this method.
+  void Init(const ArenaOptions&) {}
+
+  // API to create proto2 message objects on the arena. If the arena passed in
+  // is NULL, then a heap allocated object is returned. Type T must be a message
+  // defined in a .proto file with cc_enable_arenas set to true, otherwise a
+  // compilation error will occur.
+  //
+  // RepeatedField and RepeatedPtrField may also be instantiated directly on an
+  // arena with this method.
+  //
+  // This function also accepts any type T that satisfies the arena message
+  // allocation protocol, documented above.
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateMessage(Arena* arena, Args&&... args) {
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+    // We must delegate to CreateMaybeMessage() and NOT CreateMessageInternal()
+    // because protobuf generated classes specialize CreateMaybeMessage() and we
+    // need to use that specialization for code size reasons.
+    return Arena::CreateMaybeMessage<T>(arena, static_cast<Args&&>(args)...);
+  }
+
+  // API to create any objects on the arena. Note that only the object will
+  // be created on the arena; the underlying ptrs (in case of a proto2 message)
+  // will be still heap allocated. Proto messages should usually be allocated
+  // with CreateMessage<T>() instead.
+  //
+  // Note that even if T satisfies the arena message construction protocol
+  // (InternalArenaConstructable_ trait and optional DestructorSkippable_
+  // trait), as described above, this function does not follow the protocol;
+  // instead, it treats T as a black-box type, just as if it did not have these
+  // traits. Specifically, T's constructor arguments will always be only those
+  // passed to Create<T>() -- no additional arena pointer is implicitly added.
+  // Furthermore, the destructor will always be called at arena destruction time
+  // (unless the destructor is trivial). Hence, from T's point of view, it is as
+  // if the object were allocated on the heap (except that the underlying memory
+  // is obtained from the arena).
+  template <typename T, typename... Args>
+  PROTOBUF_NDEBUG_INLINE static T* Create(Arena* arena, Args&&... args) {
+    return CreateInternal<T>(arena, std::is_convertible<T*, MessageLite*>(),
+                             static_cast<Args&&>(args)...);
+  }
+
+  // Allocates memory with the specific size and alignment.
+  void* AllocateAligned(size_t size, size_t align = 8) {
+    if (align <= 8) {
+      return AllocateAlignedNoHook(internal::AlignUpTo8(size));
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(AllocateAlignedNoHook(size + align - 8), align);
+    }
+  }
+
+  // Create an array of object type T on the arena *without* invoking the
+  // constructor of T. If `arena` is null, then the return value should be freed
+  // with `delete[] x;` (or `::operator delete[](x);`).
+  // To ensure safe uses, this function checks at compile time
+  // (when compiled as C++11) that T is trivially default-constructible and
+  // trivially destructible.
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static T* CreateArray(Arena* arena,
+                                               size_t num_elements) {
+    static_assert(std::is_trivial<T>::value,
+                  "CreateArray requires a trivially constructible type");
+    static_assert(std::is_trivially_destructible<T>::value,
+                  "CreateArray requires a trivially destructible type");
+    GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
+    if (arena == NULL) {
+      return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
+    } else {
+      return arena->CreateInternalRawArray<T>(num_elements);
+    }
+  }
+
+  // The following are routines are for monitoring. They will approximate the
+  // total sum allocated and used memory, but the exact value is an
+  // implementation deal. For instance allocated space depends on growth
+  // policies. Do not use these in unit tests.
+  // Returns the total space allocated by the arena, which is the sum of the
+  // sizes of the underlying blocks.
+  uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); }
+  // Returns the total space used by the arena. Similar to SpaceAllocated but
+  // does not include free space and block overhead. The total space returned
+  // may not include space used by other threads executing concurrently with
+  // the call to this method.
+  uint64_t SpaceUsed() const { return impl_.SpaceUsed(); }
+
+  // Frees all storage allocated by this arena after calling destructors
+  // registered with OwnDestructor() and freeing objects registered with Own().
+  // Any objects allocated on this arena are unusable after this call. It also
+  // returns the total space used by the arena which is the sums of the sizes
+  // of the allocated blocks. This method is not thread-safe.
+  uint64_t Reset() { return impl_.Reset(); }
+
+  // Adds |object| to a list of heap-allocated objects to be freed with |delete|
+  // when the arena is destroyed or reset.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void Own(T* object) {
+    OwnInternal(object, std::is_convertible<T*, MessageLite*>());
+  }
+
+  // Adds |object| to a list of objects whose destructors will be manually
+  // called when the arena is destroyed or reset. This differs from Own() in
+  // that it does not free the underlying memory with |delete|; hence, it is
+  // normally only used for objects that are placement-newed into
+  // arena-allocated memory.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) {
+    if (object != NULL) {
+      impl_.AddCleanup(object, &internal::arena_destruct_object<T>);
+    }
+  }
+
+  // Adds a custom member function on an object to the list of destructors that
+  // will be manually called when the arena is destroyed or reset. This differs
+  // from OwnDestructor() in that any member function may be specified, not only
+  // the class destructor.
+  PROTOBUF_ALWAYS_INLINE void OwnCustomDestructor(void* object,
+                                                  void (*destruct)(void*)) {
+    impl_.AddCleanup(object, destruct);
+  }
+
+  // Retrieves the arena associated with |value| if |value| is an arena-capable
+  // message, or NULL otherwise. If possible, the call resolves at compile time.
+  // Note that we can often devirtualize calls to `value->GetArena()` so usually
+  // calling this method is unnecessary.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) {
+    return GetArenaInternal(value);
+  }
+
+  template <typename T>
+  class InternalHelper {
+   private:
+    // Provides access to protected GetOwningArena to generated messages.
+    static Arena* GetOwningArena(const T* p) { return p->GetOwningArena(); }
+
+    static void InternalSwap(T* a, T* b) { a->InternalSwap(b); }
+
+    static Arena* GetArenaForAllocationInternal(
+        const T* p, std::true_type /*is_derived_from<MessageLite>*/) {
+      return p->GetArenaForAllocation();
+    }
+
+    static Arena* GetArenaForAllocationInternal(
+        const T* p, std::false_type /*is_derived_from<MessageLite>*/) {
+      return GetArenaForAllocationForNonMessage(
+          p, typename is_arena_constructable::type());
+    }
+
+    static Arena* GetArenaForAllocationForNonMessage(
+        const T* p, std::true_type /*is_arena_constructible*/) {
+      return p->GetArena();
+    }
+
+    static Arena* GetArenaForAllocationForNonMessage(
+        const T* p, std::false_type /*is_arena_constructible*/) {
+      return GetArenaForAllocationForNonMessageNonArenaConstructible(
+          p, typename has_get_arena::type());
+    }
+
+    static Arena* GetArenaForAllocationForNonMessageNonArenaConstructible(
+        const T* p, std::true_type /*has_get_arena*/) {
+      return p->GetArena();
+    }
+
+    static Arena* GetArenaForAllocationForNonMessageNonArenaConstructible(
+        const T* /* p */, std::false_type /*has_get_arena*/) {
+      return nullptr;
+    }
+
+    template <typename U>
+    static char DestructorSkippable(const typename U::DestructorSkippable_*);
+    template <typename U>
+    static double DestructorSkippable(...);
+
+    typedef std::integral_constant<
+        bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
+                      sizeof(char) ||
+                  std::is_trivially_destructible<T>::value>
+        is_destructor_skippable;
+
+    template <typename U>
+    static char ArenaConstructable(
+        const typename U::InternalArenaConstructable_*);
+    template <typename U>
+    static double ArenaConstructable(...);
+
+    typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
+                                             static_cast<const T*>(0))) ==
+                                             sizeof(char)>
+        is_arena_constructable;
+
+    template <typename U,
+              typename std::enable_if<
+                  std::is_same<Arena*, decltype(std::declval<const U>()
+                                                    .GetArena())>::value,
+                  int>::type = 0>
+    static char HasGetArena(decltype(&U::GetArena));
+    template <typename U>
+    static double HasGetArena(...);
+
+    typedef std::integral_constant<bool, sizeof(HasGetArena<T>(nullptr)) ==
+                                             sizeof(char)>
+        has_get_arena;
+
+    template <typename... Args>
+    static T* Construct(void* ptr, Args&&... args) {
+      return new (ptr) T(static_cast<Args&&>(args)...);
+    }
+
+    static inline PROTOBUF_ALWAYS_INLINE T* New() {
+      return new T(nullptr);
+    }
+
+    static Arena* GetArena(const T* p) { return p->GetArena(); }
+
+    friend class Arena;
+    friend class TestUtil::ReflectionTester;
+  };
+
+  // Provides access to protected GetOwningArena to generated messages.  For
+  // internal use only.
+  template <typename T>
+  static Arena* InternalGetOwningArena(const T* p) {
+    return InternalHelper<T>::GetOwningArena(p);
+  }
+
+  // Provides access to protected GetArenaForAllocation to generated messages.
+  // For internal use only.
+  template <typename T>
+  static Arena* InternalGetArenaForAllocation(const T* p) {
+    return InternalHelper<T>::GetArenaForAllocationInternal(
+        p, std::is_convertible<T*, MessageLite*>());
+  }
+
+  // Creates message-owned arena.  For internal use only.
+  static Arena* InternalCreateMessageOwnedArena() {
+    return new Arena(internal::MessageOwned{});
+  }
+
+  // Checks whether this arena is message-owned.  For internal use only.
+  bool InternalIsMessageOwnedArena() { return IsMessageOwned(); }
+
+  // Helper typetraits that indicates support for arenas in a type T at compile
+  // time. This is public only to allow construction of higher-level templated
+  // utilities.
+  //
+  // is_arena_constructable<T>::value is true if the message type T has arena
+  // support enabled, and false otherwise.
+  //
+  // is_destructor_skippable<T>::value is true if the message type T has told
+  // the arena that it is safe to skip the destructor, and false otherwise.
+  //
+  // This is inside Arena because only Arena has the friend relationships
+  // necessary to see the underlying generated code traits.
+  template <typename T>
+  struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
+  template <typename T>
+  struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
+  };
+
+ private:
+  internal::ThreadSafeArena impl_;
+
+  template <typename T>
+  struct has_get_arena : InternalHelper<T>::has_get_arena {};
+
+  // Constructor solely used by message-owned arena.
+  inline Arena(internal::MessageOwned) : impl_(internal::MessageOwned{}) {}
+
+  // Checks whether this arena is message-owned.
+  PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
+    return impl_.IsMessageOwned();
+  }
+
+  void ReturnArrayMemory(void* p, size_t size) {
+    impl_.ReturnArrayMemory(p, size);
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena,
+                                                         Args&&... args) {
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+    if (arena == NULL) {
+      return new T(nullptr, static_cast<Args&&>(args)...);
+    } else {
+      return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...);
+    }
+  }
+
+  // This specialization for no arguments is necessary, because its behavior is
+  // slightly different.  When the arena pointer is nullptr, it calls T()
+  // instead of T(nullptr).
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena) {
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+    if (arena == NULL) {
+      // Generated arena constructor T(Arena*) is protected. Call via
+      // InternalHelper.
+      return InternalHelper<T>::New();
+    } else {
+      return arena->DoCreateMessage<T>();
+    }
+  }
+
+  // Allocate and also optionally call collector with the allocated type info
+  // when allocation recording is enabled.
+  PROTOBUF_NDEBUG_INLINE void* AllocateInternal(size_t size, size_t align,
+                                                void (*destructor)(void*),
+                                                const std::type_info* type) {
+    // Monitor allocation if needed.
+    if (destructor == nullptr) {
+      return AllocateAlignedWithHook(size, align, type);
+    } else {
+      if (align <= 8) {
+        auto res = AllocateAlignedWithCleanup(internal::AlignUpTo8(size), type);
+        res.second->elem = res.first;
+        res.second->cleanup = destructor;
+        return res.first;
+      } else {
+        auto res = AllocateAlignedWithCleanup(size + align - 8, type);
+        auto ptr = internal::AlignTo(res.first, align);
+        res.second->elem = ptr;
+        res.second->cleanup = destructor;
+        return ptr;
+      }
+    }
+  }
+
+  // CreateMessage<T> requires that T supports arenas, but this private method
+  // works whether or not T supports arenas. These are not exposed to user code
+  // as it can cause confusing API usages, and end up having double free in
+  // user code. These are used only internally from LazyField and Repeated
+  // fields, since they are designed to work in all mode combinations.
+  template <typename Msg, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static Msg* DoCreateMaybeMessage(Arena* arena,
+                                                          std::true_type,
+                                                          Args&&... args) {
+    return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* DoCreateMaybeMessage(Arena* arena,
+                                                        std::false_type,
+                                                        Args&&... args) {
+    return Create<T>(arena, std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateMaybeMessage(Arena* arena,
+                                                      Args&&... args) {
+    return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
+                                   std::forward<Args>(args)...);
+  }
+
+  // Just allocate the required size for the given type assuming the
+  // type has a trivial constructor.
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE T* CreateInternalRawArray(size_t num_elements) {
+    GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
+    // We count on compiler to realize that if sizeof(T) is a multiple of
+    // 8 AlignUpTo can be elided.
+    const size_t n = sizeof(T) * num_elements;
+    return static_cast<T*>(
+        AllocateAlignedWithHookForArray(n, alignof(T), RTTI_TYPE_ID(T)));
+  }
+
+  template <typename T, typename... Args>
+  PROTOBUF_NDEBUG_INLINE T* DoCreateMessage(Args&&... args) {
+    return InternalHelper<T>::Construct(
+        AllocateInternal(sizeof(T), alignof(T),
+                         internal::ObjectDestructor<
+                             InternalHelper<T>::is_destructor_skippable::value,
+                             T>::destructor,
+                         RTTI_TYPE_ID(T)),
+        this, std::forward<Args>(args)...);
+  }
+
+  // CreateInArenaStorage is used to implement map field. Without it,
+  // Map need to call generated message's protected arena constructor,
+  // which needs to declare Map as friend of generated message.
+  template <typename T, typename... Args>
+  static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) {
+    CreateInArenaStorageInternal(ptr, arena,
+                                 typename is_arena_constructable<T>::type(),
+                                 std::forward<Args>(args)...);
+    if (arena != nullptr) {
+      RegisterDestructorInternal(
+          ptr, arena,
+          typename InternalHelper<T>::is_destructor_skippable::type());
+    }
+  }
+
+  template <typename T, typename... Args>
+  static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
+                                           std::true_type, Args&&... args) {
+    InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...);
+  }
+  template <typename T, typename... Args>
+  static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
+                                           std::false_type, Args&&... args) {
+    new (ptr) T(std::forward<Args>(args)...);
+  }
+
+  template <typename T>
+  static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
+                                         std::true_type) {}
+  template <typename T>
+  static void RegisterDestructorInternal(T* ptr, Arena* arena,
+                                         std::false_type) {
+    arena->OwnDestructor(ptr);
+  }
+
+  // These implement Create(). The second parameter has type 'true_type' if T is
+  // a subtype of Message and 'false_type' otherwise.
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena, std::true_type,
+                                                  Args&&... args) {
+    if (arena == nullptr) {
+      return new T(std::forward<Args>(args)...);
+    } else {
+      auto destructor =
+          internal::ObjectDestructor<std::is_trivially_destructible<T>::value,
+                                     T>::destructor;
+      T* result =
+          new (arena->AllocateInternal(sizeof(T), alignof(T), destructor,
+                                       RTTI_TYPE_ID(T)))
+          T(std::forward<Args>(args)...);
+      return result;
+    }
+  }
+  template <typename T, typename... Args>
+  PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena, std::false_type,
+                                                  Args&&... args) {
+    if (arena == nullptr) {
+      return new T(std::forward<Args>(args)...);
+    } else {
+      auto destructor =
+          internal::ObjectDestructor<std::is_trivially_destructible<T>::value,
+                                     T>::destructor;
+      return new (arena->AllocateInternal(sizeof(T), alignof(T), destructor,
+                                          RTTI_TYPE_ID(T)))
+          T(std::forward<Args>(args)...);
+    }
+  }
+
+  // These implement Own(), which registers an object for deletion (destructor
+  // call and operator delete()). The second parameter has type 'true_type' if T
+  // is a subtype of Message and 'false_type' otherwise. Collapsing
+  // all template instantiations to one for generic Message reduces code size,
+  // using the virtual destructor instead.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::true_type) {
+    if (object != NULL) {
+      impl_.AddCleanup(object, &internal::arena_delete_object<MessageLite>);
+    }
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::false_type) {
+    if (object != NULL) {
+      impl_.AddCleanup(object, &internal::arena_delete_object<T>);
+    }
+  }
+
+  // Implementation for GetArena(). Only message objects with
+  // InternalArenaConstructable_ tags can be associated with an arena, and such
+  // objects must implement a GetArena() method.
+  template <typename T, typename std::enable_if<
+                            is_arena_constructable<T>::value, int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    return InternalHelper<T>::GetArena(value);
+  }
+  template <typename T,
+            typename std::enable_if<!is_arena_constructable<T>::value &&
+                                        has_get_arena<T>::value,
+                                    int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    return value->GetArena();
+  }
+  template <typename T,
+            typename std::enable_if<!is_arena_constructable<T>::value &&
+                                        !has_get_arena<T>::value,
+                                    int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    (void)value;
+    return nullptr;
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetOwningArena(const T* value) {
+    return GetOwningArenaInternal(
+        value, std::is_convertible<T*, MessageLite*>());
+  }
+
+  // Implementation for GetOwningArena(). All and only message objects have
+  // GetOwningArena() method.
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetOwningArenaInternal(
+      const T* value, std::true_type) {
+    return InternalHelper<T>::GetOwningArena(value);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetOwningArenaInternal(
+      const T* /* value */, std::false_type) {
+    return nullptr;
+  }
+
+  void* AllocateAlignedWithHookForArray(size_t n, size_t align,
+                                        const std::type_info* type) {
+    if (align <= 8) {
+      return AllocateAlignedWithHookForArray(internal::AlignUpTo8(n), type);
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(
+          AllocateAlignedWithHookForArray(n + align - 8, type), align);
+    }
+  }
+
+  void* AllocateAlignedWithHook(size_t n, size_t align,
+                                const std::type_info* type) {
+    if (align <= 8) {
+      return AllocateAlignedWithHook(internal::AlignUpTo8(n), type);
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(AllocateAlignedWithHook(n + align - 8, type),
+                               align);
+    }
+  }
+
+  void* AllocateAlignedNoHook(size_t n);
+  void* AllocateAlignedWithHook(size_t n, const std::type_info* type);
+  void* AllocateAlignedWithHookForArray(size_t n, const std::type_info* type);
+  std::pair<void*, internal::SerialArena::CleanupNode*>
+  AllocateAlignedWithCleanup(size_t n, const std::type_info* type);
+
+  template <typename Type>
+  friend class internal::GenericTypeHandler;
+  friend class internal::InternalMetadata;  // For user_arena().
+  friend class internal::LazyField;        // For CreateMaybeMessage.
+  friend class internal::EpsCopyInputStream;  // For parser performance
+  friend class MessageLite;
+  template <typename Key, typename T>
+  friend class Map;
+  template <typename>
+  friend class RepeatedField;                   // For ReturnArrayMemory
+  friend class internal::RepeatedPtrFieldBase;  // For ReturnArrayMemory
+  friend struct internal::ArenaTestPeer;
+};
+
+// Defined above for supporting environments without RTTI.
+#undef RTTI_TYPE_ID
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ARENA_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arena_impl.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arena_impl.h
new file mode 100644
index 0000000..8af70c4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arena_impl.h
@@ -0,0 +1,686 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines an Arena allocator for better allocation performance.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_IMPL_H__
+#define GOOGLE_PROTOBUF_ARENA_IMPL_H__
+
+#include <atomic>
+#include <limits>
+#include <typeinfo>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/port.h>
+
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif  // ADDRESS_SANITIZER
+
+#include <google/protobuf/arenaz_sampler.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// To prevent sharing cache lines between threads
+#ifdef __cpp_aligned_new
+enum { kCacheAlignment = 64 };
+#else
+enum { kCacheAlignment = alignof(max_align_t) };  // do the best we can
+#endif
+
+inline constexpr size_t AlignUpTo8(size_t n) {
+  // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
+  return (n + 7) & static_cast<size_t>(-8);
+}
+
+using LifecycleIdAtomic = uint64_t;
+
+// MetricsCollector collects stats for a particular arena.
+class PROTOBUF_EXPORT ArenaMetricsCollector {
+ public:
+  ArenaMetricsCollector(bool record_allocs) : record_allocs_(record_allocs) {}
+
+  // Invoked when the arena is about to be destroyed. This method will
+  // typically finalize any metric collection and delete the collector.
+  // space_allocated is the space used by the arena.
+  virtual void OnDestroy(uint64_t space_allocated) = 0;
+
+  // OnReset() is called when the associated arena is reset.
+  // space_allocated is the space used by the arena just before the reset.
+  virtual void OnReset(uint64_t space_allocated) = 0;
+
+  // OnAlloc is called when an allocation happens.
+  // type_info is promised to be static - its lifetime extends to
+  // match program's lifetime (It is given by typeid operator).
+  // Note: typeid(void) will be passed as allocated_type every time we
+  // intentionally want to avoid monitoring an allocation. (i.e. internal
+  // allocations for managing the arena)
+  virtual void OnAlloc(const std::type_info* allocated_type,
+                       uint64_t alloc_size) = 0;
+
+  // Does OnAlloc() need to be called?  If false, metric collection overhead
+  // will be reduced since we will not do extra work per allocation.
+  bool RecordAllocs() { return record_allocs_; }
+
+ protected:
+  // This class is destructed by the call to OnDestroy().
+  ~ArenaMetricsCollector() = default;
+  const bool record_allocs_;
+};
+
+struct AllocationPolicy {
+  static constexpr size_t kDefaultStartBlockSize = 256;
+  static constexpr size_t kDefaultMaxBlockSize = 8192;
+
+  size_t start_block_size = kDefaultStartBlockSize;
+  size_t max_block_size = kDefaultMaxBlockSize;
+  void* (*block_alloc)(size_t) = nullptr;
+  void (*block_dealloc)(void*, size_t) = nullptr;
+  ArenaMetricsCollector* metrics_collector = nullptr;
+
+  bool IsDefault() const {
+    return start_block_size == kDefaultMaxBlockSize &&
+           max_block_size == kDefaultMaxBlockSize && block_alloc == nullptr &&
+           block_dealloc == nullptr && metrics_collector == nullptr;
+  }
+};
+
+// Tagged pointer to an AllocationPolicy.
+class TaggedAllocationPolicyPtr {
+ public:
+  constexpr TaggedAllocationPolicyPtr() : policy_(0) {}
+
+  explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy)
+      : policy_(reinterpret_cast<uintptr_t>(policy)) {}
+
+  void set_policy(AllocationPolicy* policy) {
+    auto bits = policy_ & kTagsMask;
+    policy_ = reinterpret_cast<uintptr_t>(policy) | bits;
+  }
+
+  AllocationPolicy* get() {
+    return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask);
+  }
+  const AllocationPolicy* get() const {
+    return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask);
+  }
+
+  AllocationPolicy& operator*() { return *get(); }
+  const AllocationPolicy& operator*() const { return *get(); }
+
+  AllocationPolicy* operator->() { return get(); }
+  const AllocationPolicy* operator->() const { return get(); }
+
+  bool is_user_owned_initial_block() const {
+    return static_cast<bool>(get_mask<kUserOwnedInitialBlock>());
+  }
+  void set_is_user_owned_initial_block(bool v) {
+    set_mask<kUserOwnedInitialBlock>(v);
+  }
+
+  bool should_record_allocs() const {
+    return static_cast<bool>(get_mask<kRecordAllocs>());
+  }
+  void set_should_record_allocs(bool v) { set_mask<kRecordAllocs>(v); }
+
+  uintptr_t get_raw() const { return policy_; }
+
+  inline void RecordAlloc(const std::type_info* allocated_type,
+                          size_t n) const {
+    get()->metrics_collector->OnAlloc(allocated_type, n);
+  }
+
+ private:
+  enum : uintptr_t {
+    kUserOwnedInitialBlock = 1,
+    kRecordAllocs = 2,
+  };
+
+  static constexpr uintptr_t kTagsMask = 7;
+  static constexpr uintptr_t kPtrMask = ~kTagsMask;
+
+  template <uintptr_t kMask>
+  uintptr_t get_mask() const {
+    return policy_ & kMask;
+  }
+  template <uintptr_t kMask>
+  void set_mask(bool v) {
+    if (v) {
+      policy_ |= kMask;
+    } else {
+      policy_ &= ~kMask;
+    }
+  }
+  uintptr_t policy_;
+};
+
+enum class AllocationClient { kDefault, kArray };
+
+// A simple arena allocator. Calls to allocate functions must be properly
+// serialized by the caller, hence this class cannot be used as a general
+// purpose allocator in a multi-threaded program. It serves as a building block
+// for ThreadSafeArena, which provides a thread-safe arena allocator.
+//
+// This class manages
+// 1) Arena bump allocation + owning memory blocks.
+// 2) Maintaining a cleanup list.
+// It delagetes the actual memory allocation back to ThreadSafeArena, which
+// contains the information on block growth policy and backing memory allocation
+// used.
+class PROTOBUF_EXPORT SerialArena {
+ public:
+  struct Memory {
+    void* ptr;
+    size_t size;
+  };
+
+  // Node contains the ptr of the object to be cleaned up and the associated
+  // cleanup function ptr.
+  struct CleanupNode {
+    void* elem;              // Pointer to the object to be cleaned up.
+    void (*cleanup)(void*);  // Function pointer to the destructor or deleter.
+  };
+
+  void CleanupList();
+  uint64_t SpaceAllocated() const {
+    return space_allocated_.load(std::memory_order_relaxed);
+  }
+  uint64_t SpaceUsed() const;
+
+  bool HasSpace(size_t n) const {
+    return n <= static_cast<size_t>(limit_ - ptr_);
+  }
+
+  // See comments on `cached_blocks_` member for details.
+  PROTOBUF_ALWAYS_INLINE void* TryAllocateFromCachedBlock(size_t size) {
+    if (PROTOBUF_PREDICT_FALSE(size < 16)) return nullptr;
+    // We round up to the next larger block in case the memory doesn't match
+    // the pattern we are looking for.
+    const size_t index = Bits::Log2FloorNonZero64(size - 1) - 3;
+
+    if (index >= cached_block_length_) return nullptr;
+    auto& cached_head = cached_blocks_[index];
+    if (cached_head == nullptr) return nullptr;
+
+    void* ret = cached_head;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, size);
+#endif  // ADDRESS_SANITIZER
+    cached_head = cached_head->next;
+    return ret;
+  }
+
+  // In kArray mode we look through cached blocks.
+  // We do not do this by default because most non-array allocations will not
+  // have the right size and will fail to find an appropriate cached block.
+  //
+  // TODO(sbenza): Evaluate if we should use cached blocks for message types of
+  // the right size. We can statically know if the allocation size can benefit
+  // from it.
+  template <AllocationClient alloc_client = AllocationClient::kDefault>
+  void* AllocateAligned(size_t n, const AllocationPolicy* policy) {
+    GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+    GOOGLE_DCHECK_GE(limit_, ptr_);
+
+    if (alloc_client == AllocationClient::kArray) {
+      if (void* res = TryAllocateFromCachedBlock(n)) {
+        return res;
+      }
+    }
+
+    if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) {
+      return AllocateAlignedFallback(n, policy);
+    }
+    return AllocateFromExisting(n);
+  }
+
+ private:
+  void* AllocateFromExisting(size_t n) {
+    void* ret = ptr_;
+    ptr_ += n;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, n);
+#endif  // ADDRESS_SANITIZER
+    return ret;
+  }
+
+  // See comments on `cached_blocks_` member for details.
+  void ReturnArrayMemory(void* p, size_t size) {
+    // We only need to check for 32-bit platforms.
+    // In 64-bit platforms the minimum allocation size from Repeated*Field will
+    // be 16 guaranteed.
+    if (sizeof(void*) < 8) {
+      if (PROTOBUF_PREDICT_FALSE(size < 16)) return;
+    } else {
+      GOOGLE_DCHECK(size >= 16);
+    }
+
+    // We round down to the next smaller block in case the memory doesn't match
+    // the pattern we are looking for. eg, someone might have called Reserve()
+    // on the repeated field.
+    const size_t index = Bits::Log2FloorNonZero64(size) - 4;
+
+    if (PROTOBUF_PREDICT_FALSE(index >= cached_block_length_)) {
+      // We can't put this object on the freelist so make this object the
+      // freelist. It is guaranteed it is larger than the one we have, and
+      // large enough to hold another allocation of `size`.
+      CachedBlock** new_list = static_cast<CachedBlock**>(p);
+      size_t new_size = size / sizeof(CachedBlock*);
+
+      std::copy(cached_blocks_, cached_blocks_ + cached_block_length_,
+                new_list);
+      std::fill(new_list + cached_block_length_, new_list + new_size, nullptr);
+      cached_blocks_ = new_list;
+      // Make the size fit in uint8_t. This is the power of two, so we don't
+      // need anything larger.
+      cached_block_length_ =
+          static_cast<uint8_t>(std::min(size_t{64}, new_size));
+
+      return;
+    }
+
+    auto& cached_head = cached_blocks_[index];
+    auto* new_node = static_cast<CachedBlock*>(p);
+    new_node->next = cached_head;
+    cached_head = new_node;
+#ifdef ADDRESS_SANITIZER
+    ASAN_POISON_MEMORY_REGION(p, size);
+#endif  // ADDRESS_SANITIZER
+  }
+
+ public:
+  // Allocate space if the current region provides enough space.
+  bool MaybeAllocateAligned(size_t n, void** out) {
+    GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+    GOOGLE_DCHECK_GE(limit_, ptr_);
+    if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) return false;
+    *out = AllocateFromExisting(n);
+    return true;
+  }
+
+  std::pair<void*, CleanupNode*> AllocateAlignedWithCleanup(
+      size_t n, const AllocationPolicy* policy) {
+    GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+    if (PROTOBUF_PREDICT_FALSE(!HasSpace(n + kCleanupSize))) {
+      return AllocateAlignedWithCleanupFallback(n, policy);
+    }
+    return AllocateFromExistingWithCleanupFallback(n);
+  }
+
+ private:
+  std::pair<void*, CleanupNode*> AllocateFromExistingWithCleanupFallback(
+      size_t n) {
+    void* ret = ptr_;
+    ptr_ += n;
+    limit_ -= kCleanupSize;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, n);
+    ASAN_UNPOISON_MEMORY_REGION(limit_, kCleanupSize);
+#endif  // ADDRESS_SANITIZER
+    return CreatePair(ret, reinterpret_cast<CleanupNode*>(limit_));
+  }
+
+ public:
+  void AddCleanup(void* elem, void (*cleanup)(void*),
+                  const AllocationPolicy* policy) {
+    auto res = AllocateAlignedWithCleanup(0, policy);
+    res.second->elem = elem;
+    res.second->cleanup = cleanup;
+  }
+
+  void* owner() const { return owner_; }
+  SerialArena* next() const { return next_; }
+  void set_next(SerialArena* next) { next_ = next; }
+
+ private:
+  friend class ThreadSafeArena;
+  friend class ArenaBenchmark;
+
+  // Creates a new SerialArena inside mem using the remaining memory as for
+  // future allocations.
+  static SerialArena* New(SerialArena::Memory mem, void* owner,
+                          ThreadSafeArenaStats* stats);
+  // Free SerialArena returning the memory passed in to New
+  template <typename Deallocator>
+  Memory Free(Deallocator deallocator);
+
+  // Blocks are variable length malloc-ed objects.  The following structure
+  // describes the common header for all blocks.
+  struct Block {
+    Block(Block* next, size_t size) : next(next), size(size), start(nullptr) {}
+
+    char* Pointer(size_t n) {
+      GOOGLE_DCHECK(n <= size);
+      return reinterpret_cast<char*>(this) + n;
+    }
+
+    Block* const next;
+    const size_t size;
+    CleanupNode* start;
+    // data follows
+  };
+
+  void* owner_;            // &ThreadCache of this thread;
+  Block* head_;            // Head of linked list of blocks.
+  SerialArena* next_;      // Next SerialArena in this linked list.
+  size_t space_used_ = 0;  // Necessary for metrics.
+  std::atomic<size_t> space_allocated_;
+
+  // Next pointer to allocate from.  Always 8-byte aligned.  Points inside
+  // head_ (and head_->pos will always be non-canonical).  We keep these
+  // here to reduce indirection.
+  char* ptr_;
+  // Limiting address up to which memory can be allocated from the head block.
+  char* limit_;
+  // For holding sampling information.  The pointer is owned by the
+  // ThreadSafeArena that holds this serial arena.
+  ThreadSafeArenaStats* arena_stats_;
+
+  // Repeated*Field and Arena play together to reduce memory consumption by
+  // reusing blocks. Currently, natural growth of the repeated field types makes
+  // them allocate blocks of size `8 + 2^N, N>=3`.
+  // When the repeated field grows returns the previous block and we put it in
+  // this free list.
+  // `cached_blocks_[i]` points to the free list for blocks of size `8+2^(i+3)`.
+  // The array of freelists is grown when needed in `ReturnArrayMemory()`.
+  struct CachedBlock {
+    // Simple linked list.
+    CachedBlock* next;
+  };
+  uint8_t cached_block_length_ = 0;
+  CachedBlock** cached_blocks_ = nullptr;
+
+  // Constructor is private as only New() should be used.
+  inline SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats);
+  void* AllocateAlignedFallback(size_t n, const AllocationPolicy* policy);
+  std::pair<void*, CleanupNode*> AllocateAlignedWithCleanupFallback(
+      size_t n, const AllocationPolicy* policy);
+  void AllocateNewBlock(size_t n, const AllocationPolicy* policy);
+
+  std::pair<void*, CleanupNode*> CreatePair(void* ptr, CleanupNode* node) {
+    return {ptr, node};
+  }
+
+ public:
+  static constexpr size_t kBlockHeaderSize = AlignUpTo8(sizeof(Block));
+  static constexpr size_t kCleanupSize = AlignUpTo8(sizeof(CleanupNode));
+};
+
+// Tag type used to invoke the constructor of message-owned arena.
+// Only message-owned arenas use this constructor for creation.
+// Such constructors are internal implementation details of the library.
+struct MessageOwned {
+  explicit MessageOwned() = default;
+};
+
+// This class provides the core Arena memory allocation library. Different
+// implementations only need to implement the public interface below.
+// Arena is not a template type as that would only be useful if all protos
+// in turn would be templates, which will/cannot happen. However separating
+// the memory allocation part from the cruft of the API users expect we can
+// use #ifdef the select the best implementation based on hardware / OS.
+class PROTOBUF_EXPORT ThreadSafeArena {
+ public:
+  ThreadSafeArena() { Init(); }
+
+  // Constructor solely used by message-owned arena.
+  ThreadSafeArena(internal::MessageOwned) : tag_and_id_(kMessageOwnedArena) {
+    Init();
+  }
+
+  ThreadSafeArena(char* mem, size_t size) { InitializeFrom(mem, size); }
+
+  explicit ThreadSafeArena(void* mem, size_t size,
+                           const AllocationPolicy& policy) {
+    InitializeWithPolicy(mem, size, policy);
+  }
+
+  // Destructor deletes all owned heap allocated objects, and destructs objects
+  // that have non-trivial destructors, except for proto2 message objects whose
+  // destructors can be skipped. Also, frees all blocks except the initial block
+  // if it was passed in.
+  ~ThreadSafeArena();
+
+  uint64_t Reset();
+
+  uint64_t SpaceAllocated() const;
+  uint64_t SpaceUsed() const;
+
+  template <AllocationClient alloc_client = AllocationClient::kDefault>
+  void* AllocateAligned(size_t n, const std::type_info* type) {
+    SerialArena* arena = nullptr;
+    if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
+                              GetSerialArenaFast(&arena))) {
+      return arena->AllocateAligned<alloc_client>(n, AllocPolicy());
+    } else {
+      return AllocateAlignedFallback(n, type);
+    }
+  }
+
+  void ReturnArrayMemory(void* p, size_t size) {
+    SerialArena* arena = nullptr;
+    if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+      arena->ReturnArrayMemory(p, size);
+    }
+  }
+
+  // This function allocates n bytes if the common happy case is true and
+  // returns true. Otherwise does nothing and returns false. This strange
+  // semantics is necessary to allow callers to program functions that only
+  // have fallback function calls in tail position. This substantially improves
+  // code for the happy path.
+  PROTOBUF_NDEBUG_INLINE bool MaybeAllocateAligned(size_t n, void** out) {
+    SerialArena* arena;
+    if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
+                              GetSerialArenaFromThreadCache(&arena))) {
+      return arena->MaybeAllocateAligned(n, out);
+    }
+    return false;
+  }
+
+  std::pair<void*, SerialArena::CleanupNode*> AllocateAlignedWithCleanup(
+      size_t n, const std::type_info* type);
+
+  // Add object pointer and cleanup function pointer to the list.
+  void AddCleanup(void* elem, void (*cleanup)(void*));
+
+  // Checks whether this arena is message-owned.
+  PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
+    return tag_and_id_ & kMessageOwnedArena;
+  }
+
+ private:
+  // Unique for each arena. Changes on Reset().
+  uint64_t tag_and_id_ = 0;
+  // The LSB of tag_and_id_ indicates if the arena is message-owned.
+  enum : uint64_t { kMessageOwnedArena = 1 };
+
+  TaggedAllocationPolicyPtr alloc_policy_;  // Tagged pointer to AllocPolicy.
+
+  static_assert(std::is_trivially_destructible<SerialArena>{},
+                "SerialArena needs to be trivially destructible.");
+  // Pointer to a linked list of SerialArena.
+  std::atomic<SerialArena*> threads_;
+  std::atomic<SerialArena*> hint_;  // Fast thread-local block access
+
+  const AllocationPolicy* AllocPolicy() const { return alloc_policy_.get(); }
+  void InitializeFrom(void* mem, size_t size);
+  void InitializeWithPolicy(void* mem, size_t size, AllocationPolicy policy);
+  void* AllocateAlignedFallback(size_t n, const std::type_info* type);
+  std::pair<void*, SerialArena::CleanupNode*>
+  AllocateAlignedWithCleanupFallback(size_t n, const std::type_info* type);
+
+  void Init();
+  void SetInitialBlock(void* mem, size_t size);
+
+  // Delete or Destruct all objects owned by the arena.
+  void CleanupList();
+
+  inline uint64_t LifeCycleId() const {
+    return tag_and_id_ & ~kMessageOwnedArena;
+  }
+
+  inline void CacheSerialArena(SerialArena* serial) {
+    thread_cache().last_serial_arena = serial;
+    thread_cache().last_lifecycle_id_seen = tag_and_id_;
+    // TODO(haberman): evaluate whether we would gain efficiency by getting rid
+    // of hint_.  It's the only write we do to ThreadSafeArena in the allocation
+    // path, which will dirty the cache line.
+
+    hint_.store(serial, std::memory_order_release);
+  }
+
+  PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(SerialArena** arena) {
+    if (GetSerialArenaFromThreadCache(arena)) return true;
+
+    // Check whether we own the last accessed SerialArena on this arena.  This
+    // fast path optimizes the case where a single thread uses multiple arenas.
+    ThreadCache* tc = &thread_cache();
+    SerialArena* serial = hint_.load(std::memory_order_acquire);
+    if (PROTOBUF_PREDICT_TRUE(serial != nullptr && serial->owner() == tc)) {
+      *arena = serial;
+      return true;
+    }
+    return false;
+  }
+
+  PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFromThreadCache(
+      SerialArena** arena) {
+    // If this thread already owns a block in this arena then try to use that.
+    // This fast path optimizes the case where multiple threads allocate from
+    // the same arena.
+    ThreadCache* tc = &thread_cache();
+    if (PROTOBUF_PREDICT_TRUE(tc->last_lifecycle_id_seen == tag_and_id_)) {
+      *arena = tc->last_serial_arena;
+      return true;
+    }
+    return false;
+  }
+  SerialArena* GetSerialArenaFallback(void* me);
+
+  template <typename Functor>
+  void PerSerialArena(Functor fn) {
+    // By omitting an Acquire barrier we ensure that any user code that doesn't
+    // properly synchronize Reset() or the destructor will throw a TSAN warning.
+    SerialArena* serial = threads_.load(std::memory_order_relaxed);
+
+    for (; serial; serial = serial->next()) fn(serial);
+  }
+
+  // Releases all memory except the first block which it returns. The first
+  // block might be owned by the user and thus need some extra checks before
+  // deleting.
+  SerialArena::Memory Free(size_t* space_allocated);
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4324)
+#endif
+  struct alignas(kCacheAlignment) ThreadCache {
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+    // If we are using the ThreadLocalStorage class to store the ThreadCache,
+    // then the ThreadCache's default constructor has to be responsible for
+    // initializing it.
+    ThreadCache()
+        : next_lifecycle_id(0),
+          last_lifecycle_id_seen(-1),
+          last_serial_arena(nullptr) {}
+#endif
+
+    // Number of per-thread lifecycle IDs to reserve. Must be power of two.
+    // To reduce contention on a global atomic, each thread reserves a batch of
+    // IDs.  The following number is calculated based on a stress test with
+    // ~6500 threads all frequently allocating a new arena.
+    static constexpr size_t kPerThreadIds = 256;
+    // Next lifecycle ID available to this thread. We need to reserve a new
+    // batch, if `next_lifecycle_id & (kPerThreadIds - 1) == 0`.
+    uint64_t next_lifecycle_id;
+    // The ThreadCache is considered valid as long as this matches the
+    // lifecycle_id of the arena being used.
+    uint64_t last_lifecycle_id_seen;
+    SerialArena* last_serial_arena;
+  };
+
+  // Lifecycle_id can be highly contended variable in a situation of lots of
+  // arena creation. Make sure that other global variables are not sharing the
+  // cacheline.
+#ifdef _MSC_VER
+#pragma warning(disable : 4324)
+#endif
+  struct alignas(kCacheAlignment) CacheAlignedLifecycleIdGenerator {
+    std::atomic<LifecycleIdAtomic> id;
+  };
+  static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_;
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+  // iOS does not support __thread keyword so we use a custom thread local
+  // storage class we implemented.
+  static ThreadCache& thread_cache();
+#elif defined(PROTOBUF_USE_DLLS)
+  // Thread local variables cannot be exposed through DLL interface but we can
+  // wrap them in static functions.
+  static ThreadCache& thread_cache();
+#else
+  static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_;
+  static ThreadCache& thread_cache() { return thread_cache_; }
+#endif
+
+  ThreadSafeArenaStatsHandle arena_stats_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadSafeArena);
+  // All protos have pointers back to the arena hence Arena must have
+  // pointer stability.
+  ThreadSafeArena(ThreadSafeArena&&) = delete;
+  ThreadSafeArena& operator=(ThreadSafeArena&&) = delete;
+
+ public:
+  // kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
+  // to protect the invariant that pos is always at a multiple of 8.
+  static constexpr size_t kBlockHeaderSize = SerialArena::kBlockHeaderSize;
+  static constexpr size_t kSerialArenaSize =
+      (sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
+  static_assert(kBlockHeaderSize % 8 == 0,
+                "kBlockHeaderSize must be a multiple of 8.");
+  static_assert(kSerialArenaSize % 8 == 0,
+                "kSerialArenaSize must be a multiple of 8.");
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ARENA_IMPL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arenastring.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arenastring.h
new file mode 100644
index 0000000..6bc8395
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arenastring.h
@@ -0,0 +1,480 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
+#define GOOGLE_PROTOBUF_ARENASTRING_H__
+
+#include <algorithm>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/explicitly_constructed.h>
+
+// must be last:
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+class EpsCopyInputStream;
+
+class SwapFieldHelper;
+
+// Declared in message_lite.h
+PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
+    fixed_address_empty_string;
+
+// Lazy string instance to support string fields with non-empty default.
+// These are initialized on the first call to .get().
+class PROTOBUF_EXPORT LazyString {
+ public:
+  // We explicitly make LazyString an aggregate so that MSVC can do constant
+  // initialization on it without marking it `constexpr`.
+  // We do not want to use `constexpr` because it makes it harder to have extern
+  // storage for it and causes library bloat.
+  struct InitValue {
+    const char* ptr;
+    size_t size;
+  };
+  // We keep a union of the initialization value and the std::string to save on
+  // space. We don't need the string array after Init() is done.
+  union {
+    mutable InitValue init_value_;
+    alignas(std::string) mutable char string_buf_[sizeof(std::string)];
+  };
+  mutable std::atomic<const std::string*> inited_;
+
+  const std::string& get() const {
+    // This check generates less code than a call-once invocation.
+    auto* res = inited_.load(std::memory_order_acquire);
+    if (PROTOBUF_PREDICT_FALSE(res == nullptr)) return Init();
+    return *res;
+  }
+
+ private:
+  // Initialize the string in `string_buf_`, update `inited_` and return it.
+  // We return it here to avoid having to read it again in the inlined code.
+  const std::string& Init() const;
+};
+
+class TaggedStringPtr {
+ public:
+  // Bit flags qualifying string properties. We can use 2 bits as
+  // ptr_ is guaranteed and enforced to be aligned on 4 byte boundaries.
+  enum Flags {
+    kArenaBit = 0x1,      // ptr is arena allocated
+    kMutableBit = 0x2,    // ptr contents are fully mutable
+    kMask = 0x3           // Bit mask
+  };
+
+  // Composed logical types
+  enum Type {
+    // Default strings are immutable and never owned.
+    kDefault = 0,
+
+    // Allocated strings are mutable and (as the name implies) owned.
+    // A heap allocated string must be deleted.
+    kAllocated = kMutableBit,
+
+    // Mutable arena strings are strings where the string instance is owned
+    // by the arena, but the string contents itself are owned by the string
+    // instance. Mutable arena string instances need to be destroyed which is
+    // typically done through a cleanup action added to the arena owning it.
+    kMutableArena = kArenaBit | kMutableBit,
+
+    // Fixed size arena strings are strings where both the string instance and
+    // the string contents are fully owned by the arena. Fixed size arena
+    // strings are a platform and c++ library specific customization. Fixed
+    // size arena strings are immutable, with the exception of custom internal
+    // updates to the content that fit inside the existing capacity.
+    // Fixed size arena strings must never be deleted or destroyed.
+    kFixedSizeArena = kArenaBit,
+  };
+
+  TaggedStringPtr() = default;
+  explicit constexpr TaggedStringPtr(ExplicitlyConstructedArenaString* ptr)
+      : ptr_(ptr) {}
+
+  // Sets the value to `p`, tagging the value as being a 'default' value.
+  // See documentation for kDefault for more info.
+  inline const std::string* SetDefault(const std::string* p) {
+    return TagAs(kDefault, const_cast<std::string*>(p));
+  }
+
+  // Sets the value to `p`, tagging the value as a heap allocated value.
+  // Allocated strings are mutable and (as the name implies) owned.
+  // `p` must not be null
+  inline std::string* SetAllocated(std::string* p) {
+    return TagAs(kAllocated, p);
+  }
+
+  // Sets the value to `p`, tagging the value as a fixed size arena string.
+  // See documentation for kFixedSizeArena for more info.
+  // `p` must not be null
+  inline std::string* SetFixedSizeArena(std::string* p) {
+    return TagAs(kFixedSizeArena, p);
+  }
+
+  // Sets the value to `p`, tagging the value as a mutable arena string.
+  // See documentation for kMutableArena for more info.
+  // `p` must not be null
+  inline std::string* SetMutableArena(std::string* p) {
+    return TagAs(kMutableArena, p);
+  }
+
+  // Returns true if the contents of the current string are fully mutable.
+  inline bool IsMutable() const { return as_int() & kMutableBit; }
+
+  // Returns true if the current string is an immutable default value.
+  inline bool IsDefault() const { return (as_int() & kMask) == kDefault; }
+
+  // If the current string is a heap-allocated mutable value, returns a pointer
+  // to it.  Returns nullptr otherwise.
+  inline std::string *GetIfAllocated() const {
+    auto allocated = as_int() ^ kAllocated;
+    if (allocated & kMask) return nullptr;
+
+    auto ptr = reinterpret_cast<std::string*>(allocated);
+    PROTOBUF_ASSUME(ptr != nullptr);
+    return ptr;
+  }
+
+  // Returns true if the current string is an arena allocated value.
+  // This means it's either a mutable or fixed size arena string.
+  inline bool IsArena() const { return as_int() & kArenaBit; }
+
+  // Returns true if the current string is a fixed size arena allocated value.
+  inline bool IsFixedSizeArena() const {
+    return (as_int() & kMask) == kFixedSizeArena;
+  }
+
+  // Returns the contained string pointer.
+  inline std::string* Get() const {
+    return reinterpret_cast<std::string*>(as_int() & ~kMask);
+  }
+
+  // Returns true if the contained pointer is null, indicating some error.
+  // The Null value is only used during parsing for temporary values.
+  // A persisted ArenaStringPtr value is never null.
+  inline bool IsNull() { return ptr_ == nullptr; }
+
+ private:
+  static inline void assert_aligned(const void* p) {
+    GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(p) & kMask, 0UL);
+  }
+
+  inline std::string* TagAs(Type type, std::string* p) {
+    GOOGLE_DCHECK(p != nullptr);
+    assert_aligned(p);
+    ptr_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) | type);
+    return p;
+  }
+
+  uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
+  void* ptr_;
+};
+
+static_assert(std::is_trivial<TaggedStringPtr>::value,
+              "TaggedStringPtr must be trivial");
+
+// This class encapsulates a pointer to a std::string with or without arena
+// owned contents, tagged by the bottom bits of the string pointer. It is a
+// high-level wrapper that almost directly corresponds to the interface required
+// by string fields in generated code. It replaces the old std::string* pointer
+// in such cases.
+//
+// The string pointer is tagged to be either a default, externally owned value,
+// a mutable heap allocated value, or an arena allocated value. The object uses
+// a single global instance of an empty string that is used as the initial
+// default value. Fields that have empty default values directly use this global
+// default. Fields that have non empty default values are supported through
+// lazily initialized default values managed by the LazyString class.
+//
+// Generated code and reflection code both ensure that ptr_ is never null.
+// Because ArenaStringPtr is used in oneof unions, its constructor is a NOP and
+// the field is always manually initialized via method calls.
+//
+// See TaggedStringPtr for more information about the types of string values
+// being held, and the mutable and ownership invariants for each type.
+struct PROTOBUF_EXPORT ArenaStringPtr {
+  ArenaStringPtr() = default;
+  constexpr ArenaStringPtr(ExplicitlyConstructedArenaString* default_value,
+                           ConstantInitialized)
+      : tagged_ptr_(default_value) {}
+
+  // Called from generated code / reflection runtime only. Resets value to point
+  // to a default string pointer, with the semantics that this ArenaStringPtr
+  // does not own the pointed-to memory. Disregards initial value of ptr_ (so
+  // this is the *ONLY* safe method to call after construction or when
+  // reinitializing after becoming the active field in a oneof union).
+  inline void InitDefault();
+
+  // Similar to `InitDefault` except that it allows the default value to be
+  // initialized to an externally owned string. This method is called from
+  // parsing code. `str` must not be null and outlive this instance.
+  inline void InitExternal(const std::string* str);
+
+  // Called from generated code / reflection runtime only. Resets the value of
+  // this instances to the heap allocated value in `str`. `str` must not be
+  // null. Invokes `arena->Own(str)` to transfer ownership into the arena if
+  // `arena` is not null, else, `str` will be owned by ArenaStringPtr. This
+  // function should only be used to initialize a ArenaStringPtr or on an
+  // instance known to not carry any heap allocated value.
+  inline void InitAllocated(std::string* str, Arena* arena);
+
+  void Set(ConstStringParam value, Arena* arena);
+  void Set(std::string&& value, Arena* arena);
+  void Set(const char* s, Arena* arena);
+  void Set(const char* s, size_t n, Arena* arena);
+
+  void SetBytes(ConstStringParam value, Arena* arena);
+  void SetBytes(std::string&& value, Arena* arena);
+  void SetBytes(const char* s, Arena* arena);
+  void SetBytes(const void* p, size_t n, Arena* arena);
+
+  template <typename RefWrappedType>
+  void Set(std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena) {
+    Set(const_string_ref.get(), arena);
+  }
+
+  // Returns a mutable std::string reference.
+  // The version accepting a `LazyString` value is used in the generated code to
+  // initialize mutable copies for fields with a non-empty default where the
+  // default value is lazily initialized.
+  std::string* Mutable(Arena* arena);
+  std::string* Mutable(const LazyString& default_value, Arena* arena);
+
+  // Gets a mutable pointer with unspecified contents.
+  // This function is identical to Mutable(), except it is optimized for the
+  // case where the caller is not interested in the current contents. For
+  // example, if the current field is not mutable, it will re-initialize the
+  // value with an empty string rather than a (non-empty) default value.
+  // Likewise, if the current value is a fixed size arena string with contents,
+  // it will be initialized into an empty mutable arena string.
+  std::string* MutableNoCopy(Arena* arena);
+
+  // Basic accessors.
+  PROTOBUF_NDEBUG_INLINE const std::string& Get() const {
+    // Unconditionally mask away the tag.
+    return *tagged_ptr_.Get();
+  }
+
+  // Returns a pointer to the stored contents for this instance.
+  // This method is for internal debugging and tracking purposes only.
+  PROTOBUF_NDEBUG_INLINE const std::string* UnsafeGetPointer() const
+      PROTOBUF_RETURNS_NONNULL {
+    return tagged_ptr_.Get();
+  }
+
+  // Release returns a std::string* instance that is heap-allocated and is not
+  // Own()'d by any arena. If the field is not set, this returns nullptr. The
+  // caller retains ownership. Clears this field back to the default state.
+  // Used to implement release_<field>() methods on generated classes.
+  PROTOBUF_NODISCARD std::string* Release();
+
+  // Takes a std::string that is heap-allocated, and takes ownership. The
+  // std::string's destructor is registered with the arena. Used to implement
+  // set_allocated_<field> in generated classes.
+  void SetAllocated(std::string* value, Arena* arena);
+
+  // Frees storage (if not on an arena).
+  void Destroy();
+
+  // Clears content, but keeps allocated std::string, to avoid the overhead of
+  // heap operations. After this returns, the content (as seen by the user) will
+  // always be the empty std::string. Assumes that |default_value| is an empty
+  // std::string.
+  void ClearToEmpty();
+
+  // Clears content, assuming that the current value is not the empty
+  // string default.
+  void ClearNonDefaultToEmpty();
+
+  // Clears content, but keeps allocated std::string if arena != nullptr, to
+  // avoid the overhead of heap operations. After this returns, the content
+  // (as seen by the user) will always be equal to |default_value|.
+  void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
+
+  // Swaps internal pointers. Arena-safety semantics: this is guarded by the
+  // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
+  // 'unsafe' if called directly.
+  inline PROTOBUF_NDEBUG_INLINE static void InternalSwap(ArenaStringPtr* rhs,
+                                                         Arena* rhs_arena,
+                                                         ArenaStringPtr* lhs,
+                                                         Arena* lhs_arena);
+
+  // Internal setter used only at parse time to directly set a donated string
+  // value.
+  void UnsafeSetTaggedPointer(TaggedStringPtr value) { tagged_ptr_ = value; }
+  // Generated code only! An optimization, in certain cases the generated
+  // code is certain we can obtain a std::string with no default checks and
+  // tag tests.
+  std::string* UnsafeMutablePointer() PROTOBUF_RETURNS_NONNULL;
+
+  // Returns true if this instances holds an immutable default value.
+  inline bool IsDefault() const { return tagged_ptr_.IsDefault(); }
+
+ private:
+  template <typename... Args>
+  inline std::string* NewString(Arena* arena, Args&&... args) {
+    if (arena == nullptr) {
+      auto* s = new std::string(std::forward<Args>(args)...);
+      return tagged_ptr_.SetAllocated(s);
+    } else {
+      auto* s = Arena::Create<std::string>(arena, std::forward<Args>(args)...);
+      return tagged_ptr_.SetMutableArena(s);
+    }
+  }
+
+  TaggedStringPtr tagged_ptr_;
+
+  bool IsFixedSizeArena() const { return false; }
+
+  // Swaps tagged pointer without debug hardening. This is to allow python
+  // protobuf to maintain pointer stability even in DEBUG builds.
+  inline PROTOBUF_NDEBUG_INLINE static void UnsafeShallowSwap(
+      ArenaStringPtr* rhs, ArenaStringPtr* lhs) {
+    std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
+  }
+
+  friend class ::google::protobuf::internal::SwapFieldHelper;
+  friend class TcParser;
+
+  // Slow paths.
+
+  // MutableSlow requires that !IsString() || IsDefault
+  // Variadic to support 0 args for empty default and 1 arg for LazyString.
+  template <typename... Lazy>
+  std::string* MutableSlow(::google::protobuf::Arena* arena, const Lazy&... lazy_default);
+
+  friend class EpsCopyInputStream;
+};
+
+inline void ArenaStringPtr::InitDefault() {
+  tagged_ptr_ = TaggedStringPtr(&fixed_address_empty_string);
+}
+
+inline void ArenaStringPtr::InitExternal(const std::string* str) {
+  tagged_ptr_.SetDefault(str);
+}
+
+inline void ArenaStringPtr::InitAllocated(std::string* str, Arena* arena) {
+  if (arena != nullptr) {
+    tagged_ptr_.SetMutableArena(str);
+    arena->Own(str);
+  } else {
+    tagged_ptr_.SetAllocated(str);
+  }
+}
+
+inline void ArenaStringPtr::Set(const char* s, Arena* arena) {
+  Set(ConstStringParam{s}, arena);
+}
+
+inline void ArenaStringPtr::Set(const char* s, size_t n, Arena* arena) {
+  Set(ConstStringParam{s, n}, arena);
+}
+
+inline void ArenaStringPtr::SetBytes(ConstStringParam value, Arena* arena) {
+  Set(value, arena);
+}
+
+inline void ArenaStringPtr::SetBytes(std::string&& value, Arena* arena) {
+  Set(std::move(value), arena);
+}
+
+inline void ArenaStringPtr::SetBytes(const char* s, Arena* arena) {
+  Set(s, arena);
+}
+
+inline void ArenaStringPtr::SetBytes(const void* p, size_t n, Arena* arena) {
+  Set(ConstStringParam{static_cast<const char*>(p), n}, arena);
+}
+
+// Make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
+inline PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap(  //
+    ArenaStringPtr* rhs, Arena* rhs_arena,                        //
+    ArenaStringPtr* lhs, Arena* lhs_arena) {
+  // Silence unused variable warnings in release buildls.
+  (void)rhs_arena;
+  (void)lhs_arena;
+  std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  auto force_realloc = [](ArenaStringPtr* p, Arena* arena) {
+    if (p->IsDefault()) return;
+    std::string* old_value = p->tagged_ptr_.Get();
+    std::string* new_value =
+        p->IsFixedSizeArena()
+            ? Arena::Create<std::string>(arena, *old_value)
+            : Arena::Create<std::string>(arena, std::move(*old_value));
+    if (arena == nullptr) {
+      delete old_value;
+      p->tagged_ptr_.SetAllocated(new_value);
+    } else {
+      p->tagged_ptr_.SetMutableArena(new_value);
+    }
+  };
+  // Because, at this point, tagged_ptr_ has been swapped, arena should also be
+  // swapped.
+  force_realloc(lhs, rhs_arena);
+  force_realloc(rhs, lhs_arena);
+#endif  // PROTOBUF_FORCE_COPY_IN_SWAP
+}
+
+inline void ArenaStringPtr::ClearNonDefaultToEmpty() {
+  // Unconditionally mask away the tag.
+  tagged_ptr_.Get()->clear();
+}
+
+inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
+  GOOGLE_DCHECK(tagged_ptr_.IsMutable());
+  GOOGLE_DCHECK(tagged_ptr_.Get() != nullptr);
+  return tagged_ptr_.Get();
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ARENASTRING_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arenaz_sampler.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arenaz_sampler.h
new file mode 100644
index 0000000..b04b0cc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/arenaz_sampler.h
@@ -0,0 +1,207 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
+#define GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+struct ThreadSafeArenaStats;
+void RecordResetSlow(ThreadSafeArenaStats* info);
+void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
+                        size_t allocated, size_t wasted);
+// Stores information about a sampled thread safe arena.  All mutations to this
+// *must* be made through `Record*` functions below.  All reads from this *must*
+// only occur in the callback to `ThreadSafeArenazSampler::Iterate`.
+struct ThreadSafeArenaStats
+    : public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
+  // Constructs the object but does not fill in any fields.
+  ThreadSafeArenaStats();
+  ~ThreadSafeArenaStats();
+
+  // Puts the object into a clean state, fills in the logically `const` members,
+  // blocking for any readers that are currently sampling the object.
+  void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+
+  // These fields are mutated by the various Record* APIs and need to be
+  // thread-safe.
+  std::atomic<int> num_allocations;
+  std::atomic<int> num_resets;
+  std::atomic<size_t> bytes_requested;
+  std::atomic<size_t> bytes_allocated;
+  std::atomic<size_t> bytes_wasted;
+  // Records the largest size an arena ever had.  Maintained across resets.
+  std::atomic<size_t> max_bytes_allocated;
+  // Bit i when set to 1 indicates that a thread with tid % 63 = i accessed the
+  // underlying arena.  The field is maintained across resets.
+  std::atomic<uint64_t> thread_ids;
+
+  // All of the fields below are set by `PrepareForSampling`, they must not
+  // be mutated in `Record*` functions.  They are logically `const` in that
+  // sense. These are guarded by init_mu, but that is not externalized to
+  // clients, who can only read them during
+  // `ThreadSafeArenazSampler::Iterate` which will hold the lock.
+  static constexpr int kMaxStackDepth = 64;
+  int32_t depth;
+  void* stack[kMaxStackDepth];
+  static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t requested,
+                                  size_t allocated, size_t wasted) {
+    if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
+    RecordAllocateSlow(info, requested, allocated, wasted);
+  }
+};
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(ThreadSafeArenaStats* info);
+
+class ThreadSafeArenaStatsHandle {
+ public:
+  explicit ThreadSafeArenaStatsHandle() = default;
+  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
+      : info_(info) {}
+
+  ~ThreadSafeArenaStatsHandle() {
+    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
+    UnsampleSlow(info_);
+  }
+
+  ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
+      : info_(absl::exchange(other.info_, nullptr)) {}
+
+  ThreadSafeArenaStatsHandle& operator=(
+      ThreadSafeArenaStatsHandle&& other) noexcept {
+    if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
+      UnsampleSlow(info_);
+    }
+    info_ = absl::exchange(other.info_, nullptr);
+    return *this;
+  }
+
+  void RecordReset() {
+    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordResetSlow(info_);
+  }
+
+  ThreadSafeArenaStats* MutableStats() { return info_; }
+
+  friend void swap(ThreadSafeArenaStatsHandle& lhs,
+                   ThreadSafeArenaStatsHandle& rhs) {
+    std::swap(lhs.info_, rhs.info_);
+  }
+
+  friend class ThreadSafeArenaStatsHandlePeer;
+
+ private:
+  ThreadSafeArenaStats* info_ = nullptr;
+};
+
+using ThreadSafeArenazSampler =
+    ::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
+
+extern PROTOBUF_THREAD_LOCAL int64_t global_next_sample;
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline ThreadSafeArenaStatsHandle Sample() {
+  if (PROTOBUF_PREDICT_TRUE(--global_next_sample > 0)) {
+    return ThreadSafeArenaStatsHandle(nullptr);
+  }
+  return ThreadSafeArenaStatsHandle(SampleSlow(&global_next_sample));
+}
+
+#else
+struct ThreadSafeArenaStats {
+  static void RecordAllocateStats(ThreadSafeArenaStats*, size_t /*requested*/,
+                                  size_t /*allocated*/, size_t /*wasted*/) {}
+};
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(ThreadSafeArenaStats* info);
+
+class ThreadSafeArenaStatsHandle {
+ public:
+  explicit ThreadSafeArenaStatsHandle() = default;
+  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
+
+  void RecordReset() {}
+
+  ThreadSafeArenaStats* MutableStats() { return nullptr; }
+
+  friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
+
+ private:
+  friend class ThreadSafeArenaStatsHandlePeer;
+};
+
+class ThreadSafeArenazSampler {
+ public:
+  void Unregister(ThreadSafeArenaStats*) {}
+  void SetMaxSamples(int32_t) {}
+};
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline ThreadSafeArenaStatsHandle Sample() {
+  return ThreadSafeArenaStatsHandle(nullptr);
+}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+// Returns a global Sampler.
+ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
+
+// Enables or disables sampling for thread safe arenas.
+void SetThreadSafeArenazEnabled(bool enabled);
+
+// Sets the rate at which thread safe arena will be sampled.
+void SetThreadSafeArenazSampleParameter(int32_t rate);
+
+// Sets a soft max for the number of samples that will be kept.
+void SetThreadSafeArenazMaxSamples(int32_t max);
+
+// Sets the current value for when arenas should be next sampled.
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_SRC_PROTOBUF_ARENAZ_SAMPLER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/compiler/importer.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/compiler/importer.h
new file mode 100644
index 0000000..2fb88b9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/compiler/importer.h
@@ -0,0 +1,338 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file is the public interface to the .proto file parser.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
+#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/compiler/parser.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class ZeroCopyInputStream;
+}
+
+namespace compiler {
+
+// Defined in this file.
+class Importer;
+class MultiFileErrorCollector;
+class SourceTree;
+class DiskSourceTree;
+
+// TODO(kenton):  Move all SourceTree stuff to a separate file?
+
+// An implementation of DescriptorDatabase which loads files from a SourceTree
+// and parses them.
+//
+// Note:  This class is not thread-safe since it maintains a table of source
+//   code locations for error reporting.  However, when a DescriptorPool wraps
+//   a DescriptorDatabase, it uses mutex locking to make sure only one method
+//   of the database is called at a time, even if the DescriptorPool is used
+//   from multiple threads.  Therefore, there is only a problem if you create
+//   multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase
+//   and use them from multiple threads.
+//
+// Note:  This class does not implement FindFileContainingSymbol() or
+//   FindFileContainingExtension(); these will always return false.
+class PROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase {
+ public:
+  SourceTreeDescriptorDatabase(SourceTree* source_tree);
+
+  // If non-NULL, fallback_database will be checked if a file doesn't exist in
+  // the specified source_tree.
+  SourceTreeDescriptorDatabase(SourceTree* source_tree,
+                               DescriptorDatabase* fallback_database);
+  ~SourceTreeDescriptorDatabase() override;
+
+  // Instructs the SourceTreeDescriptorDatabase to report any parse errors
+  // to the given MultiFileErrorCollector.  This should be called before
+  // parsing.  error_collector must remain valid until either this method
+  // is called again or the SourceTreeDescriptorDatabase is destroyed.
+  void RecordErrorsTo(MultiFileErrorCollector* error_collector) {
+    error_collector_ = error_collector;
+  }
+
+  // Gets a DescriptorPool::ErrorCollector which records errors to the
+  // MultiFileErrorCollector specified with RecordErrorsTo().  This collector
+  // has the ability to determine exact line and column numbers of errors
+  // from the information given to it by the DescriptorPool.
+  DescriptorPool::ErrorCollector* GetValidationErrorCollector() {
+    using_validation_error_collector_ = true;
+    return &validation_error_collector_;
+  }
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+
+ private:
+  class SingleFileErrorCollector;
+
+  SourceTree* source_tree_;
+  DescriptorDatabase* fallback_database_;
+  MultiFileErrorCollector* error_collector_;
+
+  class PROTOBUF_EXPORT ValidationErrorCollector
+      : public DescriptorPool::ErrorCollector {
+   public:
+    ValidationErrorCollector(SourceTreeDescriptorDatabase* owner);
+    ~ValidationErrorCollector() override;
+
+    // implements ErrorCollector ---------------------------------------
+    void AddError(const std::string& filename, const std::string& element_name,
+                  const Message* descriptor, ErrorLocation location,
+                  const std::string& message) override;
+
+    void AddWarning(const std::string& filename,
+                    const std::string& element_name, const Message* descriptor,
+                    ErrorLocation location,
+                    const std::string& message) override;
+
+   private:
+    SourceTreeDescriptorDatabase* owner_;
+  };
+  friend class ValidationErrorCollector;
+
+  bool using_validation_error_collector_;
+  SourceLocationTable source_locations_;
+  ValidationErrorCollector validation_error_collector_;
+};
+
+// Simple interface for parsing .proto files.  This wraps the process
+// of opening the file, parsing it with a Parser, recursively parsing all its
+// imports, and then cross-linking the results to produce a FileDescriptor.
+//
+// This is really just a thin wrapper around SourceTreeDescriptorDatabase.
+// You may find that SourceTreeDescriptorDatabase is more flexible.
+//
+// TODO(kenton):  I feel like this class is not well-named.
+class PROTOBUF_EXPORT Importer {
+ public:
+  Importer(SourceTree* source_tree, MultiFileErrorCollector* error_collector);
+  ~Importer();
+
+  // Import the given file and build a FileDescriptor representing it.  If
+  // the file is already in the DescriptorPool, the existing FileDescriptor
+  // will be returned.  The FileDescriptor is property of the DescriptorPool,
+  // and will remain valid until it is destroyed.  If any errors occur, they
+  // will be reported using the error collector and Import() will return NULL.
+  //
+  // A particular Importer object will only report errors for a particular
+  // file once.  All future attempts to import the same file will return NULL
+  // without reporting any errors.  The idea is that you might want to import
+  // a lot of files without seeing the same errors over and over again.  If
+  // you want to see errors for the same files repeatedly, you can use a
+  // separate Importer object to import each one (but use the same
+  // DescriptorPool so that they can be cross-linked).
+  const FileDescriptor* Import(const std::string& filename);
+
+  // The DescriptorPool in which all imported FileDescriptors and their
+  // contents are stored.
+  inline const DescriptorPool* pool() const { return &pool_; }
+
+  void AddUnusedImportTrackFile(const std::string& file_name,
+                                bool is_error = false);
+  void ClearUnusedImportTrackFiles();
+
+
+ private:
+  SourceTreeDescriptorDatabase database_;
+  DescriptorPool pool_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer);
+};
+
+// If the importer encounters problems while trying to import the proto files,
+// it reports them to a MultiFileErrorCollector.
+class PROTOBUF_EXPORT MultiFileErrorCollector {
+ public:
+  inline MultiFileErrorCollector() {}
+  virtual ~MultiFileErrorCollector();
+
+  // Line and column numbers are zero-based.  A line number of -1 indicates
+  // an error with the entire file (e.g. "not found").
+  virtual void AddError(const std::string& filename, int line, int column,
+                        const std::string& message) = 0;
+
+  virtual void AddWarning(const std::string& /* filename */, int /* line */,
+                          int /* column */, const std::string& /* message */) {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector);
+};
+
+// Abstract interface which represents a directory tree containing proto files.
+// Used by the default implementation of Importer to resolve import statements
+// Most users will probably want to use the DiskSourceTree implementation,
+// below.
+class PROTOBUF_EXPORT SourceTree {
+ public:
+  inline SourceTree() {}
+  virtual ~SourceTree();
+
+  // Open the given file and return a stream that reads it, or NULL if not
+  // found.  The caller takes ownership of the returned object.  The filename
+  // must be a path relative to the root of the source tree and must not
+  // contain "." or ".." components.
+  virtual io::ZeroCopyInputStream* Open(const std::string& filename) = 0;
+
+  // If Open() returns NULL, calling this method immediately will return an
+  // description of the error.
+  // Subclasses should implement this method and return a meaningful value for
+  // better error reporting.
+  // TODO(xiaofeng): change this to a pure virtual function.
+  virtual std::string GetLastErrorMessage();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree);
+};
+
+// An implementation of SourceTree which loads files from locations on disk.
+// Multiple mappings can be set up to map locations in the DiskSourceTree to
+// locations in the physical filesystem.
+class PROTOBUF_EXPORT DiskSourceTree : public SourceTree {
+ public:
+  DiskSourceTree();
+  ~DiskSourceTree() override;
+
+  // Map a path on disk to a location in the SourceTree.  The path may be
+  // either a file or a directory.  If it is a directory, the entire tree
+  // under it will be mapped to the given virtual location.  To map a directory
+  // to the root of the source tree, pass an empty string for virtual_path.
+  //
+  // If multiple mapped paths apply when opening a file, they will be searched
+  // in order.  For example, if you do:
+  //   MapPath("bar", "foo/bar");
+  //   MapPath("", "baz");
+  // and then you do:
+  //   Open("bar/qux");
+  // the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux,
+  // returning the first one that opens successfully.
+  //
+  // disk_path may be an absolute path or relative to the current directory,
+  // just like a path you'd pass to open().
+  void MapPath(const std::string& virtual_path, const std::string& disk_path);
+
+  // Return type for DiskFileToVirtualFile().
+  enum DiskFileToVirtualFileResult {
+    SUCCESS,
+    SHADOWED,
+    CANNOT_OPEN,
+    NO_MAPPING
+  };
+
+  // Given a path to a file on disk, find a virtual path mapping to that
+  // file.  The first mapping created with MapPath() whose disk_path contains
+  // the filename is used.  However, that virtual path may not actually be
+  // usable to open the given file.  Possible return values are:
+  // * SUCCESS: The mapping was found.  *virtual_file is filled in so that
+  //   calling Open(*virtual_file) will open the file named by disk_file.
+  // * SHADOWED: A mapping was found, but using Open() to open this virtual
+  //   path will end up returning some different file.  This is because some
+  //   other mapping with a higher precedence also matches this virtual path
+  //   and maps it to a different file that exists on disk.  *virtual_file
+  //   is filled in as it would be in the SUCCESS case.  *shadowing_disk_file
+  //   is filled in with the disk path of the file which would be opened if
+  //   you were to call Open(*virtual_file).
+  // * CANNOT_OPEN: The mapping was found and was not shadowed, but the
+  //   file specified cannot be opened.  When this value is returned,
+  //   errno will indicate the reason the file cannot be opened.  *virtual_file
+  //   will be set to the virtual path as in the SUCCESS case, even though
+  //   it is not useful.
+  // * NO_MAPPING: Indicates that no mapping was found which contains this
+  //   file.
+  DiskFileToVirtualFileResult DiskFileToVirtualFile(
+      const std::string& disk_file, std::string* virtual_file,
+      std::string* shadowing_disk_file);
+
+  // Given a virtual path, find the path to the file on disk.
+  // Return true and update disk_file with the on-disk path if the file exists.
+  // Return false and leave disk_file untouched if the file doesn't exist.
+  bool VirtualFileToDiskFile(const std::string& virtual_file,
+                             std::string* disk_file);
+
+  // implements SourceTree -------------------------------------------
+  io::ZeroCopyInputStream* Open(const std::string& filename) override;
+
+  std::string GetLastErrorMessage() override;
+
+ private:
+  struct Mapping {
+    std::string virtual_path;
+    std::string disk_path;
+
+    inline Mapping(const std::string& virtual_path_param,
+                   const std::string& disk_path_param)
+        : virtual_path(virtual_path_param), disk_path(disk_path_param) {}
+  };
+  std::vector<Mapping> mappings_;
+  std::string last_error_message_;
+
+  // Like Open(), but returns the on-disk path in disk_file if disk_file is
+  // non-NULL and the file could be successfully opened.
+  io::ZeroCopyInputStream* OpenVirtualFile(const std::string& virtual_file,
+                                           std::string* disk_file);
+
+  // Like Open() but given the actual on-disk path.
+  io::ZeroCopyInputStream* OpenDiskFile(const std::string& filename);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree);
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/compiler/parser.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/compiler/parser.h
new file mode 100644
index 0000000..d4eb763
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/compiler/parser.h
@@ -0,0 +1,602 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Implements parsing of .proto files to FileDescriptorProtos.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__
+#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/repeated_field.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace compiler {
+
+// Defined in this file.
+class Parser;
+class SourceLocationTable;
+
+// Implements parsing of protocol definitions (such as .proto files).
+//
+// Note that most users will be more interested in the Importer class.
+// Parser is a lower-level class which simply converts a single .proto file
+// to a FileDescriptorProto.  It does not resolve import directives or perform
+// many other kinds of validation needed to construct a complete
+// FileDescriptor.
+class PROTOBUF_EXPORT Parser {
+ public:
+  Parser();
+  ~Parser();
+
+  // Parse the entire input and construct a FileDescriptorProto representing
+  // it.  Returns true if no errors occurred, false otherwise.
+  bool Parse(io::Tokenizer* input, FileDescriptorProto* file);
+
+  // Optional features:
+
+  // DEPRECATED:  New code should use the SourceCodeInfo embedded in the
+  //   FileDescriptorProto.
+  //
+  // Requests that locations of certain definitions be recorded to the given
+  // SourceLocationTable while parsing.  This can be used to look up exact line
+  // and column numbers for errors reported by DescriptorPool during validation.
+  // Set to NULL (the default) to discard source location information.
+  void RecordSourceLocationsTo(SourceLocationTable* location_table) {
+    source_location_table_ = location_table;
+  }
+
+  // Requests that errors be recorded to the given ErrorCollector while
+  // parsing.  Set to NULL (the default) to discard error messages.
+  void RecordErrorsTo(io::ErrorCollector* error_collector) {
+    error_collector_ = error_collector;
+  }
+
+  // Returns the identifier used in the "syntax = " declaration, if one was
+  // seen during the last call to Parse(), or the empty string otherwise.
+  const std::string& GetSyntaxIdentifier() { return syntax_identifier_; }
+
+  // If set true, input files will be required to begin with a syntax
+  // identifier.  Otherwise, files may omit this.  If a syntax identifier
+  // is provided, it must be 'syntax = "proto2";' and must appear at the
+  // top of this file regardless of whether or not it was required.
+  void SetRequireSyntaxIdentifier(bool value) {
+    require_syntax_identifier_ = value;
+  }
+
+  // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop
+  // parsing as soon as it has seen the syntax identifier, or lack thereof.
+  // This is useful for quickly identifying the syntax of the file without
+  // parsing the whole thing.  If this is enabled, no error will be recorded
+  // if the syntax identifier is something other than "proto2" (since
+  // presumably the caller intends to deal with that), but other kinds of
+  // errors (e.g. parse errors) will still be reported.  When this is enabled,
+  // you may pass a NULL FileDescriptorProto to Parse().
+  void SetStopAfterSyntaxIdentifier(bool value) {
+    stop_after_syntax_identifier_ = value;
+  }
+
+ private:
+  class LocationRecorder;
+  struct MapField;
+
+  // =================================================================
+  // Error recovery helpers
+
+  // Consume the rest of the current statement.  This consumes tokens
+  // until it sees one of:
+  //   ';'  Consumes the token and returns.
+  //   '{'  Consumes the brace then calls SkipRestOfBlock().
+  //   '}'  Returns without consuming.
+  //   EOF  Returns (can't consume).
+  // The Parser often calls SkipStatement() after encountering a syntax
+  // error.  This allows it to go on parsing the following lines, allowing
+  // it to report more than just one error in the file.
+  void SkipStatement();
+
+  // Consume the rest of the current block, including nested blocks,
+  // ending after the closing '}' is encountered and consumed, or at EOF.
+  void SkipRestOfBlock();
+
+  // -----------------------------------------------------------------
+  // Single-token consuming helpers
+  //
+  // These make parsing code more readable.
+
+  // True if the current token is TYPE_END.
+  inline bool AtEnd();
+
+  // True if the next token matches the given text.
+  inline bool LookingAt(const char* text);
+  // True if the next token is of the given type.
+  inline bool LookingAtType(io::Tokenizer::TokenType token_type);
+
+  // If the next token exactly matches the text given, consume it and return
+  // true.  Otherwise, return false without logging an error.
+  bool TryConsume(const char* text);
+
+  // These attempt to read some kind of token from the input.  If successful,
+  // they return true.  Otherwise they return false and add the given error
+  // to the error list.
+
+  // Consume a token with the exact text given.
+  bool Consume(const char* text, const char* error);
+  // Same as above, but automatically generates the error "Expected \"text\".",
+  // where "text" is the expected token text.
+  bool Consume(const char* text);
+  // Consume a token of type IDENTIFIER and store its text in "output".
+  bool ConsumeIdentifier(std::string* output, const char* error);
+  // Consume an integer and store its value in "output".
+  bool ConsumeInteger(int* output, const char* error);
+  // Consume a signed integer and store its value in "output".
+  bool ConsumeSignedInteger(int* output, const char* error);
+  // Consume a 64-bit integer and store its value in "output".  If the value
+  // is greater than max_value, an error will be reported.
+  bool ConsumeInteger64(uint64_t max_value, uint64_t* output,
+                        const char* error);
+  // Consume a number and store its value in "output".  This will accept
+  // tokens of either INTEGER or FLOAT type.
+  bool ConsumeNumber(double* output, const char* error);
+  // Consume a string literal and store its (unescaped) value in "output".
+  bool ConsumeString(std::string* output, const char* error);
+
+  // Consume a token representing the end of the statement.  Comments between
+  // this token and the next will be harvested for documentation.  The given
+  // LocationRecorder should refer to the declaration that was just parsed;
+  // it will be populated with these comments.
+  //
+  // TODO(kenton):  The LocationRecorder is const because historically locations
+  //   have been passed around by const reference, for no particularly good
+  //   reason.  We should probably go through and change them all to mutable
+  //   pointer to make this more intuitive.
+  bool TryConsumeEndOfDeclaration(const char* text,
+                                  const LocationRecorder* location);
+  bool TryConsumeEndOfDeclarationFinishScope(const char* text,
+                                             const LocationRecorder* location);
+
+  bool ConsumeEndOfDeclaration(const char* text,
+                               const LocationRecorder* location);
+
+  // -----------------------------------------------------------------
+  // Error logging helpers
+
+  // Invokes error_collector_->AddError(), if error_collector_ is not NULL.
+  void AddError(int line, int column, const std::string& error);
+
+  // Invokes error_collector_->AddError() with the line and column number
+  // of the current token.
+  void AddError(const std::string& error);
+
+  // Invokes error_collector_->AddWarning() with the line and column number
+  // of the current token.
+  void AddWarning(const std::string& warning);
+
+  // Records a location in the SourceCodeInfo.location table (see
+  // descriptor.proto).  We use RAII to ensure that the start and end locations
+  // are recorded -- the constructor records the start location and the
+  // destructor records the end location.  Since the parser is
+  // recursive-descent, this works out beautifully.
+  class PROTOBUF_EXPORT LocationRecorder {
+   public:
+    // Construct the file's "root" location.
+    LocationRecorder(Parser* parser);
+
+    // Construct a location that represents a declaration nested within the
+    // given parent.  E.g. a field's location is nested within the location
+    // for a message type.  The parent's path will be copied, so you should
+    // call AddPath() only to add the path components leading from the parent
+    // to the child (as opposed to leading from the root to the child).
+    LocationRecorder(const LocationRecorder& parent);
+
+    // Convenience constructors that call AddPath() one or two times.
+    LocationRecorder(const LocationRecorder& parent, int path1);
+    LocationRecorder(const LocationRecorder& parent, int path1, int path2);
+
+    // Creates a recorder that generates locations into given source code info.
+    LocationRecorder(const LocationRecorder& parent, int path1,
+                     SourceCodeInfo* source_code_info);
+
+    ~LocationRecorder();
+
+    // Add a path component.  See SourceCodeInfo.Location.path in
+    // descriptor.proto.
+    void AddPath(int path_component);
+
+    // By default the location is considered to start at the current token at
+    // the time the LocationRecorder is created.  StartAt() sets the start
+    // location to the given token instead.
+    void StartAt(const io::Tokenizer::Token& token);
+
+    // Start at the same location as some other LocationRecorder.
+    void StartAt(const LocationRecorder& other);
+
+    // By default the location is considered to end at the previous token at
+    // the time the LocationRecorder is destroyed.  EndAt() sets the end
+    // location to the given token instead.
+    void EndAt(const io::Tokenizer::Token& token);
+
+    // Records the start point of this location to the SourceLocationTable that
+    // was passed to RecordSourceLocationsTo(), if any.  SourceLocationTable
+    // is an older way of keeping track of source locations which is still
+    // used in some places.
+    void RecordLegacyLocation(
+        const Message* descriptor,
+        DescriptorPool::ErrorCollector::ErrorLocation location);
+    void RecordLegacyImportLocation(const Message* descriptor,
+                                    const std::string& name);
+
+    // Returns the number of path components in the recorder's current location.
+    int CurrentPathSize() const;
+
+    // Attaches leading and trailing comments to the location.  The two strings
+    // will be swapped into place, so after this is called *leading and
+    // *trailing will be empty.
+    //
+    // TODO(kenton):  See comment on TryConsumeEndOfDeclaration(), above, for
+    //   why this is const.
+    void AttachComments(std::string* leading, std::string* trailing,
+                        std::vector<std::string>* detached_comments) const;
+
+   private:
+    Parser* parser_;
+    SourceCodeInfo* source_code_info_;
+    SourceCodeInfo::Location* location_;
+
+    void Init(const LocationRecorder& parent, SourceCodeInfo* source_code_info);
+  };
+
+  // =================================================================
+  // Parsers for various language constructs
+
+  // Parses the "syntax = \"proto2\";" line at the top of the file.  Returns
+  // false if it failed to parse or if the syntax identifier was not
+  // recognized.
+  bool ParseSyntaxIdentifier(const LocationRecorder& parent);
+
+  // These methods parse various individual bits of code.  They return
+  // false if they completely fail to parse the construct.  In this case,
+  // it is probably necessary to skip the rest of the statement to recover.
+  // However, if these methods return true, it does NOT mean that there
+  // were no errors; only that there were no *syntax* errors.  For instance,
+  // if a service method is defined using proper syntax but uses a primitive
+  // type as its input or output, ParseMethodField() still returns true
+  // and only reports the error by calling AddError().  In practice, this
+  // makes logic much simpler for the caller.
+
+  // Parse a top-level message, enum, service, etc.
+  bool ParseTopLevelStatement(FileDescriptorProto* file,
+                              const LocationRecorder& root_location);
+
+  // Parse various language high-level language construrcts.
+  bool ParseMessageDefinition(DescriptorProto* message,
+                              const LocationRecorder& message_location,
+                              const FileDescriptorProto* containing_file);
+  bool ParseEnumDefinition(EnumDescriptorProto* enum_type,
+                           const LocationRecorder& enum_location,
+                           const FileDescriptorProto* containing_file);
+  bool ParseServiceDefinition(ServiceDescriptorProto* service,
+                              const LocationRecorder& service_location,
+                              const FileDescriptorProto* containing_file);
+  bool ParsePackage(FileDescriptorProto* file,
+                    const LocationRecorder& root_location,
+                    const FileDescriptorProto* containing_file);
+  bool ParseImport(RepeatedPtrField<std::string>* dependency,
+                   RepeatedField<int32_t>* public_dependency,
+                   RepeatedField<int32_t>* weak_dependency,
+                   const LocationRecorder& root_location,
+                   const FileDescriptorProto* containing_file);
+
+  // These methods parse the contents of a message, enum, or service type and
+  // add them to the given object.  They consume the entire block including
+  // the beginning and ending brace.
+  bool ParseMessageBlock(DescriptorProto* message,
+                         const LocationRecorder& message_location,
+                         const FileDescriptorProto* containing_file);
+  bool ParseEnumBlock(EnumDescriptorProto* enum_type,
+                      const LocationRecorder& enum_location,
+                      const FileDescriptorProto* containing_file);
+  bool ParseServiceBlock(ServiceDescriptorProto* service,
+                         const LocationRecorder& service_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Parse one statement within a message, enum, or service block, including
+  // final semicolon.
+  bool ParseMessageStatement(DescriptorProto* message,
+                             const LocationRecorder& message_location,
+                             const FileDescriptorProto* containing_file);
+  bool ParseEnumStatement(EnumDescriptorProto* message,
+                          const LocationRecorder& enum_location,
+                          const FileDescriptorProto* containing_file);
+  bool ParseServiceStatement(ServiceDescriptorProto* message,
+                             const LocationRecorder& service_location,
+                             const FileDescriptorProto* containing_file);
+
+  // Parse a field of a message.  If the field is a group, its type will be
+  // added to "messages".
+  //
+  // parent_location and location_field_number_for_nested_type are needed when
+  // parsing groups -- we need to generate a nested message type within the
+  // parent and record its location accordingly.  Since the parent could be
+  // either a FileDescriptorProto or a DescriptorProto, we must pass in the
+  // correct field number to use.
+  bool ParseMessageField(FieldDescriptorProto* field,
+                         RepeatedPtrField<DescriptorProto>* messages,
+                         const LocationRecorder& parent_location,
+                         int location_field_number_for_nested_type,
+                         const LocationRecorder& field_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Like ParseMessageField() but expects the label has already been filled in
+  // by the caller.
+  bool ParseMessageFieldNoLabel(FieldDescriptorProto* field,
+                                RepeatedPtrField<DescriptorProto>* messages,
+                                const LocationRecorder& parent_location,
+                                int location_field_number_for_nested_type,
+                                const LocationRecorder& field_location,
+                                const FileDescriptorProto* containing_file);
+
+  bool ParseMapType(MapField* map_field, FieldDescriptorProto* field,
+                    LocationRecorder& type_name_location);
+
+  // Parse an "extensions" declaration.
+  bool ParseExtensions(DescriptorProto* message,
+                       const LocationRecorder& extensions_location,
+                       const FileDescriptorProto* containing_file);
+
+  // Parse a "reserved" declaration.
+  bool ParseReserved(DescriptorProto* message,
+                     const LocationRecorder& message_location);
+  bool ParseReservedNames(DescriptorProto* message,
+                          const LocationRecorder& parent_location);
+  bool ParseReservedNumbers(DescriptorProto* message,
+                            const LocationRecorder& parent_location);
+  bool ParseReserved(EnumDescriptorProto* message,
+                     const LocationRecorder& message_location);
+  bool ParseReservedNames(EnumDescriptorProto* message,
+                          const LocationRecorder& parent_location);
+  bool ParseReservedNumbers(EnumDescriptorProto* message,
+                            const LocationRecorder& parent_location);
+
+  // Parse an "extend" declaration.  (See also comments for
+  // ParseMessageField().)
+  bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
+                   RepeatedPtrField<DescriptorProto>* messages,
+                   const LocationRecorder& parent_location,
+                   int location_field_number_for_nested_type,
+                   const LocationRecorder& extend_location,
+                   const FileDescriptorProto* containing_file);
+
+  // Parse a "oneof" declaration.  The caller is responsible for setting
+  // oneof_decl->label() since it will have had to parse the label before it
+  // knew it was parsing a oneof.
+  bool ParseOneof(OneofDescriptorProto* oneof_decl,
+                  DescriptorProto* containing_type, int oneof_index,
+                  const LocationRecorder& oneof_location,
+                  const LocationRecorder& containing_type_location,
+                  const FileDescriptorProto* containing_file);
+
+  // Parse a single enum value within an enum block.
+  bool ParseEnumConstant(EnumValueDescriptorProto* enum_value,
+                         const LocationRecorder& enum_value_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Parse enum constant options, i.e. the list in square brackets at the end
+  // of the enum constant value definition.
+  bool ParseEnumConstantOptions(EnumValueDescriptorProto* value,
+                                const LocationRecorder& enum_value_location,
+                                const FileDescriptorProto* containing_file);
+
+  // Parse a single method within a service definition.
+  bool ParseServiceMethod(MethodDescriptorProto* method,
+                          const LocationRecorder& method_location,
+                          const FileDescriptorProto* containing_file);
+
+  // Parse options of a single method or stream.
+  bool ParseMethodOptions(const LocationRecorder& parent_location,
+                          const FileDescriptorProto* containing_file,
+                          const int optionsFieldNumber,
+                          Message* mutable_options);
+
+  // Parse "required", "optional", or "repeated" and fill in "label"
+  // with the value. Returns true if such a label is consumed.
+  bool ParseLabel(FieldDescriptorProto::Label* label,
+                  const LocationRecorder& field_location);
+
+  // Parse a type name and fill in "type" (if it is a primitive) or
+  // "type_name" (if it is not) with the type parsed.
+  bool ParseType(FieldDescriptorProto::Type* type, std::string* type_name);
+  // Parse a user-defined type and fill in "type_name" with the name.
+  // If a primitive type is named, it is treated as an error.
+  bool ParseUserDefinedType(std::string* type_name);
+
+  // Parses field options, i.e. the stuff in square brackets at the end
+  // of a field definition.  Also parses default value.
+  bool ParseFieldOptions(FieldDescriptorProto* field,
+                         const LocationRecorder& field_location,
+                         const FileDescriptorProto* containing_file);
+
+  // Parse the "default" option.  This needs special handling because its
+  // type is the field's type.
+  bool ParseDefaultAssignment(FieldDescriptorProto* field,
+                              const LocationRecorder& field_location,
+                              const FileDescriptorProto* containing_file);
+
+  bool ParseJsonName(FieldDescriptorProto* field,
+                     const LocationRecorder& field_location,
+                     const FileDescriptorProto* containing_file);
+
+  enum OptionStyle {
+    OPTION_ASSIGNMENT,  // just "name = value"
+    OPTION_STATEMENT    // "option name = value;"
+  };
+
+  // Parse a single option name/value pair, e.g. "ctype = CORD".  The name
+  // identifies a field of the given Message, and the value of that field
+  // is set to the parsed value.
+  bool ParseOption(Message* options, const LocationRecorder& options_location,
+                   const FileDescriptorProto* containing_file,
+                   OptionStyle style);
+
+  // Parses a single part of a multipart option name. A multipart name consists
+  // of names separated by dots. Each name is either an identifier or a series
+  // of identifiers separated by dots and enclosed in parentheses. E.g.,
+  // "foo.(bar.baz).moo".
+  bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
+                           const LocationRecorder& part_location,
+                           const FileDescriptorProto* containing_file);
+
+  // Parses a string surrounded by balanced braces.  Strips off the outer
+  // braces and stores the enclosed string in *value.
+  // E.g.,
+  //     { foo }                     *value gets 'foo'
+  //     { foo { bar: box } }        *value gets 'foo { bar: box }'
+  //     {}                          *value gets ''
+  //
+  // REQUIRES: LookingAt("{")
+  // When finished successfully, we are looking at the first token past
+  // the ending brace.
+  bool ParseUninterpretedBlock(std::string* value);
+
+  struct MapField {
+    // Whether the field is a map field.
+    bool is_map_field;
+    // The types of the key and value if they are primitive types.
+    FieldDescriptorProto::Type key_type;
+    FieldDescriptorProto::Type value_type;
+    // Or the type names string if the types are customized types.
+    std::string key_type_name;
+    std::string value_type_name;
+
+    MapField() : is_map_field(false) {}
+  };
+  // Desugar the map syntax to generate a nested map entry message.
+  void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field,
+                        RepeatedPtrField<DescriptorProto>* messages);
+
+  // Whether fields without label default to optional fields.
+  bool DefaultToOptionalFields() const {
+    return syntax_identifier_ == "proto3";
+  }
+
+  bool ValidateEnum(const EnumDescriptorProto* proto);
+
+  // =================================================================
+
+  io::Tokenizer* input_;
+  io::ErrorCollector* error_collector_;
+  SourceCodeInfo* source_code_info_;
+  SourceLocationTable* source_location_table_;  // legacy
+  bool had_errors_;
+  bool require_syntax_identifier_;
+  bool stop_after_syntax_identifier_;
+  std::string syntax_identifier_;
+
+  // Leading doc comments for the next declaration.  These are not complete
+  // yet; use ConsumeEndOfDeclaration() to get the complete comments.
+  std::string upcoming_doc_comments_;
+
+  // Detached comments are not connected to any syntax entities. Elements in
+  // this vector are paragraphs of comments separated by empty lines. The
+  // detached comments will be put into the leading_detached_comments field for
+  // the next element (See SourceCodeInfo.Location in descriptor.proto), when
+  // ConsumeEndOfDeclaration() is called.
+  std::vector<std::string> upcoming_detached_comments_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
+};
+
+// A table mapping (descriptor, ErrorLocation) pairs -- as reported by
+// DescriptorPool when validating descriptors -- to line and column numbers
+// within the original source code.
+//
+// This is semi-obsolete:  FileDescriptorProto.source_code_info now contains
+// far more complete information about source locations.  However, as of this
+// writing you still need to use SourceLocationTable when integrating with
+// DescriptorPool.
+class PROTOBUF_EXPORT SourceLocationTable {
+ public:
+  SourceLocationTable();
+  ~SourceLocationTable();
+
+  // Finds the precise location of the given error and fills in *line and
+  // *column with the line and column numbers.  If not found, sets *line to
+  // -1 and *column to 0 (since line = -1 is used to mean "error has no exact
+  // location" in the ErrorCollector interface).  Returns true if found, false
+  // otherwise.
+  bool Find(const Message* descriptor,
+            DescriptorPool::ErrorCollector::ErrorLocation location, int* line,
+            int* column) const;
+  bool FindImport(const Message* descriptor, const std::string& name, int* line,
+                  int* column) const;
+
+  // Adds a location to the table.
+  void Add(const Message* descriptor,
+           DescriptorPool::ErrorCollector::ErrorLocation location, int line,
+           int column);
+  void AddImport(const Message* descriptor, const std::string& name, int line,
+                 int column);
+
+  // Clears the contents of the table.
+  void Clear();
+
+ private:
+  typedef std::map<
+      std::pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>,
+      std::pair<int, int> >
+      LocationMap;
+  LocationMap location_map_;
+  std::map<std::pair<const Message*, std::string>, std::pair<int, int> >
+      import_location_map_;
+};
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PARSER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor.h
new file mode 100644
index 0000000..bee3e32
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor.h
@@ -0,0 +1,2448 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains classes which describe a type of protocol message.
+// You can use a message's descriptor to learn at runtime what fields
+// it contains and what the types of those fields are.  The Message
+// interface also allows you to dynamically access and modify individual
+// fields by passing the FieldDescriptor of the field you are interested
+// in.
+//
+// Most users will not care about descriptors, because they will write
+// code specific to certain protocol types and will simply use the classes
+// generated by the protocol compiler directly.  Advanced users who want
+// to operate on arbitrary types (not known at compile time) may want to
+// read descriptors in order to learn about the contents of a message.
+// A very small number of users will want to construct their own
+// Descriptors, either because they are implementing Message manually or
+// because they are writing something like the protocol compiler.
+//
+// For an example of how you might use descriptors, see the code example
+// at the top of message.h.
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
+#define GOOGLE_PROTOBUF_DESCRIPTOR_H__
+
+
+#include <atomic>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
+#ifdef TYPE_BOOL
+#undef TYPE_BOOL
+#endif  // TYPE_BOOL
+
+#ifdef SWIG
+#define PROTOBUF_EXPORT
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Descriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class ServiceDescriptor;
+class MethodDescriptor;
+class FileDescriptor;
+class DescriptorDatabase;
+class DescriptorPool;
+
+// Defined in descriptor.proto
+class DescriptorProto;
+class DescriptorProto_ExtensionRange;
+class FieldDescriptorProto;
+class OneofDescriptorProto;
+class EnumDescriptorProto;
+class EnumValueDescriptorProto;
+class ServiceDescriptorProto;
+class MethodDescriptorProto;
+class FileDescriptorProto;
+class MessageOptions;
+class FieldOptions;
+class OneofOptions;
+class EnumOptions;
+class EnumValueOptions;
+class ExtensionRangeOptions;
+class ServiceOptions;
+class MethodOptions;
+class FileOptions;
+class UninterpretedOption;
+class SourceCodeInfo;
+
+// Defined in message.h
+class Message;
+class Reflection;
+
+// Defined in descriptor.cc
+class DescriptorBuilder;
+class FileDescriptorTables;
+class Symbol;
+
+// Defined in unknown_field_set.h.
+class UnknownField;
+
+// Defined in command_line_interface.cc
+namespace compiler {
+class CommandLineInterface;
+namespace cpp {
+// Defined in helpers.h
+class Formatter;
+}  // namespace cpp
+}  // namespace compiler
+
+namespace descriptor_unittest {
+class DescriptorTest;
+}  // namespace descriptor_unittest
+
+// Defined in printer.h
+namespace io {
+class Printer;
+}  // namespace io
+
+// NB, all indices are zero-based.
+struct SourceLocation {
+  int start_line;
+  int end_line;
+  int start_column;
+  int end_column;
+
+  // Doc comments found at the source location.
+  // See the comments in SourceCodeInfo.Location (descriptor.proto) for details.
+  std::string leading_comments;
+  std::string trailing_comments;
+  std::vector<std::string> leading_detached_comments;
+};
+
+// Options when generating machine-parsable output from a descriptor with
+// DebugString().
+struct DebugStringOptions {
+  // include original user comments as recorded in SourceLocation entries. N.B.
+  // that this must be |false| by default: several other pieces of code (for
+  // example, the C++ code generation for fields in the proto compiler) rely on
+  // DebugString() output being unobstructed by user comments.
+  bool include_comments;
+  // If true, elide the braced body in the debug string.
+  bool elide_group_body;
+  bool elide_oneof_body;
+
+  DebugStringOptions()
+      : include_comments(false),
+        elide_group_body(false),
+        elide_oneof_body(false) {
+  }
+};
+
+// A class to handle the simplest cases of a lazily linked descriptor
+// for a message type that isn't built at the time of cross linking,
+// which is needed when a pool has lazily_build_dependencies_ set.
+// Must be instantiated as mutable in a descriptor.
+namespace internal {
+
+// The classes in this file represent a significant memory footprint for the
+// library. We make sure we are not accidentally making them larger by
+// hardcoding the struct size for a specific platform. Use as:
+//
+//   PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(type, expected_size_in_x84-64);
+//
+
+#if !defined(PROTOBUF_INTERNAL_CHECK_CLASS_SIZE)
+#define PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(t, expected)
+#endif
+
+class FlatAllocator;
+
+class PROTOBUF_EXPORT LazyDescriptor {
+ public:
+  // Init function to be called at init time of a descriptor containing
+  // a LazyDescriptor.
+  void Init() {
+    descriptor_ = nullptr;
+    once_ = nullptr;
+  }
+
+  // Sets the value of the descriptor if it is known during the descriptor
+  // building process. Not thread safe, should only be called during the
+  // descriptor build process. Should not be called after SetLazy has been
+  // called.
+  void Set(const Descriptor* descriptor);
+
+  // Sets the information needed to lazily cross link the descriptor at a later
+  // time, SetLazy is not thread safe, should be called only once at descriptor
+  // build time if the symbol wasn't found and building of the file containing
+  // that type is delayed because lazily_build_dependencies_ is set on the pool.
+  // Should not be called after Set() has been called.
+  void SetLazy(StringPiece name, const FileDescriptor* file);
+
+  // Returns the current value of the descriptor, thread-safe. If SetLazy(...)
+  // has been called, will do a one-time cross link of the type specified,
+  // building the descriptor file that contains the type if necessary.
+  inline const Descriptor* Get(const ServiceDescriptor* service) {
+    Once(service);
+    return descriptor_;
+  }
+
+ private:
+  void Once(const ServiceDescriptor* service);
+
+  const Descriptor* descriptor_;
+  // The once_ flag is followed by a NUL terminated string for the type name.
+  internal::once_flag* once_;
+};
+
+class PROTOBUF_EXPORT SymbolBase {
+ private:
+  friend class google::protobuf::Symbol;
+  uint8_t symbol_type_;
+};
+
+// Some types have more than one SymbolBase because they have multiple
+// identities in the table. We can't have duplicate direct bases, so we use this
+// intermediate base to do so.
+// See BuildEnumValue for details.
+template <int N>
+class PROTOBUF_EXPORT SymbolBaseN : public SymbolBase {};
+
+}  // namespace internal
+
+// Describes a type of protocol message, or a particular group within a
+// message.  To obtain the Descriptor for a given message object, call
+// Message::GetDescriptor().  Generated message classes also have a
+// static method called descriptor() which returns the type's descriptor.
+// Use DescriptorPool to construct your own descriptors.
+class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
+ public:
+  typedef DescriptorProto Proto;
+
+  // The name of the message type, not including its scope.
+  const std::string& name() const;
+
+  // The fully-qualified name of the message type, scope delimited by
+  // periods.  For example, message type "Foo" which is declared in package
+  // "bar" has full name "bar.Foo".  If a type "Baz" is nested within
+  // Foo, Baz's full_name is "bar.Foo.Baz".  To get only the part that
+  // comes after the last '.', use name().
+  const std::string& full_name() const;
+
+  // Index of this descriptor within the file or containing type's message
+  // type array.
+  int index() const;
+
+  // The .proto file in which this message type was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+
+  // If this Descriptor describes a nested type, this returns the type
+  // in which it is nested.  Otherwise, returns nullptr.
+  const Descriptor* containing_type() const;
+
+  // Get options for this message type.  These are specified in the .proto file
+  // by placing lines like "option foo = 1234;" in the message definition.
+  // Allowed options are defined by MessageOptions in descriptor.proto, and any
+  // available extensions of that message.
+  const MessageOptions& options() const;
+
+  // Write the contents of this Descriptor into the given DescriptorProto.
+  // The target DescriptorProto must be clear before calling this; if it
+  // isn't, the result may be garbage.
+  void CopyTo(DescriptorProto* proto) const;
+
+  // Write the contents of this descriptor in a human-readable form. Output
+  // will be suitable for re-parsing.
+  std::string DebugString() const;
+
+  // Similar to DebugString(), but additionally takes options (e.g.,
+  // include original user comments in output).
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Returns true if this is a placeholder for an unknown type. This will
+  // only be the case if this descriptor comes from a DescriptorPool
+  // with AllowUnknownDependencies() set.
+  bool is_placeholder() const;
+
+  enum WellKnownType {
+    WELLKNOWNTYPE_UNSPECIFIED,  // Not a well-known type.
+
+    // Wrapper types.
+    WELLKNOWNTYPE_DOUBLEVALUE,  // google.protobuf.DoubleValue
+    WELLKNOWNTYPE_FLOATVALUE,   // google.protobuf.FloatValue
+    WELLKNOWNTYPE_INT64VALUE,   // google.protobuf.Int64Value
+    WELLKNOWNTYPE_UINT64VALUE,  // google.protobuf.UInt64Value
+    WELLKNOWNTYPE_INT32VALUE,   // google.protobuf.Int32Value
+    WELLKNOWNTYPE_UINT32VALUE,  // google.protobuf.UInt32Value
+    WELLKNOWNTYPE_STRINGVALUE,  // google.protobuf.StringValue
+    WELLKNOWNTYPE_BYTESVALUE,   // google.protobuf.BytesValue
+    WELLKNOWNTYPE_BOOLVALUE,    // google.protobuf.BoolValue
+
+    // Other well known types.
+    WELLKNOWNTYPE_ANY,        // google.protobuf.Any
+    WELLKNOWNTYPE_FIELDMASK,  // google.protobuf.FieldMask
+    WELLKNOWNTYPE_DURATION,   // google.protobuf.Duration
+    WELLKNOWNTYPE_TIMESTAMP,  // google.protobuf.Timestamp
+    WELLKNOWNTYPE_VALUE,      // google.protobuf.Value
+    WELLKNOWNTYPE_LISTVALUE,  // google.protobuf.ListValue
+    WELLKNOWNTYPE_STRUCT,     // google.protobuf.Struct
+
+    // New well-known types may be added in the future.
+    // Please make sure any switch() statements have a 'default' case.
+    __WELLKNOWNTYPE__DO_NOT_USE__ADD_DEFAULT_INSTEAD__,
+  };
+
+  WellKnownType well_known_type() const;
+
+  // Field stuff -----------------------------------------------------
+
+  // The number of fields in this message type.
+  int field_count() const;
+  // Gets a field by index, where 0 <= index < field_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FieldDescriptor* field(int index) const;
+
+  // Looks up a field by declared tag number.  Returns nullptr if no such field
+  // exists.
+  const FieldDescriptor* FindFieldByNumber(int number) const;
+  // Looks up a field by name.  Returns nullptr if no such field exists.
+  const FieldDescriptor* FindFieldByName(ConstStringParam name) const;
+
+  // Looks up a field by lowercased name (as returned by lowercase_name()).
+  // This lookup may be ambiguous if multiple field names differ only by case,
+  // in which case the field returned is chosen arbitrarily from the matches.
+  const FieldDescriptor* FindFieldByLowercaseName(
+      ConstStringParam lowercase_name) const;
+
+  // Looks up a field by camel-case name (as returned by camelcase_name()).
+  // This lookup may be ambiguous if multiple field names differ in a way that
+  // leads them to have identical camel-case names, in which case the field
+  // returned is chosen arbitrarily from the matches.
+  const FieldDescriptor* FindFieldByCamelcaseName(
+      ConstStringParam camelcase_name) const;
+
+  // The number of oneofs in this message type.
+  int oneof_decl_count() const;
+  // The number of oneofs in this message type, excluding synthetic oneofs.
+  // Real oneofs always come first, so iterating up to real_oneof_decl_cout()
+  // will yield all real oneofs.
+  int real_oneof_decl_count() const;
+  // Get a oneof by index, where 0 <= index < oneof_decl_count().
+  // These are returned in the order they were defined in the .proto file.
+  const OneofDescriptor* oneof_decl(int index) const;
+
+  // Looks up a oneof by name.  Returns nullptr if no such oneof exists.
+  const OneofDescriptor* FindOneofByName(ConstStringParam name) const;
+
+  // Nested type stuff -----------------------------------------------
+
+  // The number of nested types in this message type.
+  int nested_type_count() const;
+  // Gets a nested type by index, where 0 <= index < nested_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const Descriptor* nested_type(int index) const;
+
+  // Looks up a nested type by name.  Returns nullptr if no such nested type
+  // exists.
+  const Descriptor* FindNestedTypeByName(ConstStringParam name) const;
+
+  // Enum stuff ------------------------------------------------------
+
+  // The number of enum types in this message type.
+  int enum_type_count() const;
+  // Gets an enum type by index, where 0 <= index < enum_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const EnumDescriptor* enum_type(int index) const;
+
+  // Looks up an enum type by name.  Returns nullptr if no such enum type
+  // exists.
+  const EnumDescriptor* FindEnumTypeByName(ConstStringParam name) const;
+
+  // Looks up an enum value by name, among all enum types in this message.
+  // Returns nullptr if no such value exists.
+  const EnumValueDescriptor* FindEnumValueByName(ConstStringParam name) const;
+
+  // Extensions ------------------------------------------------------
+
+  // A range of field numbers which are designated for third-party
+  // extensions.
+  struct ExtensionRange {
+    typedef DescriptorProto_ExtensionRange Proto;
+
+    typedef ExtensionRangeOptions OptionsType;
+
+    // See Descriptor::CopyTo().
+    void CopyTo(DescriptorProto_ExtensionRange* proto) const;
+
+    int start;  // inclusive
+    int end;    // exclusive
+
+    const ExtensionRangeOptions* options_;
+  };
+
+  // The number of extension ranges in this message type.
+  int extension_range_count() const;
+  // Gets an extension range by index, where 0 <= index <
+  // extension_range_count(). These are returned in the order they were defined
+  // in the .proto file.
+  const ExtensionRange* extension_range(int index) const;
+
+  // Returns true if the number is in one of the extension ranges.
+  bool IsExtensionNumber(int number) const;
+
+  // Returns nullptr if no extension range contains the given number.
+  const ExtensionRange* FindExtensionRangeContainingNumber(int number) const;
+
+  // The number of extensions defined nested within this message type's scope.
+  // See doc:
+  // https://developers.google.com/protocol-buffers/docs/proto#nested-extensions
+  //
+  // Note that the extensions may be extending *other* messages.
+  //
+  // For example:
+  // message M1 {
+  //   extensions 1 to max;
+  // }
+  //
+  // message M2 {
+  //   extend M1 {
+  //     optional int32 foo = 1;
+  //   }
+  // }
+  //
+  // In this case,
+  // DescriptorPool::generated_pool()
+  //     ->FindMessageTypeByName("M2")
+  //     ->extension(0)
+  // will return "foo", even though "foo" is an extension of M1.
+  // To find all known extensions of a given message, instead use
+  // DescriptorPool::FindAllExtensions.
+  int extension_count() const;
+  // Get an extension by index, where 0 <= index < extension_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FieldDescriptor* extension(int index) const;
+
+  // Looks up a named extension (which extends some *other* message type)
+  // defined within this message type's scope.
+  const FieldDescriptor* FindExtensionByName(ConstStringParam name) const;
+
+  // Similar to FindFieldByLowercaseName(), but finds extensions defined within
+  // this message type's scope.
+  const FieldDescriptor* FindExtensionByLowercaseName(
+      ConstStringParam name) const;
+
+  // Similar to FindFieldByCamelcaseName(), but finds extensions defined within
+  // this message type's scope.
+  const FieldDescriptor* FindExtensionByCamelcaseName(
+      ConstStringParam name) const;
+
+  // Reserved fields -------------------------------------------------
+
+  // A range of reserved field numbers.
+  struct ReservedRange {
+    int start;  // inclusive
+    int end;    // exclusive
+  };
+
+  // The number of reserved ranges in this message type.
+  int reserved_range_count() const;
+  // Gets an reserved range by index, where 0 <= index <
+  // reserved_range_count(). These are returned in the order they were defined
+  // in the .proto file.
+  const ReservedRange* reserved_range(int index) const;
+
+  // Returns true if the number is in one of the reserved ranges.
+  bool IsReservedNumber(int number) const;
+
+  // Returns nullptr if no reserved range contains the given number.
+  const ReservedRange* FindReservedRangeContainingNumber(int number) const;
+
+  // The number of reserved field names in this message type.
+  int reserved_name_count() const;
+
+  // Gets a reserved name by index, where 0 <= index < reserved_name_count().
+  const std::string& reserved_name(int index) const;
+
+  // Returns true if the field name is reserved.
+  bool IsReservedName(ConstStringParam name) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this message declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+  // Maps --------------------------------------------------------------
+
+  // Returns the FieldDescriptor for the "key" field. If this isn't a map entry
+  // field, returns nullptr.
+  const FieldDescriptor* map_key() const;
+
+  // Returns the FieldDescriptor for the "value" field. If this isn't a map
+  // entry field, returns nullptr.
+  const FieldDescriptor* map_value() const;
+
+ private:
+  friend class Symbol;
+  typedef MessageOptions OptionsType;
+
+  // Allows tests to test CopyTo(proto, true).
+  friend class descriptor_unittest::DescriptorTest;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(DescriptorProto* proto) const;
+
+  // Internal version of DebugString; controls the level of indenting for
+  // correct depth. Takes |options| to control debug-string options, and
+  // |include_opening_clause| to indicate whether the "message ... " part of the
+  // clause has already been generated (this varies depending on context).
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options,
+                   bool include_opening_clause) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // True if this is a placeholder for an unknown type.
+  bool is_placeholder_ : 1;
+  // True if this is a placeholder and the type name wasn't fully-qualified.
+  bool is_unqualified_placeholder_ : 1;
+  // Well known type.  Stored like this to conserve space.
+  uint8_t well_known_type_ : 5;
+
+  // This points to the last field _number_ that is part of the sequence
+  // starting at 1, where
+  //     `desc->field(i)->number() == i + 1`
+  // A value of `0` means no field matches. That is, there are no fields or the
+  // first field is not field `1`.
+  // Uses 16-bit to avoid extra padding. Unlikely to have more than 2^16
+  // sequentially numbered fields in a message.
+  uint16_t sequential_field_limit_;
+
+  int field_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const Descriptor* containing_type_;
+  const MessageOptions* options_;
+
+  // These arrays are separated from their sizes to minimize padding on 64-bit.
+  FieldDescriptor* fields_;
+  OneofDescriptor* oneof_decls_;
+  Descriptor* nested_types_;
+  EnumDescriptor* enum_types_;
+  ExtensionRange* extension_ranges_;
+  FieldDescriptor* extensions_;
+  ReservedRange* reserved_ranges_;
+  const std::string** reserved_names_;
+
+  int oneof_decl_count_;
+  int real_oneof_decl_count_;
+  int nested_type_count_;
+  int enum_type_count_;
+  int extension_range_count_;
+  int extension_count_;
+  int reserved_range_count_;
+  int reserved_name_count_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<Descriptor>() and AllocateArray<Descriptor>() in descriptor.cc
+  // and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  Descriptor() {}
+  friend class DescriptorBuilder;
+  friend class DescriptorPool;
+  friend class EnumDescriptor;
+  friend class FieldDescriptor;
+  friend class FileDescriptorTables;
+  friend class OneofDescriptor;
+  friend class MethodDescriptor;
+  friend class FileDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 136);
+
+// Describes a single field of a message.  To get the descriptor for a given
+// field, first get the Descriptor for the message in which it is defined,
+// then call Descriptor::FindFieldByName().  To get a FieldDescriptor for
+// an extension, do one of the following:
+// - Get the Descriptor or FileDescriptor for its containing scope, then
+//   call Descriptor::FindExtensionByName() or
+//   FileDescriptor::FindExtensionByName().
+// - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber() or
+//   DescriptorPool::FindExtensionByPrintableName().
+// Use DescriptorPool to construct your own descriptors.
+class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase {
+ public:
+  typedef FieldDescriptorProto Proto;
+
+  // Identifies a field type.  0 is reserved for errors.  The order is weird
+  // for historical reasons.  Types 12 and up are new in proto2.
+  enum Type {
+    TYPE_DOUBLE = 1,    // double, exactly eight bytes on the wire.
+    TYPE_FLOAT = 2,     // float, exactly four bytes on the wire.
+    TYPE_INT64 = 3,     // int64, varint on the wire.  Negative numbers
+                        // take 10 bytes.  Use TYPE_SINT64 if negative
+                        // values are likely.
+    TYPE_UINT64 = 4,    // uint64, varint on the wire.
+    TYPE_INT32 = 5,     // int32, varint on the wire.  Negative numbers
+                        // take 10 bytes.  Use TYPE_SINT32 if negative
+                        // values are likely.
+    TYPE_FIXED64 = 6,   // uint64, exactly eight bytes on the wire.
+    TYPE_FIXED32 = 7,   // uint32, exactly four bytes on the wire.
+    TYPE_BOOL = 8,      // bool, varint on the wire.
+    TYPE_STRING = 9,    // UTF-8 text.
+    TYPE_GROUP = 10,    // Tag-delimited message.  Deprecated.
+    TYPE_MESSAGE = 11,  // Length-delimited message.
+
+    TYPE_BYTES = 12,     // Arbitrary byte array.
+    TYPE_UINT32 = 13,    // uint32, varint on the wire
+    TYPE_ENUM = 14,      // Enum, varint on the wire
+    TYPE_SFIXED32 = 15,  // int32, exactly four bytes on the wire
+    TYPE_SFIXED64 = 16,  // int64, exactly eight bytes on the wire
+    TYPE_SINT32 = 17,    // int32, ZigZag-encoded varint on the wire
+    TYPE_SINT64 = 18,    // int64, ZigZag-encoded varint on the wire
+
+    MAX_TYPE = 18,  // Constant useful for defining lookup tables
+                    // indexed by Type.
+  };
+
+  // Specifies the C++ data type used to represent the field.  There is a
+  // fixed mapping from Type to CppType where each Type maps to exactly one
+  // CppType.  0 is reserved for errors.
+  enum CppType {
+    CPPTYPE_INT32 = 1,     // TYPE_INT32, TYPE_SINT32, TYPE_SFIXED32
+    CPPTYPE_INT64 = 2,     // TYPE_INT64, TYPE_SINT64, TYPE_SFIXED64
+    CPPTYPE_UINT32 = 3,    // TYPE_UINT32, TYPE_FIXED32
+    CPPTYPE_UINT64 = 4,    // TYPE_UINT64, TYPE_FIXED64
+    CPPTYPE_DOUBLE = 5,    // TYPE_DOUBLE
+    CPPTYPE_FLOAT = 6,     // TYPE_FLOAT
+    CPPTYPE_BOOL = 7,      // TYPE_BOOL
+    CPPTYPE_ENUM = 8,      // TYPE_ENUM
+    CPPTYPE_STRING = 9,    // TYPE_STRING, TYPE_BYTES
+    CPPTYPE_MESSAGE = 10,  // TYPE_MESSAGE, TYPE_GROUP
+
+    MAX_CPPTYPE = 10,  // Constant useful for defining lookup tables
+                       // indexed by CppType.
+  };
+
+  // Identifies whether the field is optional, required, or repeated.  0 is
+  // reserved for errors.
+  enum Label {
+    LABEL_OPTIONAL = 1,  // optional
+    LABEL_REQUIRED = 2,  // required
+    LABEL_REPEATED = 3,  // repeated
+
+    MAX_LABEL = 3,  // Constant useful for defining lookup tables
+                    // indexed by Label.
+  };
+
+  // Valid field numbers are positive integers up to kMaxNumber.
+  static const int kMaxNumber = (1 << 29) - 1;
+
+  // First field number reserved for the protocol buffer library implementation.
+  // Users may not declare fields that use reserved numbers.
+  static const int kFirstReservedNumber = 19000;
+  // Last field number reserved for the protocol buffer library implementation.
+  // Users may not declare fields that use reserved numbers.
+  static const int kLastReservedNumber = 19999;
+
+  const std::string& name() const;  // Name of this field within the message.
+  const std::string& full_name() const;  // Fully-qualified name of the field.
+  const std::string& json_name() const;  // JSON name of this field.
+  const FileDescriptor* file() const;  // File in which this field was defined.
+  bool is_extension() const;           // Is this an extension field?
+  int number() const;                  // Declared tag number.
+
+  // Same as name() except converted to lower-case.  This (and especially the
+  // FindFieldByLowercaseName() method) can be useful when parsing formats
+  // which prefer to use lowercase naming style.  (Although, technically
+  // field names should be lowercased anyway according to the protobuf style
+  // guide, so this only makes a difference when dealing with old .proto files
+  // which do not follow the guide.)
+  const std::string& lowercase_name() const;
+
+  // Same as name() except converted to camel-case.  In this conversion, any
+  // time an underscore appears in the name, it is removed and the next
+  // letter is capitalized.  Furthermore, the first letter of the name is
+  // lower-cased.  Examples:
+  //   FooBar -> fooBar
+  //   foo_bar -> fooBar
+  //   fooBar -> fooBar
+  // This (and especially the FindFieldByCamelcaseName() method) can be useful
+  // when parsing formats which prefer to use camel-case naming style.
+  const std::string& camelcase_name() const;
+
+  Type type() const;                  // Declared type of this field.
+  const char* type_name() const;      // Name of the declared type.
+  CppType cpp_type() const;           // C++ type of this field.
+  const char* cpp_type_name() const;  // Name of the C++ type.
+  Label label() const;                // optional/required/repeated
+
+  bool is_required() const;  // shorthand for label() == LABEL_REQUIRED
+  bool is_optional() const;  // shorthand for label() == LABEL_OPTIONAL
+  bool is_repeated() const;  // shorthand for label() == LABEL_REPEATED
+  bool is_packable() const;  // shorthand for is_repeated() &&
+                             //               IsTypePackable(type())
+  bool is_packed() const;    // shorthand for is_packable() &&
+                             //               options().packed()
+  bool is_map() const;       // shorthand for type() == TYPE_MESSAGE &&
+                             // message_type()->options().map_entry()
+
+  // Returns true if this field was syntactically written with "optional" in the
+  // .proto file. Excludes singular proto3 fields that do not have a label.
+  bool has_optional_keyword() const;
+
+  // Returns true if this field tracks presence, ie. does the field
+  // distinguish between "unset" and "present with default value."
+  // This includes required, optional, and oneof fields. It excludes maps,
+  // repeated fields, and singular proto3 fields without "optional".
+  //
+  // For fields where has_presence() == true, the return value of
+  // Reflection::HasField() is semantically meaningful.
+  bool has_presence() const;
+
+  // Index of this field within the message's field array, or the file or
+  // extension scope's extensions array.
+  int index() const;
+
+  // Does this field have an explicitly-declared default value?
+  bool has_default_value() const;
+
+  // Whether the user has specified the json_name field option in the .proto
+  // file.
+  bool has_json_name() const;
+
+  // Get the field default value if cpp_type() == CPPTYPE_INT32.  If no
+  // explicit default was defined, the default is 0.
+  int32_t default_value_int32_t() const;
+  int32_t default_value_int32() const { return default_value_int32_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_INT64.  If no
+  // explicit default was defined, the default is 0.
+  int64_t default_value_int64_t() const;
+  int64_t default_value_int64() const { return default_value_int64_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_UINT32.  If no
+  // explicit default was defined, the default is 0.
+  uint32_t default_value_uint32_t() const;
+  uint32_t default_value_uint32() const { return default_value_uint32_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_UINT64.  If no
+  // explicit default was defined, the default is 0.
+  uint64_t default_value_uint64_t() const;
+  uint64_t default_value_uint64() const { return default_value_uint64_t(); }
+  // Get the field default value if cpp_type() == CPPTYPE_FLOAT.  If no
+  // explicit default was defined, the default is 0.0.
+  float default_value_float() const;
+  // Get the field default value if cpp_type() == CPPTYPE_DOUBLE.  If no
+  // explicit default was defined, the default is 0.0.
+  double default_value_double() const;
+  // Get the field default value if cpp_type() == CPPTYPE_BOOL.  If no
+  // explicit default was defined, the default is false.
+  bool default_value_bool() const;
+  // Get the field default value if cpp_type() == CPPTYPE_ENUM.  If no
+  // explicit default was defined, the default is the first value defined
+  // in the enum type (all enum types are required to have at least one value).
+  // This never returns nullptr.
+  const EnumValueDescriptor* default_value_enum() const;
+  // Get the field default value if cpp_type() == CPPTYPE_STRING.  If no
+  // explicit default was defined, the default is the empty string.
+  const std::string& default_value_string() const;
+
+  // The Descriptor for the message of which this is a field.  For extensions,
+  // this is the extended type.  Never nullptr.
+  const Descriptor* containing_type() const;
+
+  // If the field is a member of a oneof, this is the one, otherwise this is
+  // nullptr.
+  const OneofDescriptor* containing_oneof() const;
+
+  // If the field is a member of a non-synthetic oneof, returns the descriptor
+  // for the oneof, otherwise returns nullptr.
+  const OneofDescriptor* real_containing_oneof() const;
+
+  // If the field is a member of a oneof, returns the index in that oneof.
+  int index_in_oneof() const;
+
+  // An extension may be declared within the scope of another message.  If this
+  // field is an extension (is_extension() is true), then extension_scope()
+  // returns that message, or nullptr if the extension was declared at global
+  // scope.  If this is not an extension, extension_scope() is undefined (may
+  // assert-fail).
+  const Descriptor* extension_scope() const;
+
+  // If type is TYPE_MESSAGE or TYPE_GROUP, returns a descriptor for the
+  // message or the group type.  Otherwise, returns null.
+  const Descriptor* message_type() const;
+  // If type is TYPE_ENUM, returns a descriptor for the enum.  Otherwise,
+  // returns null.
+  const EnumDescriptor* enum_type() const;
+
+  // Get the FieldOptions for this field.  This includes things listed in
+  // square brackets after the field definition.  E.g., the field:
+  //   optional string text = 1 [ctype=CORD];
+  // has the "ctype" option set.  Allowed options are defined by FieldOptions in
+  // descriptor.proto, and any available extensions of that message.
+  const FieldOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(FieldDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Helper method to get the CppType for a particular Type.
+  static CppType TypeToCppType(Type type);
+
+  // Helper method to get the name of a Type.
+  static const char* TypeName(Type type);
+
+  // Helper method to get the name of a CppType.
+  static const char* CppTypeName(CppType cpp_type);
+
+  // Return true iff [packed = true] is valid for fields of this type.
+  static inline bool IsTypePackable(Type field_type);
+
+  // Returns full_name() except if the field is a MessageSet extension,
+  // in which case it returns the full_name() of the containing message type
+  // for backwards compatibility with proto1.
+  //
+  // A MessageSet extension is defined as an optional message extension
+  // whose containing type has the message_set_wire_format option set.
+  // This should be true of extensions of google.protobuf.bridge.MessageSet;
+  // by convention, such extensions are named "message_set_extension".
+  //
+  // The opposite operation (looking up an extension's FieldDescriptor given
+  // its printable name) can be accomplished with
+  //     message->file()->pool()->FindExtensionByPrintableName(message, name)
+  // where the extension extends "message".
+  const std::string& PrintableNameForExtension() const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this field declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef FieldOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+  friend class Reflection;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(FieldDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // formats the default value appropriately and returns it as a string.
+  // Must have a default value to call this. If quote_string_type is true, then
+  // types of CPPTYPE_STRING will be surrounded by quotes and CEscaped.
+  std::string DefaultValueAsString(bool quote_string_type) const;
+
+  // Helper function that returns the field type name for DebugString.
+  std::string FieldTypeNameDebugString() const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // Returns true if this is a map message type.
+  bool is_map_message_type() const;
+
+  bool has_default_value_ : 1;
+  bool proto3_optional_ : 1;
+  // Whether the user has specified the json_name field option in the .proto
+  // file.
+  bool has_json_name_ : 1;
+  bool is_extension_ : 1;
+  bool is_oneof_ : 1;
+
+  // Actually a `Label` but stored as uint8_t to save space.
+  uint8_t label_ : 2;
+
+  // Actually a `Type`, but stored as uint8_t to save space.
+  mutable uint8_t type_;
+
+  // Logically:
+  //   all_names_ = [name, full_name, lower, camel, json]
+  // However:
+  //   duplicates will be omitted, so lower/camel/json might be in the same
+  //   position.
+  // We store the true offset for each name here, and the bit width must be
+  // large enough to account for the worst case where all names are present.
+  uint8_t lowercase_name_index_ : 2;
+  uint8_t camelcase_name_index_ : 2;
+  uint8_t json_name_index_ : 3;
+  // Sadly, `number_` located here to reduce padding. Unrelated to all_names_
+  // and its indices above.
+  int number_;
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+
+  // The once_flag is followed by a NUL terminated string for the type name and
+  // enum default value (or empty string if no default enum).
+  internal::once_flag* type_once_;
+  static void TypeOnceInit(const FieldDescriptor* to_init);
+  void InternalTypeOnceInit() const;
+  const Descriptor* containing_type_;
+  union {
+    const OneofDescriptor* containing_oneof;
+    const Descriptor* extension_scope;
+  } scope_;
+  union {
+    mutable const Descriptor* message_type;
+    mutable const EnumDescriptor* enum_type;
+  } type_descriptor_;
+  const FieldOptions* options_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  union {
+    int32_t default_value_int32_t_;
+    int64_t default_value_int64_t_;
+    uint32_t default_value_uint32_t_;
+    uint64_t default_value_uint64_t_;
+    float default_value_float_;
+    double default_value_double_;
+    bool default_value_bool_;
+
+    mutable const EnumValueDescriptor* default_value_enum_;
+    const std::string* default_value_string_;
+    mutable std::atomic<const Message*> default_generated_instance_;
+  };
+
+  static const CppType kTypeToCppTypeMap[MAX_TYPE + 1];
+
+  static const char* const kTypeToName[MAX_TYPE + 1];
+
+  static const char* const kCppTypeToName[MAX_CPPTYPE + 1];
+
+  static const char* const kLabelToName[MAX_LABEL + 1];
+
+  // Must be constructed using DescriptorPool.
+  FieldDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class FileDescriptor;
+  friend class Descriptor;
+  friend class OneofDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 72);
+
+// Describes a oneof defined in a message type.
+class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
+ public:
+  typedef OneofDescriptorProto Proto;
+
+  const std::string& name() const;       // Name of this oneof.
+  const std::string& full_name() const;  // Fully-qualified name of the oneof.
+
+  // Index of this oneof within the message's oneof array.
+  int index() const;
+
+  // Returns whether this oneof was inserted by the compiler to wrap a proto3
+  // optional field. If this returns true, code generators should *not* emit it.
+  bool is_synthetic() const;
+
+  // The .proto file in which this oneof was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+  // The Descriptor for the message containing this oneof.
+  const Descriptor* containing_type() const;
+
+  // The number of (non-extension) fields which are members of this oneof.
+  int field_count() const;
+  // Get a member of this oneof, in the order in which they were declared in the
+  // .proto file.  Does not include extensions.
+  const FieldDescriptor* field(int index) const;
+
+  const OneofOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(OneofDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this oneof declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef OneofOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  int field_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const Descriptor* containing_type_;
+  const OneofOptions* options_;
+  const FieldDescriptor* fields_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
+  // in descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  OneofDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class Descriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 40);
+
+// Describes an enum type defined in a .proto file.  To get the EnumDescriptor
+// for a generated enum type, call TypeName_descriptor().  Use DescriptorPool
+// to construct your own descriptors.
+class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
+ public:
+  typedef EnumDescriptorProto Proto;
+
+  // The name of this enum type in the containing scope.
+  const std::string& name() const;
+
+  // The fully-qualified name of the enum type, scope delimited by periods.
+  const std::string& full_name() const;
+
+  // Index of this enum within the file or containing message's enum array.
+  int index() const;
+
+  // The .proto file in which this enum type was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+
+  // The number of values for this EnumDescriptor.  Guaranteed to be greater
+  // than zero.
+  int value_count() const;
+  // Gets a value by index, where 0 <= index < value_count().
+  // These are returned in the order they were defined in the .proto file.
+  const EnumValueDescriptor* value(int index) const;
+
+  // Looks up a value by name.  Returns nullptr if no such value exists.
+  const EnumValueDescriptor* FindValueByName(ConstStringParam name) const;
+  // Looks up a value by number.  Returns nullptr if no such value exists.  If
+  // multiple values have this number, the first one defined is returned.
+  const EnumValueDescriptor* FindValueByNumber(int number) const;
+
+  // If this enum type is nested in a message type, this is that message type.
+  // Otherwise, nullptr.
+  const Descriptor* containing_type() const;
+
+  // Get options for this enum type.  These are specified in the .proto file by
+  // placing lines like "option foo = 1234;" in the enum definition.  Allowed
+  // options are defined by EnumOptions in descriptor.proto, and any available
+  // extensions of that message.
+  const EnumOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(EnumDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Returns true if this is a placeholder for an unknown enum. This will
+  // only be the case if this descriptor comes from a DescriptorPool
+  // with AllowUnknownDependencies() set.
+  bool is_placeholder() const;
+
+  // Reserved fields -------------------------------------------------
+
+  // A range of reserved field numbers.
+  struct ReservedRange {
+    int start;  // inclusive
+    int end;    // inclusive
+  };
+
+  // The number of reserved ranges in this message type.
+  int reserved_range_count() const;
+  // Gets an reserved range by index, where 0 <= index <
+  // reserved_range_count(). These are returned in the order they were defined
+  // in the .proto file.
+  const EnumDescriptor::ReservedRange* reserved_range(int index) const;
+
+  // Returns true if the number is in one of the reserved ranges.
+  bool IsReservedNumber(int number) const;
+
+  // Returns nullptr if no reserved range contains the given number.
+  const EnumDescriptor::ReservedRange* FindReservedRangeContainingNumber(
+      int number) const;
+
+  // The number of reserved field names in this message type.
+  int reserved_name_count() const;
+
+  // Gets a reserved name by index, where 0 <= index < reserved_name_count().
+  const std::string& reserved_name(int index) const;
+
+  // Returns true if the field name is reserved.
+  bool IsReservedName(ConstStringParam name) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this enum declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef EnumOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // Allow access to FindValueByNumberCreatingIfUnknown.
+  friend class descriptor_unittest::DescriptorTest;
+
+  // Looks up a value by number.  If the value does not exist, dynamically
+  // creates a new EnumValueDescriptor for that value, assuming that it was
+  // unknown. If a new descriptor is created, this is done in a thread-safe way,
+  // and future calls will return the same value descriptor pointer.
+  //
+  // This is private but is used by Reflection (which is friended below) to
+  // return a valid EnumValueDescriptor from GetEnum() when this feature is
+  // enabled.
+  const EnumValueDescriptor* FindValueByNumberCreatingIfUnknown(
+      int number) const;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // True if this is a placeholder for an unknown type.
+  bool is_placeholder_ : 1;
+  // True if this is a placeholder and the type name wasn't fully-qualified.
+  bool is_unqualified_placeholder_ : 1;
+
+  // This points to the last value _index_ that is part of the sequence starting
+  // with the first label, where
+  //   `enum->value(i)->number() == enum->value(0)->number() + i`
+  // We measure relative to the first label to adapt to enum labels starting at
+  // 0 or 1.
+  // Uses 16-bit to avoid extra padding. Unlikely to have more than 2^15
+  // sequentially numbered labels in an enum.
+  int16_t sequential_value_limit_;
+
+  int value_count_;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const Descriptor* containing_type_;
+  const EnumOptions* options_;
+  EnumValueDescriptor* values_;
+
+  int reserved_range_count_;
+  int reserved_name_count_;
+  EnumDescriptor::ReservedRange* reserved_ranges_;
+  const std::string** reserved_names_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<EnumDescriptor>() and AllocateArray<EnumDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  EnumDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class Descriptor;
+  friend class FieldDescriptor;
+  friend class FileDescriptorTables;
+  friend class EnumValueDescriptor;
+  friend class FileDescriptor;
+  friend class DescriptorPool;
+  friend class Reflection;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 72);
+
+// Describes an individual enum constant of a particular type.  To get the
+// EnumValueDescriptor for a given enum value, first get the EnumDescriptor
+// for its type, then use EnumDescriptor::FindValueByName() or
+// EnumDescriptor::FindValueByNumber().  Use DescriptorPool to construct
+// your own descriptors.
+class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
+                                            private internal::SymbolBaseN<1> {
+ public:
+  typedef EnumValueDescriptorProto Proto;
+
+  const std::string& name() const;  // Name of this enum constant.
+  int index() const;                // Index within the enums's Descriptor.
+  int number() const;               // Numeric value of this enum constant.
+
+  // The full_name of an enum value is a sibling symbol of the enum type.
+  // e.g. the full name of FieldDescriptorProto::TYPE_INT32 is actually
+  // "google.protobuf.FieldDescriptorProto.TYPE_INT32", NOT
+  // "google.protobuf.FieldDescriptorProto.Type.TYPE_INT32".  This is to conform
+  // with C++ scoping rules for enums.
+  const std::string& full_name() const;
+
+  // The .proto file in which this value was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+  // The type of this value.  Never nullptr.
+  const EnumDescriptor* type() const;
+
+  // Get options for this enum value.  These are specified in the .proto file by
+  // adding text like "[foo = 1234]" after an enum value definition.  Allowed
+  // options are defined by EnumValueOptions in descriptor.proto, and any
+  // available extensions of that message.
+  const EnumValueOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(EnumValueDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this enum value declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef EnumValueOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  int number_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const EnumDescriptor* type_;
+  const EnumValueOptions* options_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<EnumValueDescriptor>() and AllocateArray<EnumValueDescriptor>()
+  // in descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  EnumValueDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class EnumDescriptor;
+  friend class DescriptorPool;
+  friend class FileDescriptorTables;
+  friend class Reflection;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 32);
+
+// Describes an RPC service. Use DescriptorPool to construct your own
+// descriptors.
+class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
+ public:
+  typedef ServiceDescriptorProto Proto;
+
+  // The name of the service, not including its containing scope.
+  const std::string& name() const;
+  // The fully-qualified name of the service, scope delimited by periods.
+  const std::string& full_name() const;
+  // Index of this service within the file's services array.
+  int index() const;
+
+  // The .proto file in which this service was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+
+  // Get options for this service type.  These are specified in the .proto file
+  // by placing lines like "option foo = 1234;" in the service definition.
+  // Allowed options are defined by ServiceOptions in descriptor.proto, and any
+  // available extensions of that message.
+  const ServiceOptions& options() const;
+
+  // The number of methods this service defines.
+  int method_count() const;
+  // Gets a MethodDescriptor by index, where 0 <= index < method_count().
+  // These are returned in the order they were defined in the .proto file.
+  const MethodDescriptor* method(int index) const;
+
+  // Look up a MethodDescriptor by name.
+  const MethodDescriptor* FindMethodByName(ConstStringParam name) const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(ServiceDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this service declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef ServiceOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const FileDescriptor* file_;
+  const ServiceOptions* options_;
+  MethodDescriptor* methods_;
+  int method_count_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<ServiceDescriptor>() and AllocateArray<ServiceDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  ServiceDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class FileDescriptor;
+  friend class MethodDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 48);
+
+// Describes an individual service method.  To obtain a MethodDescriptor given
+// a service, first get its ServiceDescriptor, then call
+// ServiceDescriptor::FindMethodByName().  Use DescriptorPool to construct your
+// own descriptors.
+class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
+ public:
+  typedef MethodDescriptorProto Proto;
+
+  // Name of this method, not including containing scope.
+  const std::string& name() const;
+  // The fully-qualified name of the method, scope delimited by periods.
+  const std::string& full_name() const;
+  // Index within the service's Descriptor.
+  int index() const;
+
+  // The .proto file in which this method was defined.  Never nullptr.
+  const FileDescriptor* file() const;
+  // Gets the service to which this method belongs.  Never nullptr.
+  const ServiceDescriptor* service() const;
+
+  // Gets the type of protocol message which this method accepts as input.
+  const Descriptor* input_type() const;
+  // Gets the type of protocol message which this message produces as output.
+  const Descriptor* output_type() const;
+
+  // Gets whether the client streams multiple requests.
+  bool client_streaming() const;
+  // Gets whether the server streams multiple responses.
+  bool server_streaming() const;
+
+  // Get options for this method.  These are specified in the .proto file by
+  // placing lines like "option foo = 1234;" in curly-braces after a method
+  // declaration.  Allowed options are defined by MethodOptions in
+  // descriptor.proto, and any available extensions of that message.
+  const MethodOptions& options() const;
+
+  // See Descriptor::CopyTo().
+  void CopyTo(MethodDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Source Location ---------------------------------------------------
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of this method declaration.  Returns false and leaves
+  // |*out_location| unchanged iff location information was not available.
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef MethodOptions OptionsType;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class io::Printer;
+  friend class compiler::cpp::Formatter;
+
+  // See Descriptor::DebugString().
+  void DebugString(int depth, std::string* contents,
+                   const DebugStringOptions& options) const;
+
+  // Walks up the descriptor tree to generate the source location path
+  // to this descriptor from the file root.
+  void GetLocationPath(std::vector<int>* output) const;
+
+  bool client_streaming_;
+  bool server_streaming_;
+  // all_names_ = [name, full_name]
+  const std::string* all_names_;
+  const ServiceDescriptor* service_;
+  mutable internal::LazyDescriptor input_type_;
+  mutable internal::LazyDescriptor output_type_;
+  const MethodOptions* options_;
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<MethodDescriptor>() and AllocateArray<MethodDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  // Must be constructed using DescriptorPool.
+  MethodDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class ServiceDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 64);
+
+// Describes a whole .proto file.  To get the FileDescriptor for a compiled-in
+// file, get the descriptor for something defined in that file and call
+// descriptor->file().  Use DescriptorPool to construct your own descriptors.
+class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
+ public:
+  typedef FileDescriptorProto Proto;
+
+  // The filename, relative to the source tree.
+  // e.g. "foo/bar/baz.proto"
+  const std::string& name() const;
+
+  // The package, e.g. "google.protobuf.compiler".
+  const std::string& package() const;
+
+  // The DescriptorPool in which this FileDescriptor and all its contents were
+  // allocated.  Never nullptr.
+  const DescriptorPool* pool() const;
+
+  // The number of files imported by this one.
+  int dependency_count() const;
+  // Gets an imported file by index, where 0 <= index < dependency_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FileDescriptor* dependency(int index) const;
+
+  // The number of files public imported by this one.
+  // The public dependency list is a subset of the dependency list.
+  int public_dependency_count() const;
+  // Gets a public imported file by index, where 0 <= index <
+  // public_dependency_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FileDescriptor* public_dependency(int index) const;
+
+  // The number of files that are imported for weak fields.
+  // The weak dependency list is a subset of the dependency list.
+  int weak_dependency_count() const;
+  // Gets a weak imported file by index, where 0 <= index <
+  // weak_dependency_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FileDescriptor* weak_dependency(int index) const;
+
+  // Number of top-level message types defined in this file.  (This does not
+  // include nested types.)
+  int message_type_count() const;
+  // Gets a top-level message type, where 0 <= index < message_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const Descriptor* message_type(int index) const;
+
+  // Number of top-level enum types defined in this file.  (This does not
+  // include nested types.)
+  int enum_type_count() const;
+  // Gets a top-level enum type, where 0 <= index < enum_type_count().
+  // These are returned in the order they were defined in the .proto file.
+  const EnumDescriptor* enum_type(int index) const;
+
+  // Number of services defined in this file.
+  int service_count() const;
+  // Gets a service, where 0 <= index < service_count().
+  // These are returned in the order they were defined in the .proto file.
+  const ServiceDescriptor* service(int index) const;
+
+  // Number of extensions defined at file scope.  (This does not include
+  // extensions nested within message types.)
+  int extension_count() const;
+  // Gets an extension's descriptor, where 0 <= index < extension_count().
+  // These are returned in the order they were defined in the .proto file.
+  const FieldDescriptor* extension(int index) const;
+
+  // Get options for this file.  These are specified in the .proto file by
+  // placing lines like "option foo = 1234;" at the top level, outside of any
+  // other definitions.  Allowed options are defined by FileOptions in
+  // descriptor.proto, and any available extensions of that message.
+  const FileOptions& options() const;
+
+  // Syntax of this file.
+  enum Syntax {
+    SYNTAX_UNKNOWN = 0,
+    SYNTAX_PROTO2 = 2,
+    SYNTAX_PROTO3 = 3,
+  };
+  Syntax syntax() const;
+  static const char* SyntaxName(Syntax syntax);
+
+  // Find a top-level message type by name (not full_name).  Returns nullptr if
+  // not found.
+  const Descriptor* FindMessageTypeByName(ConstStringParam name) const;
+  // Find a top-level enum type by name.  Returns nullptr if not found.
+  const EnumDescriptor* FindEnumTypeByName(ConstStringParam name) const;
+  // Find an enum value defined in any top-level enum by name.  Returns nullptr
+  // if not found.
+  const EnumValueDescriptor* FindEnumValueByName(ConstStringParam name) const;
+  // Find a service definition by name.  Returns nullptr if not found.
+  const ServiceDescriptor* FindServiceByName(ConstStringParam name) const;
+  // Find a top-level extension definition by name.  Returns nullptr if not
+  // found.
+  const FieldDescriptor* FindExtensionByName(ConstStringParam name) const;
+  // Similar to FindExtensionByName(), but searches by lowercased-name.  See
+  // Descriptor::FindFieldByLowercaseName().
+  const FieldDescriptor* FindExtensionByLowercaseName(
+      ConstStringParam name) const;
+  // Similar to FindExtensionByName(), but searches by camelcased-name.  See
+  // Descriptor::FindFieldByCamelcaseName().
+  const FieldDescriptor* FindExtensionByCamelcaseName(
+      ConstStringParam name) const;
+
+  // See Descriptor::CopyTo().
+  // Notes:
+  // - This method does NOT copy source code information since it is relatively
+  //   large and rarely needed.  See CopySourceCodeInfoTo() below.
+  void CopyTo(FileDescriptorProto* proto) const;
+  // Write the source code information of this FileDescriptor into the given
+  // FileDescriptorProto.  See CopyTo() above.
+  void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
+  // Fill the json_name field of FieldDescriptorProto for all fields. Can only
+  // be called after CopyTo().
+  void CopyJsonNameTo(FileDescriptorProto* proto) const;
+
+  // See Descriptor::DebugString().
+  std::string DebugString() const;
+
+  // See Descriptor::DebugStringWithOptions().
+  std::string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+  // Returns true if this is a placeholder for an unknown file. This will
+  // only be the case if this descriptor comes from a DescriptorPool
+  // with AllowUnknownDependencies() set.
+  bool is_placeholder() const;
+
+  // Updates |*out_location| to the source location of the complete extent of
+  // this file declaration (namely, the empty path).
+  bool GetSourceLocation(SourceLocation* out_location) const;
+
+  // Updates |*out_location| to the source location of the complete
+  // extent of the declaration or declaration-part denoted by |path|.
+  // Returns false and leaves |*out_location| unchanged iff location
+  // information was not available.  (See SourceCodeInfo for
+  // description of path encoding.)
+  bool GetSourceLocation(const std::vector<int>& path,
+                         SourceLocation* out_location) const;
+
+ private:
+  friend class Symbol;
+  typedef FileOptions OptionsType;
+
+  bool is_placeholder_;
+  // Indicates the FileDescriptor is completed building. Used to verify
+  // that type accessor functions that can possibly build a dependent file
+  // aren't called during the process of building the file.
+  bool finished_building_;
+  // Actually a `Syntax` but stored as uint8_t to save space.
+  uint8_t syntax_;
+  // This one is here to fill the padding.
+  int extension_count_;
+
+  const std::string* name_;
+  const std::string* package_;
+  const DescriptorPool* pool_;
+
+  // dependencies_once_ contain a once_flag followed by N NUL terminated
+  // strings. Dependencies that do not need to be loaded will be empty. ie just
+  // {'\0'}
+  internal::once_flag* dependencies_once_;
+  static void DependenciesOnceInit(const FileDescriptor* to_init);
+  void InternalDependenciesOnceInit() const;
+
+  // These are arranged to minimize padding on 64-bit.
+  int dependency_count_;
+  int public_dependency_count_;
+  int weak_dependency_count_;
+  int message_type_count_;
+  int enum_type_count_;
+  int service_count_;
+
+  mutable const FileDescriptor** dependencies_;
+  int* public_dependencies_;
+  int* weak_dependencies_;
+  Descriptor* message_types_;
+  EnumDescriptor* enum_types_;
+  ServiceDescriptor* services_;
+  FieldDescriptor* extensions_;
+  const FileOptions* options_;
+
+  const FileDescriptorTables* tables_;
+  const SourceCodeInfo* source_code_info_;
+
+  // IMPORTANT:  If you add a new field, make sure to search for all instances
+  // of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
+  // descriptor.cc and update them to initialize the field.
+
+  FileDescriptor() {}
+  friend class DescriptorBuilder;
+  friend class DescriptorPool;
+  friend class Descriptor;
+  friend class FieldDescriptor;
+  friend class internal::LazyDescriptor;
+  friend class OneofDescriptor;
+  friend class EnumDescriptor;
+  friend class EnumValueDescriptor;
+  friend class MethodDescriptor;
+  friend class ServiceDescriptor;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
+};
+
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 144);
+
+// ===================================================================
+
+// Used to construct descriptors.
+//
+// Normally you won't want to build your own descriptors.  Message classes
+// constructed by the protocol compiler will provide them for you.  However,
+// if you are implementing Message on your own, or if you are writing a
+// program which can operate on totally arbitrary types and needs to load
+// them from some sort of database, you might need to.
+//
+// Since Descriptors are composed of a whole lot of cross-linked bits of
+// data that would be a pain to put together manually, the
+// DescriptorPool class is provided to make the process easier.  It can
+// take a FileDescriptorProto (defined in descriptor.proto), validate it,
+// and convert it to a set of nicely cross-linked Descriptors.
+//
+// DescriptorPool also helps with memory management.  Descriptors are
+// composed of many objects containing static data and pointers to each
+// other.  In all likelihood, when it comes time to delete this data,
+// you'll want to delete it all at once.  In fact, it is not uncommon to
+// have a whole pool of descriptors all cross-linked with each other which
+// you wish to delete all at once.  This class represents such a pool, and
+// handles the memory management for you.
+//
+// You can also search for descriptors within a DescriptorPool by name, and
+// extensions by number.
+class PROTOBUF_EXPORT DescriptorPool {
+ public:
+  // Create a normal, empty DescriptorPool.
+  DescriptorPool();
+
+  // Constructs a DescriptorPool that, when it can't find something among the
+  // descriptors already in the pool, looks for it in the given
+  // DescriptorDatabase.
+  // Notes:
+  // - If a DescriptorPool is constructed this way, its BuildFile*() methods
+  //   must not be called (they will assert-fail).  The only way to populate
+  //   the pool with descriptors is to call the Find*By*() methods.
+  // - The Find*By*() methods may block the calling thread if the
+  //   DescriptorDatabase blocks.  This in turn means that parsing messages
+  //   may block if they need to look up extensions.
+  // - The Find*By*() methods will use mutexes for thread-safety, thus making
+  //   them slower even when they don't have to fall back to the database.
+  //   In fact, even the Find*By*() methods of descriptor objects owned by
+  //   this pool will be slower, since they will have to obtain locks too.
+  // - An ErrorCollector may optionally be given to collect validation errors
+  //   in files loaded from the database.  If not given, errors will be printed
+  //   to GOOGLE_LOG(ERROR).  Remember that files are built on-demand, so this
+  //   ErrorCollector may be called from any thread that calls one of the
+  //   Find*By*() methods.
+  // - The DescriptorDatabase must not be mutated during the lifetime of
+  //   the DescriptorPool. Even if the client takes care to avoid data races,
+  //   changes to the content of the DescriptorDatabase may not be reflected
+  //   in subsequent lookups in the DescriptorPool.
+  class ErrorCollector;
+  explicit DescriptorPool(DescriptorDatabase* fallback_database,
+                          ErrorCollector* error_collector = nullptr);
+
+  ~DescriptorPool();
+
+  // Get a pointer to the generated pool.  Generated protocol message classes
+  // which are compiled into the binary will allocate their descriptors in
+  // this pool.  Do not add your own descriptors to this pool.
+  static const DescriptorPool* generated_pool();
+
+
+  // Find a FileDescriptor in the pool by file name.  Returns nullptr if not
+  // found.
+  const FileDescriptor* FindFileByName(ConstStringParam name) const;
+
+  // Find the FileDescriptor in the pool which defines the given symbol.
+  // If any of the Find*ByName() methods below would succeed, then this is
+  // equivalent to calling that method and calling the result's file() method.
+  // Otherwise this returns nullptr.
+  const FileDescriptor* FindFileContainingSymbol(
+      ConstStringParam symbol_name) const;
+
+  // Looking up descriptors ------------------------------------------
+  // These find descriptors by fully-qualified name.  These will find both
+  // top-level descriptors and nested descriptors.  They return nullptr if not
+  // found.
+
+  const Descriptor* FindMessageTypeByName(ConstStringParam name) const;
+  const FieldDescriptor* FindFieldByName(ConstStringParam name) const;
+  const FieldDescriptor* FindExtensionByName(ConstStringParam name) const;
+  const OneofDescriptor* FindOneofByName(ConstStringParam name) const;
+  const EnumDescriptor* FindEnumTypeByName(ConstStringParam name) const;
+  const EnumValueDescriptor* FindEnumValueByName(ConstStringParam name) const;
+  const ServiceDescriptor* FindServiceByName(ConstStringParam name) const;
+  const MethodDescriptor* FindMethodByName(ConstStringParam name) const;
+
+  // Finds an extension of the given type by number.  The extendee must be
+  // a member of this DescriptorPool or one of its underlays.
+  const FieldDescriptor* FindExtensionByNumber(const Descriptor* extendee,
+                                               int number) const;
+
+  // Finds an extension of the given type by its printable name.
+  // See comments above PrintableNameForExtension() for the definition of
+  // "printable name".  The extendee must be a member of this DescriptorPool
+  // or one of its underlays.  Returns nullptr if there is no known message
+  // extension with the given printable name.
+  const FieldDescriptor* FindExtensionByPrintableName(
+      const Descriptor* extendee, ConstStringParam printable_name) const;
+
+  // Finds extensions of extendee. The extensions will be appended to
+  // out in an undefined order. Only extensions defined directly in
+  // this DescriptorPool or one of its underlays are guaranteed to be
+  // found: extensions defined in the fallback database might not be found
+  // depending on the database implementation.
+  void FindAllExtensions(const Descriptor* extendee,
+                         std::vector<const FieldDescriptor*>* out) const;
+
+  // Building descriptors --------------------------------------------
+
+  // When converting a FileDescriptorProto to a FileDescriptor, various
+  // errors might be detected in the input.  The caller may handle these
+  // programmatically by implementing an ErrorCollector.
+  class PROTOBUF_EXPORT ErrorCollector {
+   public:
+    inline ErrorCollector() {}
+    virtual ~ErrorCollector();
+
+    // These constants specify what exact part of the construct is broken.
+    // This is useful e.g. for mapping the error back to an exact location
+    // in a .proto file.
+    enum ErrorLocation {
+      NAME,           // the symbol name, or the package name for files
+      NUMBER,         // field or extension range number
+      TYPE,           // field type
+      EXTENDEE,       // field extendee
+      DEFAULT_VALUE,  // field default value
+      INPUT_TYPE,     // method input type
+      OUTPUT_TYPE,    // method output type
+      OPTION_NAME,    // name in assignment
+      OPTION_VALUE,   // value in option assignment
+      IMPORT,         // import error
+      OTHER           // some other problem
+    };
+
+    // Reports an error in the FileDescriptorProto. Use this function if the
+    // problem occurred should interrupt building the FileDescriptorProto.
+    virtual void AddError(
+        const std::string& filename,  // File name in which the error occurred.
+        const std::string& element_name,  // Full name of the erroneous element.
+        const Message* descriptor,  // Descriptor of the erroneous element.
+        ErrorLocation location,     // One of the location constants, above.
+        const std::string& message  // Human-readable error message.
+        ) = 0;
+
+    // Reports a warning in the FileDescriptorProto. Use this function if the
+    // problem occurred should NOT interrupt building the FileDescriptorProto.
+    virtual void AddWarning(
+        const std::string& /*filename*/,      // File name in which the error
+                                              // occurred.
+        const std::string& /*element_name*/,  // Full name of the erroneous
+                                              // element.
+        const Message* /*descriptor*/,  // Descriptor of the erroneous element.
+        ErrorLocation /*location*/,     // One of the location constants, above.
+        const std::string& /*message*/  // Human-readable error message.
+    ) {}
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
+  };
+
+  // Convert the FileDescriptorProto to real descriptors and place them in
+  // this DescriptorPool.  All dependencies of the file must already be in
+  // the pool.  Returns the resulting FileDescriptor, or nullptr if there were
+  // problems with the input (e.g. the message was invalid, or dependencies
+  // were missing).  Details about the errors are written to GOOGLE_LOG(ERROR).
+  const FileDescriptor* BuildFile(const FileDescriptorProto& proto);
+
+  // Same as BuildFile() except errors are sent to the given ErrorCollector.
+  const FileDescriptor* BuildFileCollectingErrors(
+      const FileDescriptorProto& proto, ErrorCollector* error_collector);
+
+  // By default, it is an error if a FileDescriptorProto contains references
+  // to types or other files that are not found in the DescriptorPool (or its
+  // backing DescriptorDatabase, if any).  If you call
+  // AllowUnknownDependencies(), however, then unknown types and files
+  // will be replaced by placeholder descriptors (which can be identified by
+  // the is_placeholder() method).  This can allow you to
+  // perform some useful operations with a .proto file even if you do not
+  // have access to other .proto files on which it depends.  However, some
+  // heuristics must be used to fill in the gaps in information, and these
+  // can lead to descriptors which are inaccurate.  For example, the
+  // DescriptorPool may be forced to guess whether an unknown type is a message
+  // or an enum, as well as what package it resides in.  Furthermore,
+  // placeholder types will not be discoverable via FindMessageTypeByName()
+  // and similar methods, which could confuse some descriptor-based algorithms.
+  // Generally, the results of this option should be handled with extreme care.
+  void AllowUnknownDependencies() { allow_unknown_ = true; }
+
+  // By default, weak imports are allowed to be missing, in which case we will
+  // use a placeholder for the dependency and convert the field to be an Empty
+  // message field. If you call EnforceWeakDependencies(true), however, the
+  // DescriptorPool will report a import not found error.
+  void EnforceWeakDependencies(bool enforce) { enforce_weak_ = enforce; }
+
+  // Internal stuff --------------------------------------------------
+  // These methods MUST NOT be called from outside the proto2 library.
+  // These methods may contain hidden pitfalls and may be removed in a
+  // future library version.
+
+  // Create a DescriptorPool which is overlaid on top of some other pool.
+  // If you search for a descriptor in the overlay and it is not found, the
+  // underlay will be searched as a backup.  If the underlay has its own
+  // underlay, that will be searched next, and so on.  This also means that
+  // files built in the overlay will be cross-linked with the underlay's
+  // descriptors if necessary.  The underlay remains property of the caller;
+  // it must remain valid for the lifetime of the newly-constructed pool.
+  //
+  // Example:  Say you want to parse a .proto file at runtime in order to use
+  // its type with a DynamicMessage.  Say this .proto file has dependencies,
+  // but you know that all the dependencies will be things that are already
+  // compiled into the binary.  For ease of use, you'd like to load the types
+  // right out of generated_pool() rather than have to parse redundant copies
+  // of all these .protos and runtime.  But, you don't want to add the parsed
+  // types directly into generated_pool(): this is not allowed, and would be
+  // bad design anyway.  So, instead, you could use generated_pool() as an
+  // underlay for a new DescriptorPool in which you add only the new file.
+  //
+  // WARNING:  Use of underlays can lead to many subtle gotchas.  Instead,
+  //   try to formulate what you want to do in terms of DescriptorDatabases.
+  explicit DescriptorPool(const DescriptorPool* underlay);
+
+  // Called by generated classes at init time to add their descriptors to
+  // generated_pool.  Do NOT call this in your own code!  filename must be a
+  // permanent string (e.g. a string literal).
+  static void InternalAddGeneratedFile(const void* encoded_file_descriptor,
+                                       int size);
+
+  // Disallow [enforce_utf8 = false] in .proto files.
+  void DisallowEnforceUtf8() { disallow_enforce_utf8_ = true; }
+
+
+  // For internal use only:  Gets a non-const pointer to the generated pool.
+  // This is called at static-initialization time only, so thread-safety is
+  // not a concern.  If both an underlay and a fallback database are present,
+  // the underlay takes precedence.
+  static DescriptorPool* internal_generated_pool();
+
+  // For internal use only:  Gets a non-const pointer to the generated
+  // descriptor database.
+  // Only used for testing.
+  static DescriptorDatabase* internal_generated_database();
+
+  // For internal use only:  Changes the behavior of BuildFile() such that it
+  // allows the file to make reference to message types declared in other files
+  // which it did not officially declare as dependencies.
+  void InternalDontEnforceDependencies();
+
+  // For internal use only: Enables lazy building of dependencies of a file.
+  // Delay the building of dependencies of a file descriptor until absolutely
+  // necessary, like when message_type() is called on a field that is defined
+  // in that dependency's file. This will cause functional issues if a proto
+  // or one of its dependencies has errors. Should only be enabled for the
+  // generated_pool_ (because no descriptor build errors are guaranteed by
+  // the compilation generation process), testing, or if a lack of descriptor
+  // build errors can be guaranteed for a pool.
+  void InternalSetLazilyBuildDependencies() {
+    lazily_build_dependencies_ = true;
+    // This needs to be set when lazily building dependencies, as it breaks
+    // dependency checking.
+    InternalDontEnforceDependencies();
+  }
+
+  // For internal use only.
+  void internal_set_underlay(const DescriptorPool* underlay) {
+    underlay_ = underlay;
+  }
+
+  // For internal (unit test) use only:  Returns true if a FileDescriptor has
+  // been constructed for the given file, false otherwise.  Useful for testing
+  // lazy descriptor initialization behavior.
+  bool InternalIsFileLoaded(ConstStringParam filename) const;
+
+  // Add a file to unused_import_track_files_. DescriptorBuilder will log
+  // warnings or errors for those files if there is any unused import.
+  void AddUnusedImportTrackFile(ConstStringParam file_name,
+                                bool is_error = false);
+  void ClearUnusedImportTrackFiles();
+
+ private:
+  friend class Descriptor;
+  friend class internal::LazyDescriptor;
+  friend class FieldDescriptor;
+  friend class EnumDescriptor;
+  friend class ServiceDescriptor;
+  friend class MethodDescriptor;
+  friend class FileDescriptor;
+  friend class DescriptorBuilder;
+  friend class FileDescriptorTables;
+
+  // Return true if the given name is a sub-symbol of any non-package
+  // descriptor that already exists in the descriptor pool.  (The full
+  // definition of such types is already known.)
+  bool IsSubSymbolOfBuiltType(StringPiece name) const;
+
+  // Tries to find something in the fallback database and link in the
+  // corresponding proto file.  Returns true if successful, in which case
+  // the caller should search for the thing again.  These are declared
+  // const because they are called by (semantically) const methods.
+  bool TryFindFileInFallbackDatabase(StringPiece name) const;
+  bool TryFindSymbolInFallbackDatabase(StringPiece name) const;
+  bool TryFindExtensionInFallbackDatabase(const Descriptor* containing_type,
+                                          int field_number) const;
+
+  // This internal find extension method only check with its table and underlay
+  // descriptor_pool's table. It does not check with fallback DB and no
+  // additional proto file will be build in this method.
+  const FieldDescriptor* InternalFindExtensionByNumberNoLock(
+      const Descriptor* extendee, int number) const;
+
+  // Like BuildFile() but called internally when the file has been loaded from
+  // fallback_database_.  Declared const because it is called by (semantically)
+  // const methods.
+  const FileDescriptor* BuildFileFromDatabase(
+      const FileDescriptorProto& proto) const;
+
+  // Helper for when lazily_build_dependencies_ is set, can look up a symbol
+  // after the file's descriptor is built, and can build the file where that
+  // symbol is defined if necessary. Will create a placeholder if the type
+  // doesn't exist in the fallback database, or the file doesn't build
+  // successfully.
+  Symbol CrossLinkOnDemandHelper(StringPiece name,
+                                 bool expecting_enum) const;
+
+  // Create a placeholder FileDescriptor of the specified name
+  FileDescriptor* NewPlaceholderFile(StringPiece name) const;
+  FileDescriptor* NewPlaceholderFileWithMutexHeld(
+      StringPiece name, internal::FlatAllocator& alloc) const;
+
+  enum PlaceholderType {
+    PLACEHOLDER_MESSAGE,
+    PLACEHOLDER_ENUM,
+    PLACEHOLDER_EXTENDABLE_MESSAGE
+  };
+  // Create a placeholder Descriptor of the specified name
+  Symbol NewPlaceholder(StringPiece name,
+                        PlaceholderType placeholder_type) const;
+  Symbol NewPlaceholderWithMutexHeld(StringPiece name,
+                                     PlaceholderType placeholder_type) const;
+
+  // If fallback_database_ is nullptr, this is nullptr.  Otherwise, this is a
+  // mutex which must be locked while accessing tables_.
+  internal::WrappedMutex* mutex_;
+
+  // See constructor.
+  DescriptorDatabase* fallback_database_;
+  ErrorCollector* default_error_collector_;
+  const DescriptorPool* underlay_;
+
+  // This class contains a lot of hash maps with complicated types that
+  // we'd like to keep out of the header.
+  class Tables;
+  std::unique_ptr<Tables> tables_;
+
+  bool enforce_dependencies_;
+  bool lazily_build_dependencies_;
+  bool allow_unknown_;
+  bool enforce_weak_;
+  bool disallow_enforce_utf8_;
+
+  // Set of files to track for unused imports. The bool value when true means
+  // unused imports are treated as errors (and as warnings when false).
+  std::map<std::string, bool> unused_import_track_files_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPool);
+};
+
+
+// inline methods ====================================================
+
+// These macros makes this repetitive code more readable.
+#define PROTOBUF_DEFINE_ACCESSOR(CLASS, FIELD, TYPE) \
+  inline TYPE CLASS::FIELD() const { return FIELD##_; }
+
+// Strings fields are stored as pointers but returned as const references.
+#define PROTOBUF_DEFINE_STRING_ACCESSOR(CLASS, FIELD) \
+  inline const std::string& CLASS::FIELD() const { return *FIELD##_; }
+
+// Name and full name are stored in a single array to save space.
+#define PROTOBUF_DEFINE_NAME_ACCESSOR(CLASS)                              \
+  inline const std::string& CLASS::name() const { return all_names_[0]; } \
+  inline const std::string& CLASS::full_name() const { return all_names_[1]; }
+
+// Arrays take an index parameter, obviously.
+#define PROTOBUF_DEFINE_ARRAY_ACCESSOR(CLASS, FIELD, TYPE) \
+  inline TYPE CLASS::FIELD(int index) const { return FIELD##s_ + index; }
+
+#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
+  inline const TYPE& CLASS::options() const { return *options_; }
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(Descriptor)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*)
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, field_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, oneof_decl_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, real_oneof_decl_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, nested_type_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, enum_type_count, int)
+
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, field, const FieldDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, oneof_decl, const OneofDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, nested_type, const Descriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, enum_type, const EnumDescriptor*)
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_range_count, int)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range,
+                               const Descriptor::ExtensionRange*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension, const FieldDescriptor*)
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_range_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range,
+                               const Descriptor::ReservedRange*)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int)
+
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(FieldDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_json_name, bool)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32_t, int32_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64_t, int64_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32_t, uint32_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64_t, uint64_t)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_float, float)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_double, double)
+PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_bool, bool)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(OneofDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(OneofDescriptor, field, const FieldDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(EnumDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
+                               const EnumValueDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_range_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, reserved_range,
+                               const EnumDescriptor::ReservedRange*)
+PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_name_count, int)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(EnumValueDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
+PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(ServiceDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*)
+PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
+                               const MethodDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
+
+PROTOBUF_DEFINE_NAME_ACCESSOR(MethodDescriptor)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
+
+PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, public_dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, weak_dependency_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
+PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool)
+
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, service,
+                               const ServiceDescriptor*)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, extension,
+                               const FieldDescriptor*)
+
+#undef PROTOBUF_DEFINE_ACCESSOR
+#undef PROTOBUF_DEFINE_STRING_ACCESSOR
+#undef PROTOBUF_DEFINE_ARRAY_ACCESSOR
+
+// A few accessors differ from the macros...
+
+inline Descriptor::WellKnownType Descriptor::well_known_type() const {
+  return static_cast<Descriptor::WellKnownType>(well_known_type_);
+}
+
+inline bool Descriptor::IsExtensionNumber(int number) const {
+  return FindExtensionRangeContainingNumber(number) != nullptr;
+}
+
+inline bool Descriptor::IsReservedNumber(int number) const {
+  return FindReservedRangeContainingNumber(number) != nullptr;
+}
+
+inline bool Descriptor::IsReservedName(ConstStringParam name) const {
+  for (int i = 0; i < reserved_name_count(); i++) {
+    if (name == static_cast<ConstStringParam>(reserved_name(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because reserved_names_ is actually
+// an array of pointers rather than the usual array of objects.
+inline const std::string& Descriptor::reserved_name(int index) const {
+  return *reserved_names_[index];
+}
+
+inline bool EnumDescriptor::IsReservedNumber(int number) const {
+  return FindReservedRangeContainingNumber(number) != nullptr;
+}
+
+inline bool EnumDescriptor::IsReservedName(ConstStringParam name) const {
+  for (int i = 0; i < reserved_name_count(); i++) {
+    if (name == static_cast<ConstStringParam>(reserved_name(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because reserved_names_ is actually
+// an array of pointers rather than the usual array of objects.
+inline const std::string& EnumDescriptor::reserved_name(int index) const {
+  return *reserved_names_[index];
+}
+
+inline const std::string& FieldDescriptor::lowercase_name() const {
+  return all_names_[lowercase_name_index_];
+}
+
+inline const std::string& FieldDescriptor::camelcase_name() const {
+  return all_names_[camelcase_name_index_];
+}
+
+inline const std::string& FieldDescriptor::json_name() const {
+  return all_names_[json_name_index_];
+}
+
+inline const OneofDescriptor* FieldDescriptor::containing_oneof() const {
+  return is_oneof_ ? scope_.containing_oneof : nullptr;
+}
+
+inline int FieldDescriptor::index_in_oneof() const {
+  GOOGLE_DCHECK(is_oneof_);
+  return static_cast<int>(this - scope_.containing_oneof->field(0));
+}
+
+inline const Descriptor* FieldDescriptor::extension_scope() const {
+  GOOGLE_CHECK(is_extension_);
+  return scope_.extension_scope;
+}
+
+inline FieldDescriptor::Label FieldDescriptor::label() const {
+  return static_cast<Label>(label_);
+}
+
+inline FieldDescriptor::Type FieldDescriptor::type() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, &FieldDescriptor::TypeOnceInit, this);
+  }
+  return static_cast<Type>(type_);
+}
+
+inline bool FieldDescriptor::is_required() const {
+  return label() == LABEL_REQUIRED;
+}
+
+inline bool FieldDescriptor::is_optional() const {
+  return label() == LABEL_OPTIONAL;
+}
+
+inline bool FieldDescriptor::is_repeated() const {
+  return label() == LABEL_REPEATED;
+}
+
+inline bool FieldDescriptor::is_packable() const {
+  return is_repeated() && IsTypePackable(type());
+}
+
+inline bool FieldDescriptor::is_map() const {
+  return type() == TYPE_MESSAGE && is_map_message_type();
+}
+
+inline bool FieldDescriptor::has_optional_keyword() const {
+  return proto3_optional_ ||
+         (file()->syntax() == FileDescriptor::SYNTAX_PROTO2 && is_optional() &&
+          !containing_oneof());
+}
+
+inline const OneofDescriptor* FieldDescriptor::real_containing_oneof() const {
+  auto* oneof = containing_oneof();
+  return oneof && !oneof->is_synthetic() ? oneof : nullptr;
+}
+
+inline bool FieldDescriptor::has_presence() const {
+  if (is_repeated()) return false;
+  return cpp_type() == CPPTYPE_MESSAGE || containing_oneof() ||
+         file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
+// To save space, index() is computed by looking at the descriptor's position
+// in the parent's array of children.
+inline int FieldDescriptor::index() const {
+  if (!is_extension_) {
+    return static_cast<int>(this - containing_type()->fields_);
+  } else if (extension_scope() != nullptr) {
+    return static_cast<int>(this - extension_scope()->extensions_);
+  } else {
+    return static_cast<int>(this - file_->extensions_);
+  }
+}
+
+inline int Descriptor::index() const {
+  if (containing_type_ == nullptr) {
+    return static_cast<int>(this - file_->message_types_);
+  } else {
+    return static_cast<int>(this - containing_type_->nested_types_);
+  }
+}
+
+inline const FileDescriptor* OneofDescriptor::file() const {
+  return containing_type()->file();
+}
+
+inline int OneofDescriptor::index() const {
+  return static_cast<int>(this - containing_type_->oneof_decls_);
+}
+
+inline bool OneofDescriptor::is_synthetic() const {
+  return field_count() == 1 && field(0)->proto3_optional_;
+}
+
+inline int EnumDescriptor::index() const {
+  if (containing_type_ == nullptr) {
+    return static_cast<int>(this - file_->enum_types_);
+  } else {
+    return static_cast<int>(this - containing_type_->enum_types_);
+  }
+}
+
+inline const FileDescriptor* EnumValueDescriptor::file() const {
+  return type()->file();
+}
+
+inline int EnumValueDescriptor::index() const {
+  return static_cast<int>(this - type_->values_);
+}
+
+inline int ServiceDescriptor::index() const {
+  return static_cast<int>(this - file_->services_);
+}
+
+inline const FileDescriptor* MethodDescriptor::file() const {
+  return service()->file();
+}
+
+inline int MethodDescriptor::index() const {
+  return static_cast<int>(this - service_->methods_);
+}
+
+inline const char* FieldDescriptor::type_name() const {
+  return kTypeToName[type()];
+}
+
+inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const {
+  return kTypeToCppTypeMap[type()];
+}
+
+inline const char* FieldDescriptor::cpp_type_name() const {
+  return kCppTypeToName[kTypeToCppTypeMap[type()]];
+}
+
+inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) {
+  return kTypeToCppTypeMap[type];
+}
+
+inline const char* FieldDescriptor::TypeName(Type type) {
+  return kTypeToName[type];
+}
+
+inline const char* FieldDescriptor::CppTypeName(CppType cpp_type) {
+  return kCppTypeToName[cpp_type];
+}
+
+inline bool FieldDescriptor::IsTypePackable(Type field_type) {
+  return (field_type != FieldDescriptor::TYPE_STRING &&
+          field_type != FieldDescriptor::TYPE_GROUP &&
+          field_type != FieldDescriptor::TYPE_MESSAGE &&
+          field_type != FieldDescriptor::TYPE_BYTES);
+}
+
+inline const FileDescriptor* FileDescriptor::public_dependency(
+    int index) const {
+  return dependency(public_dependencies_[index]);
+}
+
+inline const FileDescriptor* FileDescriptor::weak_dependency(int index) const {
+  return dependency(weak_dependencies_[index]);
+}
+
+inline FileDescriptor::Syntax FileDescriptor::syntax() const {
+  return static_cast<Syntax>(syntax_);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#undef PROTOBUF_INTERNAL_CHECK_CLASS_SIZE
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_DESCRIPTOR_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor.pb.h
new file mode 100644
index 0000000..9ae046a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor.pb.h
@@ -0,0 +1,14821 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fdescriptor_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fdescriptor_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class DescriptorProto;
+struct DescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern DescriptorProtoDefaultTypeInternal _DescriptorProto_default_instance_;
+class DescriptorProto_ExtensionRange;
+struct DescriptorProto_ExtensionRangeDefaultTypeInternal;
+PROTOBUF_EXPORT extern DescriptorProto_ExtensionRangeDefaultTypeInternal _DescriptorProto_ExtensionRange_default_instance_;
+class DescriptorProto_ReservedRange;
+struct DescriptorProto_ReservedRangeDefaultTypeInternal;
+PROTOBUF_EXPORT extern DescriptorProto_ReservedRangeDefaultTypeInternal _DescriptorProto_ReservedRange_default_instance_;
+class EnumDescriptorProto;
+struct EnumDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumDescriptorProtoDefaultTypeInternal _EnumDescriptorProto_default_instance_;
+class EnumDescriptorProto_EnumReservedRange;
+struct EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal _EnumDescriptorProto_EnumReservedRange_default_instance_;
+class EnumOptions;
+struct EnumOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumOptionsDefaultTypeInternal _EnumOptions_default_instance_;
+class EnumValueDescriptorProto;
+struct EnumValueDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumValueDescriptorProtoDefaultTypeInternal _EnumValueDescriptorProto_default_instance_;
+class EnumValueOptions;
+struct EnumValueOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumValueOptionsDefaultTypeInternal _EnumValueOptions_default_instance_;
+class ExtensionRangeOptions;
+struct ExtensionRangeOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern ExtensionRangeOptionsDefaultTypeInternal _ExtensionRangeOptions_default_instance_;
+class FieldDescriptorProto;
+struct FieldDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldDescriptorProtoDefaultTypeInternal _FieldDescriptorProto_default_instance_;
+class FieldOptions;
+struct FieldOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldOptionsDefaultTypeInternal _FieldOptions_default_instance_;
+class FileDescriptorProto;
+struct FileDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern FileDescriptorProtoDefaultTypeInternal _FileDescriptorProto_default_instance_;
+class FileDescriptorSet;
+struct FileDescriptorSetDefaultTypeInternal;
+PROTOBUF_EXPORT extern FileDescriptorSetDefaultTypeInternal _FileDescriptorSet_default_instance_;
+class FileOptions;
+struct FileOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern FileOptionsDefaultTypeInternal _FileOptions_default_instance_;
+class GeneratedCodeInfo;
+struct GeneratedCodeInfoDefaultTypeInternal;
+PROTOBUF_EXPORT extern GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
+class GeneratedCodeInfo_Annotation;
+struct GeneratedCodeInfo_AnnotationDefaultTypeInternal;
+PROTOBUF_EXPORT extern GeneratedCodeInfo_AnnotationDefaultTypeInternal _GeneratedCodeInfo_Annotation_default_instance_;
+class MessageOptions;
+struct MessageOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern MessageOptionsDefaultTypeInternal _MessageOptions_default_instance_;
+class MethodDescriptorProto;
+struct MethodDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern MethodDescriptorProtoDefaultTypeInternal _MethodDescriptorProto_default_instance_;
+class MethodOptions;
+struct MethodOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern MethodOptionsDefaultTypeInternal _MethodOptions_default_instance_;
+class OneofDescriptorProto;
+struct OneofDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern OneofDescriptorProtoDefaultTypeInternal _OneofDescriptorProto_default_instance_;
+class OneofOptions;
+struct OneofOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern OneofOptionsDefaultTypeInternal _OneofOptions_default_instance_;
+class ServiceDescriptorProto;
+struct ServiceDescriptorProtoDefaultTypeInternal;
+PROTOBUF_EXPORT extern ServiceDescriptorProtoDefaultTypeInternal _ServiceDescriptorProto_default_instance_;
+class ServiceOptions;
+struct ServiceOptionsDefaultTypeInternal;
+PROTOBUF_EXPORT extern ServiceOptionsDefaultTypeInternal _ServiceOptions_default_instance_;
+class SourceCodeInfo;
+struct SourceCodeInfoDefaultTypeInternal;
+PROTOBUF_EXPORT extern SourceCodeInfoDefaultTypeInternal _SourceCodeInfo_default_instance_;
+class SourceCodeInfo_Location;
+struct SourceCodeInfo_LocationDefaultTypeInternal;
+PROTOBUF_EXPORT extern SourceCodeInfo_LocationDefaultTypeInternal _SourceCodeInfo_Location_default_instance_;
+class UninterpretedOption;
+struct UninterpretedOptionDefaultTypeInternal;
+PROTOBUF_EXPORT extern UninterpretedOptionDefaultTypeInternal _UninterpretedOption_default_instance_;
+class UninterpretedOption_NamePart;
+struct UninterpretedOption_NamePartDefaultTypeInternal;
+PROTOBUF_EXPORT extern UninterpretedOption_NamePartDefaultTypeInternal _UninterpretedOption_NamePart_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValueOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileDescriptorSet>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FileOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::MessageOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MessageOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::MethodOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MethodOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::OneofOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::OneofOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ServiceOptions* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ServiceOptions>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceCodeInfo>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UninterpretedOption>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+enum FieldDescriptorProto_Type : int {
+  FieldDescriptorProto_Type_TYPE_DOUBLE = 1,
+  FieldDescriptorProto_Type_TYPE_FLOAT = 2,
+  FieldDescriptorProto_Type_TYPE_INT64 = 3,
+  FieldDescriptorProto_Type_TYPE_UINT64 = 4,
+  FieldDescriptorProto_Type_TYPE_INT32 = 5,
+  FieldDescriptorProto_Type_TYPE_FIXED64 = 6,
+  FieldDescriptorProto_Type_TYPE_FIXED32 = 7,
+  FieldDescriptorProto_Type_TYPE_BOOL = 8,
+  FieldDescriptorProto_Type_TYPE_STRING = 9,
+  FieldDescriptorProto_Type_TYPE_GROUP = 10,
+  FieldDescriptorProto_Type_TYPE_MESSAGE = 11,
+  FieldDescriptorProto_Type_TYPE_BYTES = 12,
+  FieldDescriptorProto_Type_TYPE_UINT32 = 13,
+  FieldDescriptorProto_Type_TYPE_ENUM = 14,
+  FieldDescriptorProto_Type_TYPE_SFIXED32 = 15,
+  FieldDescriptorProto_Type_TYPE_SFIXED64 = 16,
+  FieldDescriptorProto_Type_TYPE_SINT32 = 17,
+  FieldDescriptorProto_Type_TYPE_SINT64 = 18
+};
+PROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
+constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
+constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
+template<typename T>
+inline const std::string& FieldDescriptorProto_Type_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldDescriptorProto_Type>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldDescriptorProto_Type_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldDescriptorProto_Type_descriptor(), enum_t_value);
+}
+inline bool FieldDescriptorProto_Type_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldDescriptorProto_Type* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldDescriptorProto_Type>(
+    FieldDescriptorProto_Type_descriptor(), name, value);
+}
+enum FieldDescriptorProto_Label : int {
+  FieldDescriptorProto_Label_LABEL_OPTIONAL = 1,
+  FieldDescriptorProto_Label_LABEL_REQUIRED = 2,
+  FieldDescriptorProto_Label_LABEL_REPEATED = 3
+};
+PROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
+constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
+constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
+template<typename T>
+inline const std::string& FieldDescriptorProto_Label_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldDescriptorProto_Label>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldDescriptorProto_Label_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldDescriptorProto_Label_descriptor(), enum_t_value);
+}
+inline bool FieldDescriptorProto_Label_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldDescriptorProto_Label* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldDescriptorProto_Label>(
+    FieldDescriptorProto_Label_descriptor(), name, value);
+}
+enum FileOptions_OptimizeMode : int {
+  FileOptions_OptimizeMode_SPEED = 1,
+  FileOptions_OptimizeMode_CODE_SIZE = 2,
+  FileOptions_OptimizeMode_LITE_RUNTIME = 3
+};
+PROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
+constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
+constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
+constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
+template<typename T>
+inline const std::string& FileOptions_OptimizeMode_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FileOptions_OptimizeMode>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FileOptions_OptimizeMode_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FileOptions_OptimizeMode_descriptor(), enum_t_value);
+}
+inline bool FileOptions_OptimizeMode_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FileOptions_OptimizeMode* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FileOptions_OptimizeMode>(
+    FileOptions_OptimizeMode_descriptor(), name, value);
+}
+enum FieldOptions_CType : int {
+  FieldOptions_CType_STRING = 0,
+  FieldOptions_CType_CORD = 1,
+  FieldOptions_CType_STRING_PIECE = 2
+};
+PROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
+constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING;
+constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
+constexpr int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor();
+template<typename T>
+inline const std::string& FieldOptions_CType_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldOptions_CType>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldOptions_CType_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldOptions_CType_descriptor(), enum_t_value);
+}
+inline bool FieldOptions_CType_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldOptions_CType* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldOptions_CType>(
+    FieldOptions_CType_descriptor(), name, value);
+}
+enum FieldOptions_JSType : int {
+  FieldOptions_JSType_JS_NORMAL = 0,
+  FieldOptions_JSType_JS_STRING = 1,
+  FieldOptions_JSType_JS_NUMBER = 2
+};
+PROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value);
+constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
+constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
+constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor();
+template<typename T>
+inline const std::string& FieldOptions_JSType_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, FieldOptions_JSType>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function FieldOptions_JSType_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    FieldOptions_JSType_descriptor(), enum_t_value);
+}
+inline bool FieldOptions_JSType_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldOptions_JSType* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldOptions_JSType>(
+    FieldOptions_JSType_descriptor(), name, value);
+}
+enum MethodOptions_IdempotencyLevel : int {
+  MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN = 0,
+  MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS = 1,
+  MethodOptions_IdempotencyLevel_IDEMPOTENT = 2
+};
+PROTOBUF_EXPORT bool MethodOptions_IdempotencyLevel_IsValid(int value);
+constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IDEMPOTENT;
+constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor();
+template<typename T>
+inline const std::string& MethodOptions_IdempotencyLevel_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, MethodOptions_IdempotencyLevel>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function MethodOptions_IdempotencyLevel_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    MethodOptions_IdempotencyLevel_descriptor(), enum_t_value);
+}
+inline bool MethodOptions_IdempotencyLevel_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, MethodOptions_IdempotencyLevel* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<MethodOptions_IdempotencyLevel>(
+    MethodOptions_IdempotencyLevel_descriptor(), name, value);
+}
+// ===================================================================
+
+class PROTOBUF_EXPORT FileDescriptorSet final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorSet) */ {
+ public:
+  inline FileDescriptorSet() : FileDescriptorSet(nullptr) {}
+  ~FileDescriptorSet() override;
+  explicit PROTOBUF_CONSTEXPR FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FileDescriptorSet(const FileDescriptorSet& from);
+  FileDescriptorSet(FileDescriptorSet&& from) noexcept
+    : FileDescriptorSet() {
+    *this = ::std::move(from);
+  }
+
+  inline FileDescriptorSet& operator=(const FileDescriptorSet& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FileDescriptorSet& operator=(FileDescriptorSet&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FileDescriptorSet& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FileDescriptorSet* internal_default_instance() {
+    return reinterpret_cast<const FileDescriptorSet*>(
+               &_FileDescriptorSet_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(FileDescriptorSet& a, FileDescriptorSet& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FileDescriptorSet* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FileDescriptorSet* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FileDescriptorSet* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FileDescriptorSet>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FileDescriptorSet& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FileDescriptorSet& from) {
+    FileDescriptorSet::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FileDescriptorSet* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FileDescriptorSet";
+  }
+  protected:
+  explicit FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFileFieldNumber = 1,
+  };
+  // repeated .google.protobuf.FileDescriptorProto file = 1;
+  int file_size() const;
+  private:
+  int _internal_file_size() const;
+  public:
+  void clear_file();
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* mutable_file(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
+      mutable_file();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& _internal_file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _internal_add_file();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& file(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* add_file();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >&
+      file() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto > file_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FileDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorProto) */ {
+ public:
+  inline FileDescriptorProto() : FileDescriptorProto(nullptr) {}
+  ~FileDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FileDescriptorProto(const FileDescriptorProto& from);
+  FileDescriptorProto(FileDescriptorProto&& from) noexcept
+    : FileDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline FileDescriptorProto& operator=(const FileDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FileDescriptorProto& operator=(FileDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FileDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FileDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const FileDescriptorProto*>(
+               &_FileDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(FileDescriptorProto& a, FileDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FileDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FileDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FileDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FileDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FileDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FileDescriptorProto& from) {
+    FileDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FileDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FileDescriptorProto";
+  }
+  protected:
+  explicit FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kDependencyFieldNumber = 3,
+    kMessageTypeFieldNumber = 4,
+    kEnumTypeFieldNumber = 5,
+    kServiceFieldNumber = 6,
+    kExtensionFieldNumber = 7,
+    kPublicDependencyFieldNumber = 10,
+    kWeakDependencyFieldNumber = 11,
+    kNameFieldNumber = 1,
+    kPackageFieldNumber = 2,
+    kSyntaxFieldNumber = 12,
+    kOptionsFieldNumber = 8,
+    kSourceCodeInfoFieldNumber = 9,
+  };
+  // repeated string dependency = 3;
+  int dependency_size() const;
+  private:
+  int _internal_dependency_size() const;
+  public:
+  void clear_dependency();
+  const std::string& dependency(int index) const;
+  std::string* mutable_dependency(int index);
+  void set_dependency(int index, const std::string& value);
+  void set_dependency(int index, std::string&& value);
+  void set_dependency(int index, const char* value);
+  void set_dependency(int index, const char* value, size_t size);
+  std::string* add_dependency();
+  void add_dependency(const std::string& value);
+  void add_dependency(std::string&& value);
+  void add_dependency(const char* value);
+  void add_dependency(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& dependency() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_dependency();
+  private:
+  const std::string& _internal_dependency(int index) const;
+  std::string* _internal_add_dependency();
+  public:
+
+  // repeated .google.protobuf.DescriptorProto message_type = 4;
+  int message_type_size() const;
+  private:
+  int _internal_message_type_size() const;
+  public:
+  void clear_message_type();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* mutable_message_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+      mutable_message_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& _internal_message_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _internal_add_message_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& message_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* add_message_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+      message_type() const;
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+  int enum_type_size() const;
+  private:
+  int _internal_enum_type_size() const;
+  public:
+  void clear_enum_type();
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* mutable_enum_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+      mutable_enum_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& _internal_enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _internal_add_enum_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* add_enum_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+      enum_type() const;
+
+  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+  int service_size() const;
+  private:
+  int _internal_service_size() const;
+  public:
+  void clear_service();
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* mutable_service(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >*
+      mutable_service();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& _internal_service(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* _internal_add_service();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& service(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* add_service();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >&
+      service() const;
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+  int extension_size() const;
+  private:
+  int _internal_extension_size() const;
+  public:
+  void clear_extension();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* mutable_extension(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+      mutable_extension();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& _internal_extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _internal_add_extension();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* add_extension();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+      extension() const;
+
+  // repeated int32 public_dependency = 10;
+  int public_dependency_size() const;
+  private:
+  int _internal_public_dependency_size() const;
+  public:
+  void clear_public_dependency();
+  private:
+  int32_t _internal_public_dependency(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_public_dependency() const;
+  void _internal_add_public_dependency(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_public_dependency();
+  public:
+  int32_t public_dependency(int index) const;
+  void set_public_dependency(int index, int32_t value);
+  void add_public_dependency(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      public_dependency() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_public_dependency();
+
+  // repeated int32 weak_dependency = 11;
+  int weak_dependency_size() const;
+  private:
+  int _internal_weak_dependency_size() const;
+  public:
+  void clear_weak_dependency();
+  private:
+  int32_t _internal_weak_dependency(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_weak_dependency() const;
+  void _internal_add_weak_dependency(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_weak_dependency();
+  public:
+  int32_t weak_dependency(int index) const;
+  void set_weak_dependency(int index, int32_t value);
+  void add_weak_dependency(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      weak_dependency() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_weak_dependency();
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string package = 2;
+  bool has_package() const;
+  private:
+  bool _internal_has_package() const;
+  public:
+  void clear_package();
+  const std::string& package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_package();
+  PROTOBUF_NODISCARD std::string* release_package();
+  void set_allocated_package(std::string* package);
+  private:
+  const std::string& _internal_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_package(const std::string& value);
+  std::string* _internal_mutable_package();
+  public:
+
+  // optional string syntax = 12;
+  bool has_syntax() const;
+  private:
+  bool _internal_has_syntax() const;
+  public:
+  void clear_syntax();
+  const std::string& syntax() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_syntax(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_syntax();
+  PROTOBUF_NODISCARD std::string* release_syntax();
+  void set_allocated_syntax(std::string* syntax);
+  private:
+  const std::string& _internal_syntax() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_syntax(const std::string& value);
+  std::string* _internal_mutable_syntax();
+  public:
+
+  // optional .google.protobuf.FileOptions options = 8;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::FileOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::FileOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::FileOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FileOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::FileOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* unsafe_arena_release_options();
+
+  // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+  bool has_source_code_info() const;
+  private:
+  bool _internal_has_source_code_info() const;
+  public:
+  void clear_source_code_info();
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& source_code_info() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* release_source_code_info();
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* mutable_source_code_info();
+  void set_allocated_source_code_info(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& _internal_source_code_info() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* _internal_mutable_source_code_info();
+  public:
+  void unsafe_arena_set_allocated_source_code_info(
+      ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info);
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* unsafe_arena_release_source_code_info();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> dependency_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto > message_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto > enum_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto > service_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto > extension_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > public_dependency_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > weak_dependency_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr package_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr syntax_;
+    ::PROTOBUF_NAMESPACE_ID::FileOptions* options_;
+    ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT DescriptorProto_ExtensionRange final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ExtensionRange) */ {
+ public:
+  inline DescriptorProto_ExtensionRange() : DescriptorProto_ExtensionRange(nullptr) {}
+  ~DescriptorProto_ExtensionRange() override;
+  explicit PROTOBUF_CONSTEXPR DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from);
+  DescriptorProto_ExtensionRange(DescriptorProto_ExtensionRange&& from) noexcept
+    : DescriptorProto_ExtensionRange() {
+    *this = ::std::move(from);
+  }
+
+  inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DescriptorProto_ExtensionRange& operator=(DescriptorProto_ExtensionRange&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DescriptorProto_ExtensionRange& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DescriptorProto_ExtensionRange* internal_default_instance() {
+    return reinterpret_cast<const DescriptorProto_ExtensionRange*>(
+               &_DescriptorProto_ExtensionRange_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(DescriptorProto_ExtensionRange& a, DescriptorProto_ExtensionRange& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DescriptorProto_ExtensionRange* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DescriptorProto_ExtensionRange* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DescriptorProto_ExtensionRange* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DescriptorProto_ExtensionRange>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DescriptorProto_ExtensionRange& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DescriptorProto_ExtensionRange& from) {
+    DescriptorProto_ExtensionRange::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DescriptorProto_ExtensionRange* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto.ExtensionRange";
+  }
+  protected:
+  explicit DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 3,
+    kStartFieldNumber = 1,
+    kEndFieldNumber = 2,
+  };
+  // optional .google.protobuf.ExtensionRangeOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* unsafe_arena_release_options();
+
+  // optional int32 start = 1;
+  bool has_start() const;
+  private:
+  bool _internal_has_start() const;
+  public:
+  void clear_start();
+  int32_t start() const;
+  void set_start(int32_t value);
+  private:
+  int32_t _internal_start() const;
+  void _internal_set_start(int32_t value);
+  public:
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options_;
+    int32_t start_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT DescriptorProto_ReservedRange final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ReservedRange) */ {
+ public:
+  inline DescriptorProto_ReservedRange() : DescriptorProto_ReservedRange(nullptr) {}
+  ~DescriptorProto_ReservedRange() override;
+  explicit PROTOBUF_CONSTEXPR DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from);
+  DescriptorProto_ReservedRange(DescriptorProto_ReservedRange&& from) noexcept
+    : DescriptorProto_ReservedRange() {
+    *this = ::std::move(from);
+  }
+
+  inline DescriptorProto_ReservedRange& operator=(const DescriptorProto_ReservedRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DescriptorProto_ReservedRange& operator=(DescriptorProto_ReservedRange&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DescriptorProto_ReservedRange& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DescriptorProto_ReservedRange* internal_default_instance() {
+    return reinterpret_cast<const DescriptorProto_ReservedRange*>(
+               &_DescriptorProto_ReservedRange_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(DescriptorProto_ReservedRange& a, DescriptorProto_ReservedRange& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DescriptorProto_ReservedRange* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DescriptorProto_ReservedRange* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DescriptorProto_ReservedRange* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DescriptorProto_ReservedRange>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DescriptorProto_ReservedRange& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DescriptorProto_ReservedRange& from) {
+    DescriptorProto_ReservedRange::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DescriptorProto_ReservedRange* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto.ReservedRange";
+  }
+  protected:
+  explicit DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kStartFieldNumber = 1,
+    kEndFieldNumber = 2,
+  };
+  // optional int32 start = 1;
+  bool has_start() const;
+  private:
+  bool _internal_has_start() const;
+  public:
+  void clear_start();
+  int32_t start() const;
+  void set_start(int32_t value);
+  private:
+  int32_t _internal_start() const;
+  void _internal_set_start(int32_t value);
+  public:
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ReservedRange)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    int32_t start_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT DescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto) */ {
+ public:
+  inline DescriptorProto() : DescriptorProto(nullptr) {}
+  ~DescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR DescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DescriptorProto(const DescriptorProto& from);
+  DescriptorProto(DescriptorProto&& from) noexcept
+    : DescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline DescriptorProto& operator=(const DescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DescriptorProto& operator=(DescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const DescriptorProto*>(
+               &_DescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    4;
+
+  friend void swap(DescriptorProto& a, DescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DescriptorProto& from) {
+    DescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto";
+  }
+  protected:
+  explicit DescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef DescriptorProto_ExtensionRange ExtensionRange;
+  typedef DescriptorProto_ReservedRange ReservedRange;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFieldFieldNumber = 2,
+    kNestedTypeFieldNumber = 3,
+    kEnumTypeFieldNumber = 4,
+    kExtensionRangeFieldNumber = 5,
+    kExtensionFieldNumber = 6,
+    kOneofDeclFieldNumber = 8,
+    kReservedRangeFieldNumber = 9,
+    kReservedNameFieldNumber = 10,
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 7,
+  };
+  // repeated .google.protobuf.FieldDescriptorProto field = 2;
+  int field_size() const;
+  private:
+  int _internal_field_size() const;
+  public:
+  void clear_field();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* mutable_field(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+      mutable_field();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& _internal_field(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _internal_add_field();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& field(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* add_field();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+      field() const;
+
+  // repeated .google.protobuf.DescriptorProto nested_type = 3;
+  int nested_type_size() const;
+  private:
+  int _internal_nested_type_size() const;
+  public:
+  void clear_nested_type();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* mutable_nested_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+      mutable_nested_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& _internal_nested_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _internal_add_nested_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& nested_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* add_nested_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+      nested_type() const;
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+  int enum_type_size() const;
+  private:
+  int _internal_enum_type_size() const;
+  public:
+  void clear_enum_type();
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* mutable_enum_type(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+      mutable_enum_type();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& _internal_enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _internal_add_enum_type();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& enum_type(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* add_enum_type();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+      enum_type() const;
+
+  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+  int extension_range_size() const;
+  private:
+  int _internal_extension_range_size() const;
+  public:
+  void clear_extension_range();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >*
+      mutable_extension_range();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& _internal_extension_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* _internal_add_extension_range();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& extension_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* add_extension_range();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >&
+      extension_range() const;
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+  int extension_size() const;
+  private:
+  int _internal_extension_size() const;
+  public:
+  void clear_extension();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* mutable_extension(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+      mutable_extension();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& _internal_extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _internal_add_extension();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& extension(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* add_extension();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+      extension() const;
+
+  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+  int oneof_decl_size() const;
+  private:
+  int _internal_oneof_decl_size() const;
+  public:
+  void clear_oneof_decl();
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* mutable_oneof_decl(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >*
+      mutable_oneof_decl();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& _internal_oneof_decl(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* _internal_add_oneof_decl();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& oneof_decl(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* add_oneof_decl();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >&
+      oneof_decl() const;
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  int reserved_range_size() const;
+  private:
+  int _internal_reserved_range_size() const;
+  public:
+  void clear_reserved_range();
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* mutable_reserved_range(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >*
+      mutable_reserved_range();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& _internal_reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* _internal_add_reserved_range();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* add_reserved_range();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >&
+      reserved_range() const;
+
+  // repeated string reserved_name = 10;
+  int reserved_name_size() const;
+  private:
+  int _internal_reserved_name_size() const;
+  public:
+  void clear_reserved_name();
+  const std::string& reserved_name(int index) const;
+  std::string* mutable_reserved_name(int index);
+  void set_reserved_name(int index, const std::string& value);
+  void set_reserved_name(int index, std::string&& value);
+  void set_reserved_name(int index, const char* value);
+  void set_reserved_name(int index, const char* value, size_t size);
+  std::string* add_reserved_name();
+  void add_reserved_name(const std::string& value);
+  void add_reserved_name(std::string&& value);
+  void add_reserved_name(const char* value);
+  void add_reserved_name(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& reserved_name() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_reserved_name();
+  private:
+  const std::string& _internal_reserved_name(int index) const;
+  std::string* _internal_add_reserved_name();
+  public:
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.MessageOptions options = 7;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::MessageOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::MessageOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::MessageOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::MessageOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::MessageOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto > field_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto > nested_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto > enum_type_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange > extension_range_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto > extension_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto > oneof_decl_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange > reserved_range_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> reserved_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::MessageOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ExtensionRangeOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ExtensionRangeOptions) */ {
+ public:
+  inline ExtensionRangeOptions() : ExtensionRangeOptions(nullptr) {}
+  ~ExtensionRangeOptions() override;
+  explicit PROTOBUF_CONSTEXPR ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ExtensionRangeOptions(const ExtensionRangeOptions& from);
+  ExtensionRangeOptions(ExtensionRangeOptions&& from) noexcept
+    : ExtensionRangeOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline ExtensionRangeOptions& operator=(const ExtensionRangeOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ExtensionRangeOptions& operator=(ExtensionRangeOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ExtensionRangeOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ExtensionRangeOptions* internal_default_instance() {
+    return reinterpret_cast<const ExtensionRangeOptions*>(
+               &_ExtensionRangeOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    5;
+
+  friend void swap(ExtensionRangeOptions& a, ExtensionRangeOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ExtensionRangeOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ExtensionRangeOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ExtensionRangeOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ExtensionRangeOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ExtensionRangeOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ExtensionRangeOptions& from) {
+    ExtensionRangeOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ExtensionRangeOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ExtensionRangeOptions";
+  }
+  protected:
+  explicit ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ExtensionRangeOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ExtensionRangeOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FieldDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldDescriptorProto) */ {
+ public:
+  inline FieldDescriptorProto() : FieldDescriptorProto(nullptr) {}
+  ~FieldDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FieldDescriptorProto(const FieldDescriptorProto& from);
+  FieldDescriptorProto(FieldDescriptorProto&& from) noexcept
+    : FieldDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FieldDescriptorProto& operator=(FieldDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FieldDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FieldDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const FieldDescriptorProto*>(
+               &_FieldDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    6;
+
+  friend void swap(FieldDescriptorProto& a, FieldDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FieldDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FieldDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FieldDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FieldDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FieldDescriptorProto& from) {
+    FieldDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FieldDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FieldDescriptorProto";
+  }
+  protected:
+  explicit FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef FieldDescriptorProto_Type Type;
+  static constexpr Type TYPE_DOUBLE =
+    FieldDescriptorProto_Type_TYPE_DOUBLE;
+  static constexpr Type TYPE_FLOAT =
+    FieldDescriptorProto_Type_TYPE_FLOAT;
+  static constexpr Type TYPE_INT64 =
+    FieldDescriptorProto_Type_TYPE_INT64;
+  static constexpr Type TYPE_UINT64 =
+    FieldDescriptorProto_Type_TYPE_UINT64;
+  static constexpr Type TYPE_INT32 =
+    FieldDescriptorProto_Type_TYPE_INT32;
+  static constexpr Type TYPE_FIXED64 =
+    FieldDescriptorProto_Type_TYPE_FIXED64;
+  static constexpr Type TYPE_FIXED32 =
+    FieldDescriptorProto_Type_TYPE_FIXED32;
+  static constexpr Type TYPE_BOOL =
+    FieldDescriptorProto_Type_TYPE_BOOL;
+  static constexpr Type TYPE_STRING =
+    FieldDescriptorProto_Type_TYPE_STRING;
+  static constexpr Type TYPE_GROUP =
+    FieldDescriptorProto_Type_TYPE_GROUP;
+  static constexpr Type TYPE_MESSAGE =
+    FieldDescriptorProto_Type_TYPE_MESSAGE;
+  static constexpr Type TYPE_BYTES =
+    FieldDescriptorProto_Type_TYPE_BYTES;
+  static constexpr Type TYPE_UINT32 =
+    FieldDescriptorProto_Type_TYPE_UINT32;
+  static constexpr Type TYPE_ENUM =
+    FieldDescriptorProto_Type_TYPE_ENUM;
+  static constexpr Type TYPE_SFIXED32 =
+    FieldDescriptorProto_Type_TYPE_SFIXED32;
+  static constexpr Type TYPE_SFIXED64 =
+    FieldDescriptorProto_Type_TYPE_SFIXED64;
+  static constexpr Type TYPE_SINT32 =
+    FieldDescriptorProto_Type_TYPE_SINT32;
+  static constexpr Type TYPE_SINT64 =
+    FieldDescriptorProto_Type_TYPE_SINT64;
+  static inline bool Type_IsValid(int value) {
+    return FieldDescriptorProto_Type_IsValid(value);
+  }
+  static constexpr Type Type_MIN =
+    FieldDescriptorProto_Type_Type_MIN;
+  static constexpr Type Type_MAX =
+    FieldDescriptorProto_Type_Type_MAX;
+  static constexpr int Type_ARRAYSIZE =
+    FieldDescriptorProto_Type_Type_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Type_descriptor() {
+    return FieldDescriptorProto_Type_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Type_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Type>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Type_Name.");
+    return FieldDescriptorProto_Type_Name(enum_t_value);
+  }
+  static inline bool Type_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Type* value) {
+    return FieldDescriptorProto_Type_Parse(name, value);
+  }
+
+  typedef FieldDescriptorProto_Label Label;
+  static constexpr Label LABEL_OPTIONAL =
+    FieldDescriptorProto_Label_LABEL_OPTIONAL;
+  static constexpr Label LABEL_REQUIRED =
+    FieldDescriptorProto_Label_LABEL_REQUIRED;
+  static constexpr Label LABEL_REPEATED =
+    FieldDescriptorProto_Label_LABEL_REPEATED;
+  static inline bool Label_IsValid(int value) {
+    return FieldDescriptorProto_Label_IsValid(value);
+  }
+  static constexpr Label Label_MIN =
+    FieldDescriptorProto_Label_Label_MIN;
+  static constexpr Label Label_MAX =
+    FieldDescriptorProto_Label_Label_MAX;
+  static constexpr int Label_ARRAYSIZE =
+    FieldDescriptorProto_Label_Label_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Label_descriptor() {
+    return FieldDescriptorProto_Label_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Label_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Label>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Label_Name.");
+    return FieldDescriptorProto_Label_Name(enum_t_value);
+  }
+  static inline bool Label_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Label* value) {
+    return FieldDescriptorProto_Label_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kExtendeeFieldNumber = 2,
+    kTypeNameFieldNumber = 6,
+    kDefaultValueFieldNumber = 7,
+    kJsonNameFieldNumber = 10,
+    kOptionsFieldNumber = 8,
+    kNumberFieldNumber = 3,
+    kOneofIndexFieldNumber = 9,
+    kProto3OptionalFieldNumber = 17,
+    kLabelFieldNumber = 4,
+    kTypeFieldNumber = 5,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string extendee = 2;
+  bool has_extendee() const;
+  private:
+  bool _internal_has_extendee() const;
+  public:
+  void clear_extendee();
+  const std::string& extendee() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_extendee(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_extendee();
+  PROTOBUF_NODISCARD std::string* release_extendee();
+  void set_allocated_extendee(std::string* extendee);
+  private:
+  const std::string& _internal_extendee() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_extendee(const std::string& value);
+  std::string* _internal_mutable_extendee();
+  public:
+
+  // optional string type_name = 6;
+  bool has_type_name() const;
+  private:
+  bool _internal_has_type_name() const;
+  public:
+  void clear_type_name();
+  const std::string& type_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_type_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_type_name();
+  PROTOBUF_NODISCARD std::string* release_type_name();
+  void set_allocated_type_name(std::string* type_name);
+  private:
+  const std::string& _internal_type_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_name(const std::string& value);
+  std::string* _internal_mutable_type_name();
+  public:
+
+  // optional string default_value = 7;
+  bool has_default_value() const;
+  private:
+  bool _internal_has_default_value() const;
+  public:
+  void clear_default_value();
+  const std::string& default_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_default_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_default_value();
+  PROTOBUF_NODISCARD std::string* release_default_value();
+  void set_allocated_default_value(std::string* default_value);
+  private:
+  const std::string& _internal_default_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_default_value(const std::string& value);
+  std::string* _internal_mutable_default_value();
+  public:
+
+  // optional string json_name = 10;
+  bool has_json_name() const;
+  private:
+  bool _internal_has_json_name() const;
+  public:
+  void clear_json_name();
+  const std::string& json_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_json_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_json_name();
+  PROTOBUF_NODISCARD std::string* release_json_name();
+  void set_allocated_json_name(std::string* json_name);
+  private:
+  const std::string& _internal_json_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_json_name(const std::string& value);
+  std::string* _internal_mutable_json_name();
+  public:
+
+  // optional .google.protobuf.FieldOptions options = 8;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::FieldOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::FieldOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::FieldOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::FieldOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::FieldOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* unsafe_arena_release_options();
+
+  // optional int32 number = 3;
+  bool has_number() const;
+  private:
+  bool _internal_has_number() const;
+  public:
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // optional int32 oneof_index = 9;
+  bool has_oneof_index() const;
+  private:
+  bool _internal_has_oneof_index() const;
+  public:
+  void clear_oneof_index();
+  int32_t oneof_index() const;
+  void set_oneof_index(int32_t value);
+  private:
+  int32_t _internal_oneof_index() const;
+  void _internal_set_oneof_index(int32_t value);
+  public:
+
+  // optional bool proto3_optional = 17;
+  bool has_proto3_optional() const;
+  private:
+  bool _internal_has_proto3_optional() const;
+  public:
+  void clear_proto3_optional();
+  bool proto3_optional() const;
+  void set_proto3_optional(bool value);
+  private:
+  bool _internal_proto3_optional() const;
+  void _internal_set_proto3_optional(bool value);
+  public:
+
+  // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+  bool has_label() const;
+  private:
+  bool _internal_has_label() const;
+  public:
+  void clear_label();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label label() const;
+  void set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label _internal_label() const;
+  void _internal_set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value);
+  public:
+
+  // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+  bool has_type() const;
+  private:
+  bool _internal_has_type() const;
+  public:
+  void clear_type();
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type type() const;
+  void set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type _internal_type() const;
+  void _internal_set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr extendee_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr default_value_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr json_name_;
+    ::PROTOBUF_NAMESPACE_ID::FieldOptions* options_;
+    int32_t number_;
+    int32_t oneof_index_;
+    bool proto3_optional_;
+    int label_;
+    int type_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT OneofDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofDescriptorProto) */ {
+ public:
+  inline OneofDescriptorProto() : OneofDescriptorProto(nullptr) {}
+  ~OneofDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  OneofDescriptorProto(const OneofDescriptorProto& from);
+  OneofDescriptorProto(OneofDescriptorProto&& from) noexcept
+    : OneofDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline OneofDescriptorProto& operator=(const OneofDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline OneofDescriptorProto& operator=(OneofDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const OneofDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const OneofDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const OneofDescriptorProto*>(
+               &_OneofDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    7;
+
+  friend void swap(OneofDescriptorProto& a, OneofDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(OneofDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(OneofDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  OneofDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<OneofDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const OneofDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const OneofDescriptorProto& from) {
+    OneofDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(OneofDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.OneofDescriptorProto";
+  }
+  protected:
+  explicit OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 2,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.OneofOptions options = 2;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::OneofOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::OneofOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::OneofOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::OneofOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::OneofOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::OneofOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumDescriptorProto_EnumReservedRange final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumDescriptorProto.EnumReservedRange) */ {
+ public:
+  inline EnumDescriptorProto_EnumReservedRange() : EnumDescriptorProto_EnumReservedRange(nullptr) {}
+  ~EnumDescriptorProto_EnumReservedRange() override;
+  explicit PROTOBUF_CONSTEXPR EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumDescriptorProto_EnumReservedRange(const EnumDescriptorProto_EnumReservedRange& from);
+  EnumDescriptorProto_EnumReservedRange(EnumDescriptorProto_EnumReservedRange&& from) noexcept
+    : EnumDescriptorProto_EnumReservedRange() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumDescriptorProto_EnumReservedRange& operator=(const EnumDescriptorProto_EnumReservedRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumDescriptorProto_EnumReservedRange& operator=(EnumDescriptorProto_EnumReservedRange&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumDescriptorProto_EnumReservedRange& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumDescriptorProto_EnumReservedRange* internal_default_instance() {
+    return reinterpret_cast<const EnumDescriptorProto_EnumReservedRange*>(
+               &_EnumDescriptorProto_EnumReservedRange_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    8;
+
+  friend void swap(EnumDescriptorProto_EnumReservedRange& a, EnumDescriptorProto_EnumReservedRange& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumDescriptorProto_EnumReservedRange* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumDescriptorProto_EnumReservedRange* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumDescriptorProto_EnumReservedRange* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumDescriptorProto_EnumReservedRange>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumDescriptorProto_EnumReservedRange& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumDescriptorProto_EnumReservedRange& from) {
+    EnumDescriptorProto_EnumReservedRange::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumDescriptorProto_EnumReservedRange* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumDescriptorProto.EnumReservedRange";
+  }
+  protected:
+  explicit EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kStartFieldNumber = 1,
+    kEndFieldNumber = 2,
+  };
+  // optional int32 start = 1;
+  bool has_start() const;
+  private:
+  bool _internal_has_start() const;
+  public:
+  void clear_start();
+  int32_t start() const;
+  void set_start(int32_t value);
+  private:
+  int32_t _internal_start() const;
+  void _internal_set_start(int32_t value);
+  public:
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    int32_t start_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumDescriptorProto) */ {
+ public:
+  inline EnumDescriptorProto() : EnumDescriptorProto(nullptr) {}
+  ~EnumDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumDescriptorProto(const EnumDescriptorProto& from);
+  EnumDescriptorProto(EnumDescriptorProto&& from) noexcept
+    : EnumDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumDescriptorProto& operator=(EnumDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const EnumDescriptorProto*>(
+               &_EnumDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    9;
+
+  friend void swap(EnumDescriptorProto& a, EnumDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumDescriptorProto& from) {
+    EnumDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumDescriptorProto";
+  }
+  protected:
+  explicit EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef EnumDescriptorProto_EnumReservedRange EnumReservedRange;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 2,
+    kReservedRangeFieldNumber = 4,
+    kReservedNameFieldNumber = 5,
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 3,
+  };
+  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+  int value_size() const;
+  private:
+  int _internal_value_size() const;
+  public:
+  void clear_value();
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* mutable_value(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >*
+      mutable_value();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& _internal_value(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* _internal_add_value();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& value(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* add_value();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >&
+      value() const;
+
+  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+  int reserved_range_size() const;
+  private:
+  int _internal_reserved_range_size() const;
+  public:
+  void clear_reserved_range();
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* mutable_reserved_range(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >*
+      mutable_reserved_range();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& _internal_reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* _internal_add_reserved_range();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& reserved_range(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* add_reserved_range();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >&
+      reserved_range() const;
+
+  // repeated string reserved_name = 5;
+  int reserved_name_size() const;
+  private:
+  int _internal_reserved_name_size() const;
+  public:
+  void clear_reserved_name();
+  const std::string& reserved_name(int index) const;
+  std::string* mutable_reserved_name(int index);
+  void set_reserved_name(int index, const std::string& value);
+  void set_reserved_name(int index, std::string&& value);
+  void set_reserved_name(int index, const char* value);
+  void set_reserved_name(int index, const char* value, size_t size);
+  std::string* add_reserved_name();
+  void add_reserved_name(const std::string& value);
+  void add_reserved_name(std::string&& value);
+  void add_reserved_name(const char* value);
+  void add_reserved_name(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& reserved_name() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_reserved_name();
+  private:
+  const std::string& _internal_reserved_name(int index) const;
+  std::string* _internal_add_reserved_name();
+  public:
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.EnumOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::EnumOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::EnumOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::EnumOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto > value_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange > reserved_range_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> reserved_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::EnumOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumValueDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueDescriptorProto) */ {
+ public:
+  inline EnumValueDescriptorProto() : EnumValueDescriptorProto(nullptr) {}
+  ~EnumValueDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumValueDescriptorProto(const EnumValueDescriptorProto& from);
+  EnumValueDescriptorProto(EnumValueDescriptorProto&& from) noexcept
+    : EnumValueDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumValueDescriptorProto& operator=(EnumValueDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumValueDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumValueDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const EnumValueDescriptorProto*>(
+               &_EnumValueDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    10;
+
+  friend void swap(EnumValueDescriptorProto& a, EnumValueDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumValueDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValueDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumValueDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumValueDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumValueDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumValueDescriptorProto& from) {
+    EnumValueDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumValueDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValueDescriptorProto";
+  }
+  protected:
+  explicit EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 3,
+    kNumberFieldNumber = 2,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.EnumValueOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* unsafe_arena_release_options();
+
+  // optional int32 number = 2;
+  bool has_number() const;
+  private:
+  bool _internal_has_number() const;
+  public:
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options_;
+    int32_t number_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ServiceDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceDescriptorProto) */ {
+ public:
+  inline ServiceDescriptorProto() : ServiceDescriptorProto(nullptr) {}
+  ~ServiceDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ServiceDescriptorProto(const ServiceDescriptorProto& from);
+  ServiceDescriptorProto(ServiceDescriptorProto&& from) noexcept
+    : ServiceDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ServiceDescriptorProto& operator=(ServiceDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ServiceDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ServiceDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const ServiceDescriptorProto*>(
+               &_ServiceDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    11;
+
+  friend void swap(ServiceDescriptorProto& a, ServiceDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ServiceDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ServiceDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ServiceDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ServiceDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ServiceDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ServiceDescriptorProto& from) {
+    ServiceDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ServiceDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ServiceDescriptorProto";
+  }
+  protected:
+  explicit ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kMethodFieldNumber = 2,
+    kNameFieldNumber = 1,
+    kOptionsFieldNumber = 3,
+  };
+  // repeated .google.protobuf.MethodDescriptorProto method = 2;
+  int method_size() const;
+  private:
+  int _internal_method_size() const;
+  public:
+  void clear_method();
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* mutable_method(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >*
+      mutable_method();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& _internal_method(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* _internal_add_method();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& method(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* add_method();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >&
+      method() const;
+
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional .google.protobuf.ServiceOptions options = 3;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::ServiceOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::ServiceOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::ServiceOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* unsafe_arena_release_options();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto > method_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::ServiceOptions* options_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT MethodDescriptorProto final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodDescriptorProto) */ {
+ public:
+  inline MethodDescriptorProto() : MethodDescriptorProto(nullptr) {}
+  ~MethodDescriptorProto() override;
+  explicit PROTOBUF_CONSTEXPR MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MethodDescriptorProto(const MethodDescriptorProto& from);
+  MethodDescriptorProto(MethodDescriptorProto&& from) noexcept
+    : MethodDescriptorProto() {
+    *this = ::std::move(from);
+  }
+
+  inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MethodDescriptorProto& operator=(MethodDescriptorProto&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MethodDescriptorProto& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MethodDescriptorProto* internal_default_instance() {
+    return reinterpret_cast<const MethodDescriptorProto*>(
+               &_MethodDescriptorProto_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    12;
+
+  friend void swap(MethodDescriptorProto& a, MethodDescriptorProto& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MethodDescriptorProto* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MethodDescriptorProto* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MethodDescriptorProto* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MethodDescriptorProto>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MethodDescriptorProto& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MethodDescriptorProto& from) {
+    MethodDescriptorProto::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MethodDescriptorProto* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.MethodDescriptorProto";
+  }
+  protected:
+  explicit MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kInputTypeFieldNumber = 2,
+    kOutputTypeFieldNumber = 3,
+    kOptionsFieldNumber = 4,
+    kClientStreamingFieldNumber = 5,
+    kServerStreamingFieldNumber = 6,
+  };
+  // optional string name = 1;
+  bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // optional string input_type = 2;
+  bool has_input_type() const;
+  private:
+  bool _internal_has_input_type() const;
+  public:
+  void clear_input_type();
+  const std::string& input_type() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_input_type(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_input_type();
+  PROTOBUF_NODISCARD std::string* release_input_type();
+  void set_allocated_input_type(std::string* input_type);
+  private:
+  const std::string& _internal_input_type() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_input_type(const std::string& value);
+  std::string* _internal_mutable_input_type();
+  public:
+
+  // optional string output_type = 3;
+  bool has_output_type() const;
+  private:
+  bool _internal_has_output_type() const;
+  public:
+  void clear_output_type();
+  const std::string& output_type() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_output_type(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_output_type();
+  PROTOBUF_NODISCARD std::string* release_output_type();
+  void set_allocated_output_type(std::string* output_type);
+  private:
+  const std::string& _internal_output_type() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_output_type(const std::string& value);
+  std::string* _internal_mutable_output_type();
+  public:
+
+  // optional .google.protobuf.MethodOptions options = 4;
+  bool has_options() const;
+  private:
+  bool _internal_has_options() const;
+  public:
+  void clear_options();
+  const ::PROTOBUF_NAMESPACE_ID::MethodOptions& options() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::MethodOptions* release_options();
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* mutable_options();
+  void set_allocated_options(::PROTOBUF_NAMESPACE_ID::MethodOptions* options);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::MethodOptions& _internal_options() const;
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* _internal_mutable_options();
+  public:
+  void unsafe_arena_set_allocated_options(
+      ::PROTOBUF_NAMESPACE_ID::MethodOptions* options);
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* unsafe_arena_release_options();
+
+  // optional bool client_streaming = 5 [default = false];
+  bool has_client_streaming() const;
+  private:
+  bool _internal_has_client_streaming() const;
+  public:
+  void clear_client_streaming();
+  bool client_streaming() const;
+  void set_client_streaming(bool value);
+  private:
+  bool _internal_client_streaming() const;
+  void _internal_set_client_streaming(bool value);
+  public:
+
+  // optional bool server_streaming = 6 [default = false];
+  bool has_server_streaming() const;
+  private:
+  bool _internal_has_server_streaming() const;
+  public:
+  void clear_server_streaming();
+  bool server_streaming() const;
+  void set_server_streaming(bool value);
+  private:
+  bool _internal_server_streaming() const;
+  void _internal_set_server_streaming(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr input_type_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr output_type_;
+    ::PROTOBUF_NAMESPACE_ID::MethodOptions* options_;
+    bool client_streaming_;
+    bool server_streaming_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FileOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileOptions) */ {
+ public:
+  inline FileOptions() : FileOptions(nullptr) {}
+  ~FileOptions() override;
+  explicit PROTOBUF_CONSTEXPR FileOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FileOptions(const FileOptions& from);
+  FileOptions(FileOptions&& from) noexcept
+    : FileOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline FileOptions& operator=(const FileOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FileOptions& operator=(FileOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FileOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FileOptions* internal_default_instance() {
+    return reinterpret_cast<const FileOptions*>(
+               &_FileOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    13;
+
+  friend void swap(FileOptions& a, FileOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FileOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FileOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FileOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FileOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FileOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FileOptions& from) {
+    FileOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FileOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FileOptions";
+  }
+  protected:
+  explicit FileOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef FileOptions_OptimizeMode OptimizeMode;
+  static constexpr OptimizeMode SPEED =
+    FileOptions_OptimizeMode_SPEED;
+  static constexpr OptimizeMode CODE_SIZE =
+    FileOptions_OptimizeMode_CODE_SIZE;
+  static constexpr OptimizeMode LITE_RUNTIME =
+    FileOptions_OptimizeMode_LITE_RUNTIME;
+  static inline bool OptimizeMode_IsValid(int value) {
+    return FileOptions_OptimizeMode_IsValid(value);
+  }
+  static constexpr OptimizeMode OptimizeMode_MIN =
+    FileOptions_OptimizeMode_OptimizeMode_MIN;
+  static constexpr OptimizeMode OptimizeMode_MAX =
+    FileOptions_OptimizeMode_OptimizeMode_MAX;
+  static constexpr int OptimizeMode_ARRAYSIZE =
+    FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  OptimizeMode_descriptor() {
+    return FileOptions_OptimizeMode_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& OptimizeMode_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, OptimizeMode>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function OptimizeMode_Name.");
+    return FileOptions_OptimizeMode_Name(enum_t_value);
+  }
+  static inline bool OptimizeMode_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      OptimizeMode* value) {
+    return FileOptions_OptimizeMode_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kJavaPackageFieldNumber = 1,
+    kJavaOuterClassnameFieldNumber = 8,
+    kGoPackageFieldNumber = 11,
+    kObjcClassPrefixFieldNumber = 36,
+    kCsharpNamespaceFieldNumber = 37,
+    kSwiftPrefixFieldNumber = 39,
+    kPhpClassPrefixFieldNumber = 40,
+    kPhpNamespaceFieldNumber = 41,
+    kPhpMetadataNamespaceFieldNumber = 44,
+    kRubyPackageFieldNumber = 45,
+    kJavaMultipleFilesFieldNumber = 10,
+    kJavaGenerateEqualsAndHashFieldNumber = 20,
+    kJavaStringCheckUtf8FieldNumber = 27,
+    kCcGenericServicesFieldNumber = 16,
+    kJavaGenericServicesFieldNumber = 17,
+    kPyGenericServicesFieldNumber = 18,
+    kPhpGenericServicesFieldNumber = 42,
+    kDeprecatedFieldNumber = 23,
+    kOptimizeForFieldNumber = 9,
+    kCcEnableArenasFieldNumber = 31,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional string java_package = 1;
+  bool has_java_package() const;
+  private:
+  bool _internal_has_java_package() const;
+  public:
+  void clear_java_package();
+  const std::string& java_package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_java_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_java_package();
+  PROTOBUF_NODISCARD std::string* release_java_package();
+  void set_allocated_java_package(std::string* java_package);
+  private:
+  const std::string& _internal_java_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_java_package(const std::string& value);
+  std::string* _internal_mutable_java_package();
+  public:
+
+  // optional string java_outer_classname = 8;
+  bool has_java_outer_classname() const;
+  private:
+  bool _internal_has_java_outer_classname() const;
+  public:
+  void clear_java_outer_classname();
+  const std::string& java_outer_classname() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_java_outer_classname(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_java_outer_classname();
+  PROTOBUF_NODISCARD std::string* release_java_outer_classname();
+  void set_allocated_java_outer_classname(std::string* java_outer_classname);
+  private:
+  const std::string& _internal_java_outer_classname() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_java_outer_classname(const std::string& value);
+  std::string* _internal_mutable_java_outer_classname();
+  public:
+
+  // optional string go_package = 11;
+  bool has_go_package() const;
+  private:
+  bool _internal_has_go_package() const;
+  public:
+  void clear_go_package();
+  const std::string& go_package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_go_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_go_package();
+  PROTOBUF_NODISCARD std::string* release_go_package();
+  void set_allocated_go_package(std::string* go_package);
+  private:
+  const std::string& _internal_go_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_go_package(const std::string& value);
+  std::string* _internal_mutable_go_package();
+  public:
+
+  // optional string objc_class_prefix = 36;
+  bool has_objc_class_prefix() const;
+  private:
+  bool _internal_has_objc_class_prefix() const;
+  public:
+  void clear_objc_class_prefix();
+  const std::string& objc_class_prefix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_objc_class_prefix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_objc_class_prefix();
+  PROTOBUF_NODISCARD std::string* release_objc_class_prefix();
+  void set_allocated_objc_class_prefix(std::string* objc_class_prefix);
+  private:
+  const std::string& _internal_objc_class_prefix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_objc_class_prefix(const std::string& value);
+  std::string* _internal_mutable_objc_class_prefix();
+  public:
+
+  // optional string csharp_namespace = 37;
+  bool has_csharp_namespace() const;
+  private:
+  bool _internal_has_csharp_namespace() const;
+  public:
+  void clear_csharp_namespace();
+  const std::string& csharp_namespace() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_csharp_namespace(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_csharp_namespace();
+  PROTOBUF_NODISCARD std::string* release_csharp_namespace();
+  void set_allocated_csharp_namespace(std::string* csharp_namespace);
+  private:
+  const std::string& _internal_csharp_namespace() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_csharp_namespace(const std::string& value);
+  std::string* _internal_mutable_csharp_namespace();
+  public:
+
+  // optional string swift_prefix = 39;
+  bool has_swift_prefix() const;
+  private:
+  bool _internal_has_swift_prefix() const;
+  public:
+  void clear_swift_prefix();
+  const std::string& swift_prefix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_swift_prefix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_swift_prefix();
+  PROTOBUF_NODISCARD std::string* release_swift_prefix();
+  void set_allocated_swift_prefix(std::string* swift_prefix);
+  private:
+  const std::string& _internal_swift_prefix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_swift_prefix(const std::string& value);
+  std::string* _internal_mutable_swift_prefix();
+  public:
+
+  // optional string php_class_prefix = 40;
+  bool has_php_class_prefix() const;
+  private:
+  bool _internal_has_php_class_prefix() const;
+  public:
+  void clear_php_class_prefix();
+  const std::string& php_class_prefix() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_php_class_prefix(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_php_class_prefix();
+  PROTOBUF_NODISCARD std::string* release_php_class_prefix();
+  void set_allocated_php_class_prefix(std::string* php_class_prefix);
+  private:
+  const std::string& _internal_php_class_prefix() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_php_class_prefix(const std::string& value);
+  std::string* _internal_mutable_php_class_prefix();
+  public:
+
+  // optional string php_namespace = 41;
+  bool has_php_namespace() const;
+  private:
+  bool _internal_has_php_namespace() const;
+  public:
+  void clear_php_namespace();
+  const std::string& php_namespace() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_php_namespace(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_php_namespace();
+  PROTOBUF_NODISCARD std::string* release_php_namespace();
+  void set_allocated_php_namespace(std::string* php_namespace);
+  private:
+  const std::string& _internal_php_namespace() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_php_namespace(const std::string& value);
+  std::string* _internal_mutable_php_namespace();
+  public:
+
+  // optional string php_metadata_namespace = 44;
+  bool has_php_metadata_namespace() const;
+  private:
+  bool _internal_has_php_metadata_namespace() const;
+  public:
+  void clear_php_metadata_namespace();
+  const std::string& php_metadata_namespace() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_php_metadata_namespace(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_php_metadata_namespace();
+  PROTOBUF_NODISCARD std::string* release_php_metadata_namespace();
+  void set_allocated_php_metadata_namespace(std::string* php_metadata_namespace);
+  private:
+  const std::string& _internal_php_metadata_namespace() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_php_metadata_namespace(const std::string& value);
+  std::string* _internal_mutable_php_metadata_namespace();
+  public:
+
+  // optional string ruby_package = 45;
+  bool has_ruby_package() const;
+  private:
+  bool _internal_has_ruby_package() const;
+  public:
+  void clear_ruby_package();
+  const std::string& ruby_package() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_ruby_package(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_ruby_package();
+  PROTOBUF_NODISCARD std::string* release_ruby_package();
+  void set_allocated_ruby_package(std::string* ruby_package);
+  private:
+  const std::string& _internal_ruby_package() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_ruby_package(const std::string& value);
+  std::string* _internal_mutable_ruby_package();
+  public:
+
+  // optional bool java_multiple_files = 10 [default = false];
+  bool has_java_multiple_files() const;
+  private:
+  bool _internal_has_java_multiple_files() const;
+  public:
+  void clear_java_multiple_files();
+  bool java_multiple_files() const;
+  void set_java_multiple_files(bool value);
+  private:
+  bool _internal_java_multiple_files() const;
+  void _internal_set_java_multiple_files(bool value);
+  public:
+
+  // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+  PROTOBUF_DEPRECATED bool has_java_generate_equals_and_hash() const;
+  private:
+  bool _internal_has_java_generate_equals_and_hash() const;
+  public:
+  PROTOBUF_DEPRECATED void clear_java_generate_equals_and_hash();
+  PROTOBUF_DEPRECATED bool java_generate_equals_and_hash() const;
+  PROTOBUF_DEPRECATED void set_java_generate_equals_and_hash(bool value);
+  private:
+  bool _internal_java_generate_equals_and_hash() const;
+  void _internal_set_java_generate_equals_and_hash(bool value);
+  public:
+
+  // optional bool java_string_check_utf8 = 27 [default = false];
+  bool has_java_string_check_utf8() const;
+  private:
+  bool _internal_has_java_string_check_utf8() const;
+  public:
+  void clear_java_string_check_utf8();
+  bool java_string_check_utf8() const;
+  void set_java_string_check_utf8(bool value);
+  private:
+  bool _internal_java_string_check_utf8() const;
+  void _internal_set_java_string_check_utf8(bool value);
+  public:
+
+  // optional bool cc_generic_services = 16 [default = false];
+  bool has_cc_generic_services() const;
+  private:
+  bool _internal_has_cc_generic_services() const;
+  public:
+  void clear_cc_generic_services();
+  bool cc_generic_services() const;
+  void set_cc_generic_services(bool value);
+  private:
+  bool _internal_cc_generic_services() const;
+  void _internal_set_cc_generic_services(bool value);
+  public:
+
+  // optional bool java_generic_services = 17 [default = false];
+  bool has_java_generic_services() const;
+  private:
+  bool _internal_has_java_generic_services() const;
+  public:
+  void clear_java_generic_services();
+  bool java_generic_services() const;
+  void set_java_generic_services(bool value);
+  private:
+  bool _internal_java_generic_services() const;
+  void _internal_set_java_generic_services(bool value);
+  public:
+
+  // optional bool py_generic_services = 18 [default = false];
+  bool has_py_generic_services() const;
+  private:
+  bool _internal_has_py_generic_services() const;
+  public:
+  void clear_py_generic_services();
+  bool py_generic_services() const;
+  void set_py_generic_services(bool value);
+  private:
+  bool _internal_py_generic_services() const;
+  void _internal_set_py_generic_services(bool value);
+  public:
+
+  // optional bool php_generic_services = 42 [default = false];
+  bool has_php_generic_services() const;
+  private:
+  bool _internal_has_php_generic_services() const;
+  public:
+  void clear_php_generic_services();
+  bool php_generic_services() const;
+  void set_php_generic_services(bool value);
+  private:
+  bool _internal_php_generic_services() const;
+  void _internal_set_php_generic_services(bool value);
+  public:
+
+  // optional bool deprecated = 23 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+  bool has_optimize_for() const;
+  private:
+  bool _internal_has_optimize_for() const;
+  public:
+  void clear_optimize_for();
+  ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode optimize_for() const;
+  void set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode _internal_optimize_for() const;
+  void _internal_set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value);
+  public:
+
+  // optional bool cc_enable_arenas = 31 [default = true];
+  bool has_cc_enable_arenas() const;
+  private:
+  bool _internal_has_cc_enable_arenas() const;
+  public:
+  void clear_cc_enable_arenas();
+  bool cc_enable_arenas() const;
+  void set_cc_enable_arenas(bool value);
+  private:
+  bool _internal_cc_enable_arenas() const;
+  void _internal_set_cc_enable_arenas(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FileOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr java_package_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr java_outer_classname_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr go_package_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr objc_class_prefix_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr csharp_namespace_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr swift_prefix_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr php_class_prefix_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr php_namespace_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr php_metadata_namespace_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr ruby_package_;
+    bool java_multiple_files_;
+    bool java_generate_equals_and_hash_;
+    bool java_string_check_utf8_;
+    bool cc_generic_services_;
+    bool java_generic_services_;
+    bool py_generic_services_;
+    bool php_generic_services_;
+    bool deprecated_;
+    int optimize_for_;
+    bool cc_enable_arenas_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT MessageOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MessageOptions) */ {
+ public:
+  inline MessageOptions() : MessageOptions(nullptr) {}
+  ~MessageOptions() override;
+  explicit PROTOBUF_CONSTEXPR MessageOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MessageOptions(const MessageOptions& from);
+  MessageOptions(MessageOptions&& from) noexcept
+    : MessageOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline MessageOptions& operator=(const MessageOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MessageOptions& operator=(MessageOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MessageOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MessageOptions* internal_default_instance() {
+    return reinterpret_cast<const MessageOptions*>(
+               &_MessageOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    14;
+
+  friend void swap(MessageOptions& a, MessageOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MessageOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MessageOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MessageOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MessageOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MessageOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MessageOptions& from) {
+    MessageOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MessageOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.MessageOptions";
+  }
+  protected:
+  explicit MessageOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kMessageSetWireFormatFieldNumber = 1,
+    kNoStandardDescriptorAccessorFieldNumber = 2,
+    kDeprecatedFieldNumber = 3,
+    kMapEntryFieldNumber = 7,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool message_set_wire_format = 1 [default = false];
+  bool has_message_set_wire_format() const;
+  private:
+  bool _internal_has_message_set_wire_format() const;
+  public:
+  void clear_message_set_wire_format();
+  bool message_set_wire_format() const;
+  void set_message_set_wire_format(bool value);
+  private:
+  bool _internal_message_set_wire_format() const;
+  void _internal_set_message_set_wire_format(bool value);
+  public:
+
+  // optional bool no_standard_descriptor_accessor = 2 [default = false];
+  bool has_no_standard_descriptor_accessor() const;
+  private:
+  bool _internal_has_no_standard_descriptor_accessor() const;
+  public:
+  void clear_no_standard_descriptor_accessor();
+  bool no_standard_descriptor_accessor() const;
+  void set_no_standard_descriptor_accessor(bool value);
+  private:
+  bool _internal_no_standard_descriptor_accessor() const;
+  void _internal_set_no_standard_descriptor_accessor(bool value);
+  public:
+
+  // optional bool deprecated = 3 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional bool map_entry = 7;
+  bool has_map_entry() const;
+  private:
+  bool _internal_has_map_entry() const;
+  public:
+  void clear_map_entry();
+  bool map_entry() const;
+  void set_map_entry(bool value);
+  private:
+  bool _internal_map_entry() const;
+  void _internal_set_map_entry(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MessageOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool message_set_wire_format_;
+    bool no_standard_descriptor_accessor_;
+    bool deprecated_;
+    bool map_entry_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FieldOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldOptions) */ {
+ public:
+  inline FieldOptions() : FieldOptions(nullptr) {}
+  ~FieldOptions() override;
+  explicit PROTOBUF_CONSTEXPR FieldOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FieldOptions(const FieldOptions& from);
+  FieldOptions(FieldOptions&& from) noexcept
+    : FieldOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline FieldOptions& operator=(const FieldOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FieldOptions& operator=(FieldOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FieldOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FieldOptions* internal_default_instance() {
+    return reinterpret_cast<const FieldOptions*>(
+               &_FieldOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    15;
+
+  friend void swap(FieldOptions& a, FieldOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FieldOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FieldOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FieldOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FieldOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FieldOptions& from) {
+    FieldOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FieldOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FieldOptions";
+  }
+  protected:
+  explicit FieldOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef FieldOptions_CType CType;
+  static constexpr CType STRING =
+    FieldOptions_CType_STRING;
+  static constexpr CType CORD =
+    FieldOptions_CType_CORD;
+  static constexpr CType STRING_PIECE =
+    FieldOptions_CType_STRING_PIECE;
+  static inline bool CType_IsValid(int value) {
+    return FieldOptions_CType_IsValid(value);
+  }
+  static constexpr CType CType_MIN =
+    FieldOptions_CType_CType_MIN;
+  static constexpr CType CType_MAX =
+    FieldOptions_CType_CType_MAX;
+  static constexpr int CType_ARRAYSIZE =
+    FieldOptions_CType_CType_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  CType_descriptor() {
+    return FieldOptions_CType_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& CType_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, CType>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function CType_Name.");
+    return FieldOptions_CType_Name(enum_t_value);
+  }
+  static inline bool CType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      CType* value) {
+    return FieldOptions_CType_Parse(name, value);
+  }
+
+  typedef FieldOptions_JSType JSType;
+  static constexpr JSType JS_NORMAL =
+    FieldOptions_JSType_JS_NORMAL;
+  static constexpr JSType JS_STRING =
+    FieldOptions_JSType_JS_STRING;
+  static constexpr JSType JS_NUMBER =
+    FieldOptions_JSType_JS_NUMBER;
+  static inline bool JSType_IsValid(int value) {
+    return FieldOptions_JSType_IsValid(value);
+  }
+  static constexpr JSType JSType_MIN =
+    FieldOptions_JSType_JSType_MIN;
+  static constexpr JSType JSType_MAX =
+    FieldOptions_JSType_JSType_MAX;
+  static constexpr int JSType_ARRAYSIZE =
+    FieldOptions_JSType_JSType_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  JSType_descriptor() {
+    return FieldOptions_JSType_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& JSType_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, JSType>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function JSType_Name.");
+    return FieldOptions_JSType_Name(enum_t_value);
+  }
+  static inline bool JSType_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      JSType* value) {
+    return FieldOptions_JSType_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kCtypeFieldNumber = 1,
+    kJstypeFieldNumber = 6,
+    kPackedFieldNumber = 2,
+    kLazyFieldNumber = 5,
+    kUnverifiedLazyFieldNumber = 15,
+    kDeprecatedFieldNumber = 3,
+    kWeakFieldNumber = 10,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+  bool has_ctype() const;
+  private:
+  bool _internal_has_ctype() const;
+  public:
+  void clear_ctype();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType ctype() const;
+  void set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType _internal_ctype() const;
+  void _internal_set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value);
+  public:
+
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  bool has_jstype() const;
+  private:
+  bool _internal_has_jstype() const;
+  public:
+  void clear_jstype();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType jstype() const;
+  void set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType _internal_jstype() const;
+  void _internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
+  public:
+
+  // optional bool packed = 2;
+  bool has_packed() const;
+  private:
+  bool _internal_has_packed() const;
+  public:
+  void clear_packed();
+  bool packed() const;
+  void set_packed(bool value);
+  private:
+  bool _internal_packed() const;
+  void _internal_set_packed(bool value);
+  public:
+
+  // optional bool lazy = 5 [default = false];
+  bool has_lazy() const;
+  private:
+  bool _internal_has_lazy() const;
+  public:
+  void clear_lazy();
+  bool lazy() const;
+  void set_lazy(bool value);
+  private:
+  bool _internal_lazy() const;
+  void _internal_set_lazy(bool value);
+  public:
+
+  // optional bool unverified_lazy = 15 [default = false];
+  bool has_unverified_lazy() const;
+  private:
+  bool _internal_has_unverified_lazy() const;
+  public:
+  void clear_unverified_lazy();
+  bool unverified_lazy() const;
+  void set_unverified_lazy(bool value);
+  private:
+  bool _internal_unverified_lazy() const;
+  void _internal_set_unverified_lazy(bool value);
+  public:
+
+  // optional bool deprecated = 3 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional bool weak = 10 [default = false];
+  bool has_weak() const;
+  private:
+  bool _internal_has_weak() const;
+  public:
+  void clear_weak();
+  bool weak() const;
+  void set_weak(bool value);
+  private:
+  bool _internal_weak() const;
+  void _internal_set_weak(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          FieldOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    int ctype_;
+    int jstype_;
+    bool packed_;
+    bool lazy_;
+    bool unverified_lazy_;
+    bool deprecated_;
+    bool weak_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT OneofOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofOptions) */ {
+ public:
+  inline OneofOptions() : OneofOptions(nullptr) {}
+  ~OneofOptions() override;
+  explicit PROTOBUF_CONSTEXPR OneofOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  OneofOptions(const OneofOptions& from);
+  OneofOptions(OneofOptions&& from) noexcept
+    : OneofOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline OneofOptions& operator=(const OneofOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline OneofOptions& operator=(OneofOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const OneofOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const OneofOptions* internal_default_instance() {
+    return reinterpret_cast<const OneofOptions*>(
+               &_OneofOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    16;
+
+  friend void swap(OneofOptions& a, OneofOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(OneofOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(OneofOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  OneofOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<OneofOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const OneofOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const OneofOptions& from) {
+    OneofOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(OneofOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.OneofOptions";
+  }
+  protected:
+  explicit OneofOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          OneofOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.OneofOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumOptions) */ {
+ public:
+  inline EnumOptions() : EnumOptions(nullptr) {}
+  ~EnumOptions() override;
+  explicit PROTOBUF_CONSTEXPR EnumOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumOptions(const EnumOptions& from);
+  EnumOptions(EnumOptions&& from) noexcept
+    : EnumOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumOptions& operator=(const EnumOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumOptions& operator=(EnumOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumOptions* internal_default_instance() {
+    return reinterpret_cast<const EnumOptions*>(
+               &_EnumOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    17;
+
+  friend void swap(EnumOptions& a, EnumOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumOptions& from) {
+    EnumOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumOptions";
+  }
+  protected:
+  explicit EnumOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kAllowAliasFieldNumber = 2,
+    kDeprecatedFieldNumber = 3,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool allow_alias = 2;
+  bool has_allow_alias() const;
+  private:
+  bool _internal_has_allow_alias() const;
+  public:
+  void clear_allow_alias();
+  bool allow_alias() const;
+  void set_allow_alias(bool value);
+  private:
+  bool _internal_allow_alias() const;
+  void _internal_set_allow_alias(bool value);
+  public:
+
+  // optional bool deprecated = 3 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool allow_alias_;
+    bool deprecated_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumValueOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueOptions) */ {
+ public:
+  inline EnumValueOptions() : EnumValueOptions(nullptr) {}
+  ~EnumValueOptions() override;
+  explicit PROTOBUF_CONSTEXPR EnumValueOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumValueOptions(const EnumValueOptions& from);
+  EnumValueOptions(EnumValueOptions&& from) noexcept
+    : EnumValueOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumValueOptions& operator=(const EnumValueOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumValueOptions& operator=(EnumValueOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumValueOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumValueOptions* internal_default_instance() {
+    return reinterpret_cast<const EnumValueOptions*>(
+               &_EnumValueOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    18;
+
+  friend void swap(EnumValueOptions& a, EnumValueOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumValueOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValueOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumValueOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumValueOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumValueOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumValueOptions& from) {
+    EnumValueOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumValueOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValueOptions";
+  }
+  protected:
+  explicit EnumValueOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kDeprecatedFieldNumber = 1,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool deprecated = 1 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          EnumValueOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool deprecated_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ServiceOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceOptions) */ {
+ public:
+  inline ServiceOptions() : ServiceOptions(nullptr) {}
+  ~ServiceOptions() override;
+  explicit PROTOBUF_CONSTEXPR ServiceOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ServiceOptions(const ServiceOptions& from);
+  ServiceOptions(ServiceOptions&& from) noexcept
+    : ServiceOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline ServiceOptions& operator=(const ServiceOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ServiceOptions& operator=(ServiceOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ServiceOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ServiceOptions* internal_default_instance() {
+    return reinterpret_cast<const ServiceOptions*>(
+               &_ServiceOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    19;
+
+  friend void swap(ServiceOptions& a, ServiceOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ServiceOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ServiceOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ServiceOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ServiceOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ServiceOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ServiceOptions& from) {
+    ServiceOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ServiceOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ServiceOptions";
+  }
+  protected:
+  explicit ServiceOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kDeprecatedFieldNumber = 33,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool deprecated = 33 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          ServiceOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool deprecated_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT MethodOptions final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodOptions) */ {
+ public:
+  inline MethodOptions() : MethodOptions(nullptr) {}
+  ~MethodOptions() override;
+  explicit PROTOBUF_CONSTEXPR MethodOptions(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  MethodOptions(const MethodOptions& from);
+  MethodOptions(MethodOptions&& from) noexcept
+    : MethodOptions() {
+    *this = ::std::move(from);
+  }
+
+  inline MethodOptions& operator=(const MethodOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline MethodOptions& operator=(MethodOptions&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const MethodOptions& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const MethodOptions* internal_default_instance() {
+    return reinterpret_cast<const MethodOptions*>(
+               &_MethodOptions_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    20;
+
+  friend void swap(MethodOptions& a, MethodOptions& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(MethodOptions* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(MethodOptions* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  MethodOptions* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<MethodOptions>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const MethodOptions& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const MethodOptions& from) {
+    MethodOptions::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(MethodOptions* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.MethodOptions";
+  }
+  protected:
+  explicit MethodOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef MethodOptions_IdempotencyLevel IdempotencyLevel;
+  static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN =
+    MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
+  static constexpr IdempotencyLevel NO_SIDE_EFFECTS =
+    MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS;
+  static constexpr IdempotencyLevel IDEMPOTENT =
+    MethodOptions_IdempotencyLevel_IDEMPOTENT;
+  static inline bool IdempotencyLevel_IsValid(int value) {
+    return MethodOptions_IdempotencyLevel_IsValid(value);
+  }
+  static constexpr IdempotencyLevel IdempotencyLevel_MIN =
+    MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN;
+  static constexpr IdempotencyLevel IdempotencyLevel_MAX =
+    MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX;
+  static constexpr int IdempotencyLevel_ARRAYSIZE =
+    MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  IdempotencyLevel_descriptor() {
+    return MethodOptions_IdempotencyLevel_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& IdempotencyLevel_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, IdempotencyLevel>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function IdempotencyLevel_Name.");
+    return MethodOptions_IdempotencyLevel_Name(enum_t_value);
+  }
+  static inline bool IdempotencyLevel_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      IdempotencyLevel* value) {
+    return MethodOptions_IdempotencyLevel_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kUninterpretedOptionFieldNumber = 999,
+    kDeprecatedFieldNumber = 33,
+    kIdempotencyLevelFieldNumber = 34,
+  };
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  private:
+  int _internal_uninterpreted_option_size() const;
+  public:
+  void clear_uninterpreted_option();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& _internal_uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _internal_add_uninterpreted_option();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& uninterpreted_option(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* add_uninterpreted_option();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  // optional bool deprecated = 33 [default = false];
+  bool has_deprecated() const;
+  private:
+  bool _internal_has_deprecated() const;
+  public:
+  void clear_deprecated();
+  bool deprecated() const;
+  void set_deprecated(bool value);
+  private:
+  bool _internal_deprecated() const;
+  void _internal_set_deprecated(bool value);
+  public:
+
+  // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+  bool has_idempotency_level() const;
+  private:
+  bool _internal_has_idempotency_level() const;
+  public:
+  void clear_idempotency_level();
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel idempotency_level() const;
+  void set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel _internal_idempotency_level() const;
+  void _internal_set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value);
+  public:
+
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline bool HasExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.Has(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void ClearExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    _impl_._extensions_.ClearExtension(id.number());
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline int ExtensionSize(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _impl_._extensions_.ExtensionSize(id.number());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_,
+                                  id.default_value());
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Mutable(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), _field_type, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::SetAllocated(id.number(), _field_type, value,
+                                    &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void UnsafeArenaSetAllocatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Singular::MutableType value) {
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,
+                                               value, &_impl_._extensions_);
+
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  PROTOBUF_NODISCARD inline
+      typename _proto_TypeTraits::Singular::MutableType
+      ReleaseExtension(
+          const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+              MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::Release(id.number(), _field_type,
+                                      &_impl_._extensions_);
+  }
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Singular::MutableType
+  UnsafeArenaReleaseExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,
+                                                 &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::ConstType GetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) const {
+
+    return _proto_TypeTraits::Get(id.number(), _impl_._extensions_, index);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index) {
+
+    return _proto_TypeTraits::Mutable(id.number(), index, &_impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void SetExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      int index, typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Set(id.number(), index, value, &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::MutableType AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+    typename _proto_TypeTraits::Repeated::MutableType to_add =
+        _proto_TypeTraits::Add(id.number(), _field_type, &_impl_._extensions_);
+
+    return to_add;
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline void AddExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id,
+      typename _proto_TypeTraits::Repeated::ConstType value) {
+    _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value,
+                           &_impl_._extensions_);
+
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType&
+  GetRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) const {
+
+    return _proto_TypeTraits::GetRepeated(id.number(), _impl_._extensions_);
+  }
+
+  template <typename _proto_TypeTraits,
+            ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
+            bool _is_packed>
+  inline typename _proto_TypeTraits::Repeated::RepeatedFieldType*
+  MutableRepeatedExtension(
+      const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier<
+          MethodOptions, _proto_TypeTraits, _field_type, _is_packed>& id) {
+
+    return _proto_TypeTraits::MutableRepeated(id.number(), _field_type,
+                                              _is_packed, &_impl_._extensions_);
+  }
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ExtensionSet _extensions_;
+
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
+    bool deprecated_;
+    int idempotency_level_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UninterpretedOption_NamePart final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption.NamePart) */ {
+ public:
+  inline UninterpretedOption_NamePart() : UninterpretedOption_NamePart(nullptr) {}
+  ~UninterpretedOption_NamePart() override;
+  explicit PROTOBUF_CONSTEXPR UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from);
+  UninterpretedOption_NamePart(UninterpretedOption_NamePart&& from) noexcept
+    : UninterpretedOption_NamePart() {
+    *this = ::std::move(from);
+  }
+
+  inline UninterpretedOption_NamePart& operator=(const UninterpretedOption_NamePart& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UninterpretedOption_NamePart& operator=(UninterpretedOption_NamePart&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UninterpretedOption_NamePart& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UninterpretedOption_NamePart* internal_default_instance() {
+    return reinterpret_cast<const UninterpretedOption_NamePart*>(
+               &_UninterpretedOption_NamePart_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    21;
+
+  friend void swap(UninterpretedOption_NamePart& a, UninterpretedOption_NamePart& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UninterpretedOption_NamePart* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UninterpretedOption_NamePart* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UninterpretedOption_NamePart* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UninterpretedOption_NamePart>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UninterpretedOption_NamePart& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UninterpretedOption_NamePart& from) {
+    UninterpretedOption_NamePart::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UninterpretedOption_NamePart* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UninterpretedOption.NamePart";
+  }
+  protected:
+  explicit UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNamePartFieldNumber = 1,
+    kIsExtensionFieldNumber = 2,
+  };
+  // required string name_part = 1;
+  bool has_name_part() const;
+  private:
+  bool _internal_has_name_part() const;
+  public:
+  void clear_name_part();
+  const std::string& name_part() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name_part(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name_part();
+  PROTOBUF_NODISCARD std::string* release_name_part();
+  void set_allocated_name_part(std::string* name_part);
+  private:
+  const std::string& _internal_name_part() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name_part(const std::string& value);
+  std::string* _internal_mutable_name_part();
+  public:
+
+  // required bool is_extension = 2;
+  bool has_is_extension() const;
+  private:
+  bool _internal_has_is_extension() const;
+  public:
+  void clear_is_extension();
+  bool is_extension() const;
+  void set_is_extension(bool value);
+  private:
+  bool _internal_is_extension() const;
+  void _internal_set_is_extension(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
+ private:
+  class _Internal;
+
+  // helper for ByteSizeLong()
+  size_t RequiredFieldsByteSizeFallback() const;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_part_;
+    bool is_extension_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UninterpretedOption final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption) */ {
+ public:
+  inline UninterpretedOption() : UninterpretedOption(nullptr) {}
+  ~UninterpretedOption() override;
+  explicit PROTOBUF_CONSTEXPR UninterpretedOption(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UninterpretedOption(const UninterpretedOption& from);
+  UninterpretedOption(UninterpretedOption&& from) noexcept
+    : UninterpretedOption() {
+    *this = ::std::move(from);
+  }
+
+  inline UninterpretedOption& operator=(const UninterpretedOption& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UninterpretedOption& operator=(UninterpretedOption&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UninterpretedOption& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UninterpretedOption* internal_default_instance() {
+    return reinterpret_cast<const UninterpretedOption*>(
+               &_UninterpretedOption_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    22;
+
+  friend void swap(UninterpretedOption& a, UninterpretedOption& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UninterpretedOption* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UninterpretedOption* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UninterpretedOption* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UninterpretedOption>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UninterpretedOption& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UninterpretedOption& from) {
+    UninterpretedOption::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UninterpretedOption* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UninterpretedOption";
+  }
+  protected:
+  explicit UninterpretedOption(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef UninterpretedOption_NamePart NamePart;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 2,
+    kIdentifierValueFieldNumber = 3,
+    kStringValueFieldNumber = 7,
+    kAggregateValueFieldNumber = 8,
+    kPositiveIntValueFieldNumber = 4,
+    kNegativeIntValueFieldNumber = 5,
+    kDoubleValueFieldNumber = 6,
+  };
+  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+  int name_size() const;
+  private:
+  int _internal_name_size() const;
+  public:
+  void clear_name();
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* mutable_name(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >*
+      mutable_name();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& _internal_name(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* _internal_add_name();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& name(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* add_name();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >&
+      name() const;
+
+  // optional string identifier_value = 3;
+  bool has_identifier_value() const;
+  private:
+  bool _internal_has_identifier_value() const;
+  public:
+  void clear_identifier_value();
+  const std::string& identifier_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_identifier_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_identifier_value();
+  PROTOBUF_NODISCARD std::string* release_identifier_value();
+  void set_allocated_identifier_value(std::string* identifier_value);
+  private:
+  const std::string& _internal_identifier_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_identifier_value(const std::string& value);
+  std::string* _internal_mutable_identifier_value();
+  public:
+
+  // optional bytes string_value = 7;
+  bool has_string_value() const;
+  private:
+  bool _internal_has_string_value() const;
+  public:
+  void clear_string_value();
+  const std::string& string_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_string_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_string_value();
+  PROTOBUF_NODISCARD std::string* release_string_value();
+  void set_allocated_string_value(std::string* string_value);
+  private:
+  const std::string& _internal_string_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_string_value(const std::string& value);
+  std::string* _internal_mutable_string_value();
+  public:
+
+  // optional string aggregate_value = 8;
+  bool has_aggregate_value() const;
+  private:
+  bool _internal_has_aggregate_value() const;
+  public:
+  void clear_aggregate_value();
+  const std::string& aggregate_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_aggregate_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_aggregate_value();
+  PROTOBUF_NODISCARD std::string* release_aggregate_value();
+  void set_allocated_aggregate_value(std::string* aggregate_value);
+  private:
+  const std::string& _internal_aggregate_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_aggregate_value(const std::string& value);
+  std::string* _internal_mutable_aggregate_value();
+  public:
+
+  // optional uint64 positive_int_value = 4;
+  bool has_positive_int_value() const;
+  private:
+  bool _internal_has_positive_int_value() const;
+  public:
+  void clear_positive_int_value();
+  uint64_t positive_int_value() const;
+  void set_positive_int_value(uint64_t value);
+  private:
+  uint64_t _internal_positive_int_value() const;
+  void _internal_set_positive_int_value(uint64_t value);
+  public:
+
+  // optional int64 negative_int_value = 5;
+  bool has_negative_int_value() const;
+  private:
+  bool _internal_has_negative_int_value() const;
+  public:
+  void clear_negative_int_value();
+  int64_t negative_int_value() const;
+  void set_negative_int_value(int64_t value);
+  private:
+  int64_t _internal_negative_int_value() const;
+  void _internal_set_negative_int_value(int64_t value);
+  public:
+
+  // optional double double_value = 6;
+  bool has_double_value() const;
+  private:
+  bool _internal_has_double_value() const;
+  public:
+  void clear_double_value();
+  double double_value() const;
+  void set_double_value(double value);
+  private:
+  double _internal_double_value() const;
+  void _internal_set_double_value(double value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart > name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr identifier_value_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr string_value_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr aggregate_value_;
+    uint64_t positive_int_value_;
+    int64_t negative_int_value_;
+    double double_value_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT SourceCodeInfo_Location final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo.Location) */ {
+ public:
+  inline SourceCodeInfo_Location() : SourceCodeInfo_Location(nullptr) {}
+  ~SourceCodeInfo_Location() override;
+  explicit PROTOBUF_CONSTEXPR SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  SourceCodeInfo_Location(const SourceCodeInfo_Location& from);
+  SourceCodeInfo_Location(SourceCodeInfo_Location&& from) noexcept
+    : SourceCodeInfo_Location() {
+    *this = ::std::move(from);
+  }
+
+  inline SourceCodeInfo_Location& operator=(const SourceCodeInfo_Location& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline SourceCodeInfo_Location& operator=(SourceCodeInfo_Location&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const SourceCodeInfo_Location& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const SourceCodeInfo_Location* internal_default_instance() {
+    return reinterpret_cast<const SourceCodeInfo_Location*>(
+               &_SourceCodeInfo_Location_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    23;
+
+  friend void swap(SourceCodeInfo_Location& a, SourceCodeInfo_Location& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(SourceCodeInfo_Location* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(SourceCodeInfo_Location* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  SourceCodeInfo_Location* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<SourceCodeInfo_Location>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const SourceCodeInfo_Location& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const SourceCodeInfo_Location& from) {
+    SourceCodeInfo_Location::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(SourceCodeInfo_Location* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.SourceCodeInfo.Location";
+  }
+  protected:
+  explicit SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPathFieldNumber = 1,
+    kSpanFieldNumber = 2,
+    kLeadingDetachedCommentsFieldNumber = 6,
+    kLeadingCommentsFieldNumber = 3,
+    kTrailingCommentsFieldNumber = 4,
+  };
+  // repeated int32 path = 1 [packed = true];
+  int path_size() const;
+  private:
+  int _internal_path_size() const;
+  public:
+  void clear_path();
+  private:
+  int32_t _internal_path(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_path() const;
+  void _internal_add_path(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_path();
+  public:
+  int32_t path(int index) const;
+  void set_path(int index, int32_t value);
+  void add_path(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      path() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_path();
+
+  // repeated int32 span = 2 [packed = true];
+  int span_size() const;
+  private:
+  int _internal_span_size() const;
+  public:
+  void clear_span();
+  private:
+  int32_t _internal_span(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_span() const;
+  void _internal_add_span(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_span();
+  public:
+  int32_t span(int index) const;
+  void set_span(int index, int32_t value);
+  void add_span(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      span() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_span();
+
+  // repeated string leading_detached_comments = 6;
+  int leading_detached_comments_size() const;
+  private:
+  int _internal_leading_detached_comments_size() const;
+  public:
+  void clear_leading_detached_comments();
+  const std::string& leading_detached_comments(int index) const;
+  std::string* mutable_leading_detached_comments(int index);
+  void set_leading_detached_comments(int index, const std::string& value);
+  void set_leading_detached_comments(int index, std::string&& value);
+  void set_leading_detached_comments(int index, const char* value);
+  void set_leading_detached_comments(int index, const char* value, size_t size);
+  std::string* add_leading_detached_comments();
+  void add_leading_detached_comments(const std::string& value);
+  void add_leading_detached_comments(std::string&& value);
+  void add_leading_detached_comments(const char* value);
+  void add_leading_detached_comments(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& leading_detached_comments() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_leading_detached_comments();
+  private:
+  const std::string& _internal_leading_detached_comments(int index) const;
+  std::string* _internal_add_leading_detached_comments();
+  public:
+
+  // optional string leading_comments = 3;
+  bool has_leading_comments() const;
+  private:
+  bool _internal_has_leading_comments() const;
+  public:
+  void clear_leading_comments();
+  const std::string& leading_comments() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_leading_comments(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_leading_comments();
+  PROTOBUF_NODISCARD std::string* release_leading_comments();
+  void set_allocated_leading_comments(std::string* leading_comments);
+  private:
+  const std::string& _internal_leading_comments() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_leading_comments(const std::string& value);
+  std::string* _internal_mutable_leading_comments();
+  public:
+
+  // optional string trailing_comments = 4;
+  bool has_trailing_comments() const;
+  private:
+  bool _internal_has_trailing_comments() const;
+  public:
+  void clear_trailing_comments();
+  const std::string& trailing_comments() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_trailing_comments(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_trailing_comments();
+  PROTOBUF_NODISCARD std::string* release_trailing_comments();
+  void set_allocated_trailing_comments(std::string* trailing_comments);
+  private:
+  const std::string& _internal_trailing_comments() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_trailing_comments(const std::string& value);
+  std::string* _internal_mutable_trailing_comments();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > path_;
+    mutable std::atomic<int> _path_cached_byte_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > span_;
+    mutable std::atomic<int> _span_cached_byte_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> leading_detached_comments_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr leading_comments_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr trailing_comments_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT SourceCodeInfo final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo) */ {
+ public:
+  inline SourceCodeInfo() : SourceCodeInfo(nullptr) {}
+  ~SourceCodeInfo() override;
+  explicit PROTOBUF_CONSTEXPR SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  SourceCodeInfo(const SourceCodeInfo& from);
+  SourceCodeInfo(SourceCodeInfo&& from) noexcept
+    : SourceCodeInfo() {
+    *this = ::std::move(from);
+  }
+
+  inline SourceCodeInfo& operator=(const SourceCodeInfo& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline SourceCodeInfo& operator=(SourceCodeInfo&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const SourceCodeInfo& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const SourceCodeInfo* internal_default_instance() {
+    return reinterpret_cast<const SourceCodeInfo*>(
+               &_SourceCodeInfo_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    24;
+
+  friend void swap(SourceCodeInfo& a, SourceCodeInfo& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(SourceCodeInfo* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(SourceCodeInfo* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  SourceCodeInfo* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<SourceCodeInfo>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const SourceCodeInfo& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const SourceCodeInfo& from) {
+    SourceCodeInfo::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(SourceCodeInfo* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.SourceCodeInfo";
+  }
+  protected:
+  explicit SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef SourceCodeInfo_Location Location;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kLocationFieldNumber = 1,
+  };
+  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+  int location_size() const;
+  private:
+  int _internal_location_size() const;
+  public:
+  void clear_location();
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* mutable_location(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >*
+      mutable_location();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& _internal_location(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* _internal_add_location();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& location(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* add_location();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >&
+      location() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location > location_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo.Annotation) */ {
+ public:
+  inline GeneratedCodeInfo_Annotation() : GeneratedCodeInfo_Annotation(nullptr) {}
+  ~GeneratedCodeInfo_Annotation() override;
+  explicit PROTOBUF_CONSTEXPR GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from);
+  GeneratedCodeInfo_Annotation(GeneratedCodeInfo_Annotation&& from) noexcept
+    : GeneratedCodeInfo_Annotation() {
+    *this = ::std::move(from);
+  }
+
+  inline GeneratedCodeInfo_Annotation& operator=(const GeneratedCodeInfo_Annotation& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline GeneratedCodeInfo_Annotation& operator=(GeneratedCodeInfo_Annotation&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const GeneratedCodeInfo_Annotation& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const GeneratedCodeInfo_Annotation* internal_default_instance() {
+    return reinterpret_cast<const GeneratedCodeInfo_Annotation*>(
+               &_GeneratedCodeInfo_Annotation_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    25;
+
+  friend void swap(GeneratedCodeInfo_Annotation& a, GeneratedCodeInfo_Annotation& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(GeneratedCodeInfo_Annotation* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(GeneratedCodeInfo_Annotation* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  GeneratedCodeInfo_Annotation* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<GeneratedCodeInfo_Annotation>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const GeneratedCodeInfo_Annotation& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const GeneratedCodeInfo_Annotation& from) {
+    GeneratedCodeInfo_Annotation::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(GeneratedCodeInfo_Annotation* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.GeneratedCodeInfo.Annotation";
+  }
+  protected:
+  explicit GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPathFieldNumber = 1,
+    kSourceFileFieldNumber = 2,
+    kBeginFieldNumber = 3,
+    kEndFieldNumber = 4,
+  };
+  // repeated int32 path = 1 [packed = true];
+  int path_size() const;
+  private:
+  int _internal_path_size() const;
+  public:
+  void clear_path();
+  private:
+  int32_t _internal_path(int index) const;
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      _internal_path() const;
+  void _internal_add_path(int32_t value);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      _internal_mutable_path();
+  public:
+  int32_t path(int index) const;
+  void set_path(int index, int32_t value);
+  void add_path(int32_t value);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+      path() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+      mutable_path();
+
+  // optional string source_file = 2;
+  bool has_source_file() const;
+  private:
+  bool _internal_has_source_file() const;
+  public:
+  void clear_source_file();
+  const std::string& source_file() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_source_file(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_source_file();
+  PROTOBUF_NODISCARD std::string* release_source_file();
+  void set_allocated_source_file(std::string* source_file);
+  private:
+  const std::string& _internal_source_file() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_source_file(const std::string& value);
+  std::string* _internal_mutable_source_file();
+  public:
+
+  // optional int32 begin = 3;
+  bool has_begin() const;
+  private:
+  bool _internal_has_begin() const;
+  public:
+  void clear_begin();
+  int32_t begin() const;
+  void set_begin(int32_t value);
+  private:
+  int32_t _internal_begin() const;
+  void _internal_set_begin(int32_t value);
+  public:
+
+  // optional int32 end = 4;
+  bool has_end() const;
+  private:
+  bool _internal_has_end() const;
+  public:
+  void clear_end();
+  int32_t end() const;
+  void set_end(int32_t value);
+  private:
+  int32_t _internal_end() const;
+  void _internal_set_end(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::HasBits<1> _has_bits_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t > path_;
+    mutable std::atomic<int> _path_cached_byte_size_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr source_file_;
+    int32_t begin_;
+    int32_t end_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT GeneratedCodeInfo final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo) */ {
+ public:
+  inline GeneratedCodeInfo() : GeneratedCodeInfo(nullptr) {}
+  ~GeneratedCodeInfo() override;
+  explicit PROTOBUF_CONSTEXPR GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  GeneratedCodeInfo(const GeneratedCodeInfo& from);
+  GeneratedCodeInfo(GeneratedCodeInfo&& from) noexcept
+    : GeneratedCodeInfo() {
+    *this = ::std::move(from);
+  }
+
+  inline GeneratedCodeInfo& operator=(const GeneratedCodeInfo& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline GeneratedCodeInfo& operator=(GeneratedCodeInfo&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+  }
+  inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const GeneratedCodeInfo& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const GeneratedCodeInfo* internal_default_instance() {
+    return reinterpret_cast<const GeneratedCodeInfo*>(
+               &_GeneratedCodeInfo_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    26;
+
+  friend void swap(GeneratedCodeInfo& a, GeneratedCodeInfo& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(GeneratedCodeInfo* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(GeneratedCodeInfo* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  GeneratedCodeInfo* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<GeneratedCodeInfo>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const GeneratedCodeInfo& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const GeneratedCodeInfo& from) {
+    GeneratedCodeInfo::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(GeneratedCodeInfo* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.GeneratedCodeInfo";
+  }
+  protected:
+  explicit GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef GeneratedCodeInfo_Annotation Annotation;
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kAnnotationFieldNumber = 1,
+  };
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  int annotation_size() const;
+  private:
+  int _internal_annotation_size() const;
+  public:
+  void clear_annotation();
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* mutable_annotation(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >*
+      mutable_annotation();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& _internal_annotation(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* _internal_add_annotation();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& annotation(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* add_annotation();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >&
+      annotation() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation > annotation_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// FileDescriptorSet
+
+// repeated .google.protobuf.FileDescriptorProto file = 1;
+inline int FileDescriptorSet::_internal_file_size() const {
+  return _impl_.file_.size();
+}
+inline int FileDescriptorSet::file_size() const {
+  return _internal_file_size();
+}
+inline void FileDescriptorSet::clear_file() {
+  _impl_.file_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorSet.file)
+  return _impl_.file_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
+FileDescriptorSet::mutable_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file)
+  return &_impl_.file_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& FileDescriptorSet::_internal_file(int index) const {
+  return _impl_.file_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto& FileDescriptorSet::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorSet.file)
+  return _internal_file(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* FileDescriptorSet::_internal_add_file() {
+  return _impl_.file_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* FileDescriptorSet::add_file() {
+  ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* _add = _internal_add_file();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >&
+FileDescriptorSet::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
+  return _impl_.file_;
+}
+
+// -------------------------------------------------------------------
+
+// FileDescriptorProto
+
+// optional string name = 1;
+inline bool FileDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FileDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void FileDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& FileDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.name)
+}
+inline std::string* FileDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void FileDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.name)
+}
+
+// optional string package = 2;
+inline bool FileDescriptorProto::_internal_has_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FileDescriptorProto::has_package() const {
+  return _internal_has_package();
+}
+inline void FileDescriptorProto::clear_package() {
+  _impl_.package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& FileDescriptorProto::package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package)
+  return _internal_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileDescriptorProto::set_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.package)
+}
+inline std::string* FileDescriptorProto::mutable_package() {
+  std::string* _s = _internal_mutable_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_package() const {
+  return _impl_.package_.Get();
+}
+inline void FileDescriptorProto::_internal_set_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::_internal_mutable_package() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::release_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package)
+  if (!_internal_has_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.package_.IsDefault()) {
+    _impl_.package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileDescriptorProto::set_allocated_package(std::string* package) {
+  if (package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.package_.SetAllocated(package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.package_.IsDefault()) {
+    _impl_.package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package)
+}
+
+// repeated string dependency = 3;
+inline int FileDescriptorProto::_internal_dependency_size() const {
+  return _impl_.dependency_.size();
+}
+inline int FileDescriptorProto::dependency_size() const {
+  return _internal_dependency_size();
+}
+inline void FileDescriptorProto::clear_dependency() {
+  _impl_.dependency_.Clear();
+}
+inline std::string* FileDescriptorProto::add_dependency() {
+  std::string* _s = _internal_add_dependency();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_dependency(int index) const {
+  return _impl_.dependency_.Get(index);
+}
+inline const std::string& FileDescriptorProto::dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.dependency)
+  return _internal_dependency(index);
+}
+inline std::string* FileDescriptorProto::mutable_dependency(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.dependency)
+  return _impl_.dependency_.Mutable(index);
+}
+inline void FileDescriptorProto::set_dependency(int index, const std::string& value) {
+  _impl_.dependency_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::set_dependency(int index, std::string&& value) {
+  _impl_.dependency_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::set_dependency(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.dependency_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) {
+  _impl_.dependency_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+inline std::string* FileDescriptorProto::_internal_add_dependency() {
+  return _impl_.dependency_.Add();
+}
+inline void FileDescriptorProto::add_dependency(const std::string& value) {
+  _impl_.dependency_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::add_dependency(std::string&& value) {
+  _impl_.dependency_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::add_dependency(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.dependency_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.FileDescriptorProto.dependency)
+}
+inline void FileDescriptorProto::add_dependency(const char* value, size_t size) {
+  _impl_.dependency_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+FileDescriptorProto::dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.dependency)
+  return _impl_.dependency_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+FileDescriptorProto::mutable_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.dependency)
+  return &_impl_.dependency_;
+}
+
+// repeated int32 public_dependency = 10;
+inline int FileDescriptorProto::_internal_public_dependency_size() const {
+  return _impl_.public_dependency_.size();
+}
+inline int FileDescriptorProto::public_dependency_size() const {
+  return _internal_public_dependency_size();
+}
+inline void FileDescriptorProto::clear_public_dependency() {
+  _impl_.public_dependency_.Clear();
+}
+inline int32_t FileDescriptorProto::_internal_public_dependency(int index) const {
+  return _impl_.public_dependency_.Get(index);
+}
+inline int32_t FileDescriptorProto::public_dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.public_dependency)
+  return _internal_public_dependency(index);
+}
+inline void FileDescriptorProto::set_public_dependency(int index, int32_t value) {
+  _impl_.public_dependency_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.public_dependency)
+}
+inline void FileDescriptorProto::_internal_add_public_dependency(int32_t value) {
+  _impl_.public_dependency_.Add(value);
+}
+inline void FileDescriptorProto::add_public_dependency(int32_t value) {
+  _internal_add_public_dependency(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.public_dependency)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::_internal_public_dependency() const {
+  return _impl_.public_dependency_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::public_dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.public_dependency)
+  return _internal_public_dependency();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::_internal_mutable_public_dependency() {
+  return &_impl_.public_dependency_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::mutable_public_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.public_dependency)
+  return _internal_mutable_public_dependency();
+}
+
+// repeated int32 weak_dependency = 11;
+inline int FileDescriptorProto::_internal_weak_dependency_size() const {
+  return _impl_.weak_dependency_.size();
+}
+inline int FileDescriptorProto::weak_dependency_size() const {
+  return _internal_weak_dependency_size();
+}
+inline void FileDescriptorProto::clear_weak_dependency() {
+  _impl_.weak_dependency_.Clear();
+}
+inline int32_t FileDescriptorProto::_internal_weak_dependency(int index) const {
+  return _impl_.weak_dependency_.Get(index);
+}
+inline int32_t FileDescriptorProto::weak_dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.weak_dependency)
+  return _internal_weak_dependency(index);
+}
+inline void FileDescriptorProto::set_weak_dependency(int index, int32_t value) {
+  _impl_.weak_dependency_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+inline void FileDescriptorProto::_internal_add_weak_dependency(int32_t value) {
+  _impl_.weak_dependency_.Add(value);
+}
+inline void FileDescriptorProto::add_weak_dependency(int32_t value) {
+  _internal_add_weak_dependency(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::_internal_weak_dependency() const {
+  return _impl_.weak_dependency_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+FileDescriptorProto::weak_dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.weak_dependency)
+  return _internal_weak_dependency();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::_internal_mutable_weak_dependency() {
+  return &_impl_.weak_dependency_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+FileDescriptorProto::mutable_weak_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.weak_dependency)
+  return _internal_mutable_weak_dependency();
+}
+
+// repeated .google.protobuf.DescriptorProto message_type = 4;
+inline int FileDescriptorProto::_internal_message_type_size() const {
+  return _impl_.message_type_.size();
+}
+inline int FileDescriptorProto::message_type_size() const {
+  return _internal_message_type_size();
+}
+inline void FileDescriptorProto::clear_message_type() {
+  _impl_.message_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.message_type)
+  return _impl_.message_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+FileDescriptorProto::mutable_message_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type)
+  return &_impl_.message_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& FileDescriptorProto::_internal_message_type(int index) const {
+  return _impl_.message_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.message_type)
+  return _internal_message_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* FileDescriptorProto::_internal_add_message_type() {
+  return _impl_.message_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* FileDescriptorProto::add_message_type() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _add = _internal_add_message_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+FileDescriptorProto::message_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
+  return _impl_.message_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+inline int FileDescriptorProto::_internal_enum_type_size() const {
+  return _impl_.enum_type_.size();
+}
+inline int FileDescriptorProto::enum_type_size() const {
+  return _internal_enum_type_size();
+}
+inline void FileDescriptorProto::clear_enum_type() {
+  _impl_.enum_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.enum_type)
+  return _impl_.enum_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+FileDescriptorProto::mutable_enum_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type)
+  return &_impl_.enum_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& FileDescriptorProto::_internal_enum_type(int index) const {
+  return _impl_.enum_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.enum_type)
+  return _internal_enum_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* FileDescriptorProto::_internal_add_enum_type() {
+  return _impl_.enum_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _add = _internal_add_enum_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+FileDescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
+  return _impl_.enum_type_;
+}
+
+// repeated .google.protobuf.ServiceDescriptorProto service = 6;
+inline int FileDescriptorProto::_internal_service_size() const {
+  return _impl_.service_.size();
+}
+inline int FileDescriptorProto::service_size() const {
+  return _internal_service_size();
+}
+inline void FileDescriptorProto::clear_service() {
+  _impl_.service_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.service)
+  return _impl_.service_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >*
+FileDescriptorProto::mutable_service() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service)
+  return &_impl_.service_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& FileDescriptorProto::_internal_service(int index) const {
+  return _impl_.service_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.service)
+  return _internal_service(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* FileDescriptorProto::_internal_add_service() {
+  return _impl_.service_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* FileDescriptorProto::add_service() {
+  ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* _add = _internal_add_service();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >&
+FileDescriptorProto::service() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
+  return _impl_.service_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 7;
+inline int FileDescriptorProto::_internal_extension_size() const {
+  return _impl_.extension_.size();
+}
+inline int FileDescriptorProto::extension_size() const {
+  return _internal_extension_size();
+}
+inline void FileDescriptorProto::clear_extension() {
+  _impl_.extension_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.extension)
+  return _impl_.extension_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+FileDescriptorProto::mutable_extension() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension)
+  return &_impl_.extension_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& FileDescriptorProto::_internal_extension(int index) const {
+  return _impl_.extension_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.extension)
+  return _internal_extension(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* FileDescriptorProto::_internal_add_extension() {
+  return _impl_.extension_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* FileDescriptorProto::add_extension() {
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _add = _internal_add_extension();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+FileDescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
+  return _impl_.extension_;
+}
+
+// optional .google.protobuf.FileOptions options = 8;
+inline bool FileDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool FileDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void FileDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileOptions& FileDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::FileOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::FileOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_FileOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FileOptions& FileDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.options)
+  return _internal_options();
+}
+inline void FileDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::FileOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FileOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions* FileDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::FileOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
+  return _msg;
+}
+inline void FileDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::FileOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
+
+// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+inline bool FileDescriptorProto::_internal_has_source_code_info() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.source_code_info_ != nullptr);
+  return value;
+}
+inline bool FileDescriptorProto::has_source_code_info() const {
+  return _internal_has_source_code_info();
+}
+inline void FileDescriptorProto::clear_source_code_info() {
+  if (_impl_.source_code_info_ != nullptr) _impl_.source_code_info_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& FileDescriptorProto::_internal_source_code_info() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* p = _impl_.source_code_info_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& FileDescriptorProto::source_code_info() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.source_code_info)
+  return _internal_source_code_info();
+}
+inline void FileDescriptorProto::unsafe_arena_set_allocated_source_code_info(
+    ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_code_info_);
+  }
+  _impl_.source_code_info_ = source_code_info;
+  if (source_code_info) {
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* temp = _impl_.source_code_info_;
+  _impl_.source_code_info_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::unsafe_arena_release_source_code_info() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info)
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* temp = _impl_.source_code_info_;
+  _impl_.source_code_info_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::_internal_mutable_source_code_info() {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  if (_impl_.source_code_info_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceCodeInfo>(GetArenaForAllocation());
+    _impl_.source_code_info_ = p;
+  }
+  return _impl_.source_code_info_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() {
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* _msg = _internal_mutable_source_code_info();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
+  return _msg;
+}
+inline void FileDescriptorProto::set_allocated_source_code_info(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* source_code_info) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.source_code_info_;
+  }
+  if (source_code_info) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(source_code_info);
+    if (message_arena != submessage_arena) {
+      source_code_info = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_code_info, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  _impl_.source_code_info_ = source_code_info;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
+}
+
+// optional string syntax = 12;
+inline bool FileDescriptorProto::_internal_has_syntax() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FileDescriptorProto::has_syntax() const {
+  return _internal_has_syntax();
+}
+inline void FileDescriptorProto::clear_syntax() {
+  _impl_.syntax_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& FileDescriptorProto::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax)
+  return _internal_syntax();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileDescriptorProto::set_syntax(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.syntax_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax)
+}
+inline std::string* FileDescriptorProto::mutable_syntax() {
+  std::string* _s = _internal_mutable_syntax();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.syntax)
+  return _s;
+}
+inline const std::string& FileDescriptorProto::_internal_syntax() const {
+  return _impl_.syntax_.Get();
+}
+inline void FileDescriptorProto::_internal_set_syntax(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.syntax_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::_internal_mutable_syntax() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.syntax_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileDescriptorProto::release_syntax() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax)
+  if (!_internal_has_syntax()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.syntax_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.syntax_.IsDefault()) {
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileDescriptorProto::set_allocated_syntax(std::string* syntax) {
+  if (syntax != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.syntax_.SetAllocated(syntax, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.syntax_.IsDefault()) {
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto_ExtensionRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ExtensionRange::_internal_has_start() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ExtensionRange::has_start() const {
+  return _internal_has_start();
+}
+inline void DescriptorProto_ExtensionRange::clear_start() {
+  _impl_.start_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t DescriptorProto_ExtensionRange::_internal_start() const {
+  return _impl_.start_;
+}
+inline int32_t DescriptorProto_ExtensionRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.start)
+  return _internal_start();
+}
+inline void DescriptorProto_ExtensionRange::_internal_set_start(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.start_ = value;
+}
+inline void DescriptorProto_ExtensionRange::set_start(int32_t value) {
+  _internal_set_start(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.start)
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ExtensionRange::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ExtensionRange::has_end() const {
+  return _internal_has_end();
+}
+inline void DescriptorProto_ExtensionRange::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t DescriptorProto_ExtensionRange::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t DescriptorProto_ExtensionRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.end)
+  return _internal_end();
+}
+inline void DescriptorProto_ExtensionRange::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.end_ = value;
+}
+inline void DescriptorProto_ExtensionRange::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.end)
+}
+
+// optional .google.protobuf.ExtensionRangeOptions options = 3;
+inline bool DescriptorProto_ExtensionRange::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool DescriptorProto_ExtensionRange::has_options() const {
+  return _internal_has_options();
+}
+inline void DescriptorProto_ExtensionRange::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& DescriptorProto_ExtensionRange::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_ExtensionRangeOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& DescriptorProto_ExtensionRange::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.options)
+  return _internal_options();
+}
+inline void DescriptorProto_ExtensionRange::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.DescriptorProto.ExtensionRange.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.ExtensionRange.options)
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* DescriptorProto_ExtensionRange::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.ExtensionRange.options)
+  return _msg;
+}
+inline void DescriptorProto_ExtensionRange::set_allocated_options(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.ExtensionRange.options)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto_ReservedRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ReservedRange::_internal_has_start() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ReservedRange::has_start() const {
+  return _internal_has_start();
+}
+inline void DescriptorProto_ReservedRange::clear_start() {
+  _impl_.start_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline int32_t DescriptorProto_ReservedRange::_internal_start() const {
+  return _impl_.start_;
+}
+inline int32_t DescriptorProto_ReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start)
+  return _internal_start();
+}
+inline void DescriptorProto_ReservedRange::_internal_set_start(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.start_ = value;
+}
+inline void DescriptorProto_ReservedRange::set_start(int32_t value) {
+  _internal_set_start(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start)
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ReservedRange::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool DescriptorProto_ReservedRange::has_end() const {
+  return _internal_has_end();
+}
+inline void DescriptorProto_ReservedRange::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t DescriptorProto_ReservedRange::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t DescriptorProto_ReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end)
+  return _internal_end();
+}
+inline void DescriptorProto_ReservedRange::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.end_ = value;
+}
+inline void DescriptorProto_ReservedRange::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto
+
+// optional string name = 1;
+inline bool DescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool DescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void DescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& DescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void DescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.name)
+}
+inline std::string* DescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name)
+  return _s;
+}
+inline const std::string& DescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void DescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* DescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* DescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void DescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.name)
+}
+
+// repeated .google.protobuf.FieldDescriptorProto field = 2;
+inline int DescriptorProto::_internal_field_size() const {
+  return _impl_.field_.size();
+}
+inline int DescriptorProto::field_size() const {
+  return _internal_field_size();
+}
+inline void DescriptorProto::clear_field() {
+  _impl_.field_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::mutable_field(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.field)
+  return _impl_.field_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+DescriptorProto::mutable_field() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field)
+  return &_impl_.field_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::_internal_field(int index) const {
+  return _impl_.field_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::field(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.field)
+  return _internal_field(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::_internal_add_field() {
+  return _impl_.field_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::add_field() {
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _add = _internal_add_field();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+DescriptorProto::field() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
+  return _impl_.field_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 6;
+inline int DescriptorProto::_internal_extension_size() const {
+  return _impl_.extension_.size();
+}
+inline int DescriptorProto::extension_size() const {
+  return _internal_extension_size();
+}
+inline void DescriptorProto::clear_extension() {
+  _impl_.extension_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension)
+  return _impl_.extension_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >*
+DescriptorProto::mutable_extension() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension)
+  return &_impl_.extension_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::_internal_extension(int index) const {
+  return _impl_.extension_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension)
+  return _internal_extension(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::_internal_add_extension() {
+  return _impl_.extension_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* DescriptorProto::add_extension() {
+  ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* _add = _internal_add_extension();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >&
+DescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
+  return _impl_.extension_;
+}
+
+// repeated .google.protobuf.DescriptorProto nested_type = 3;
+inline int DescriptorProto::_internal_nested_type_size() const {
+  return _impl_.nested_type_.size();
+}
+inline int DescriptorProto::nested_type_size() const {
+  return _internal_nested_type_size();
+}
+inline void DescriptorProto::clear_nested_type() {
+  _impl_.nested_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* DescriptorProto::mutable_nested_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.nested_type)
+  return _impl_.nested_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >*
+DescriptorProto::mutable_nested_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type)
+  return &_impl_.nested_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& DescriptorProto::_internal_nested_type(int index) const {
+  return _impl_.nested_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto& DescriptorProto::nested_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.nested_type)
+  return _internal_nested_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* DescriptorProto::_internal_add_nested_type() {
+  return _impl_.nested_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto* DescriptorProto::add_nested_type() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto* _add = _internal_add_nested_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >&
+DescriptorProto::nested_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
+  return _impl_.nested_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+inline int DescriptorProto::_internal_enum_type_size() const {
+  return _impl_.enum_type_.size();
+}
+inline int DescriptorProto::enum_type_size() const {
+  return _internal_enum_type_size();
+}
+inline void DescriptorProto::clear_enum_type() {
+  _impl_.enum_type_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.enum_type)
+  return _impl_.enum_type_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >*
+DescriptorProto::mutable_enum_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type)
+  return &_impl_.enum_type_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& DescriptorProto::_internal_enum_type(int index) const {
+  return _impl_.enum_type_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.enum_type)
+  return _internal_enum_type(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* DescriptorProto::_internal_add_enum_type() {
+  return _impl_.enum_type_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* DescriptorProto::add_enum_type() {
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* _add = _internal_add_enum_type();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >&
+DescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
+  return _impl_.enum_type_;
+}
+
+// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+inline int DescriptorProto::_internal_extension_range_size() const {
+  return _impl_.extension_range_.size();
+}
+inline int DescriptorProto::extension_range_size() const {
+  return _internal_extension_range_size();
+}
+inline void DescriptorProto::clear_extension_range() {
+  _impl_.extension_range_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension_range)
+  return _impl_.extension_range_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >*
+DescriptorProto::mutable_extension_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range)
+  return &_impl_.extension_range_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& DescriptorProto::_internal_extension_range(int index) const {
+  return _impl_.extension_range_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension_range)
+  return _internal_extension_range(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* DescriptorProto::_internal_add_extension_range() {
+  return _impl_.extension_range_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* _add = _internal_add_extension_range();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >&
+DescriptorProto::extension_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
+  return _impl_.extension_range_;
+}
+
+// repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+inline int DescriptorProto::_internal_oneof_decl_size() const {
+  return _impl_.oneof_decl_.size();
+}
+inline int DescriptorProto::oneof_decl_size() const {
+  return _internal_oneof_decl_size();
+}
+inline void DescriptorProto::clear_oneof_decl() {
+  _impl_.oneof_decl_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.oneof_decl)
+  return _impl_.oneof_decl_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >*
+DescriptorProto::mutable_oneof_decl() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl)
+  return &_impl_.oneof_decl_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& DescriptorProto::_internal_oneof_decl(int index) const {
+  return _impl_.oneof_decl_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.oneof_decl)
+  return _internal_oneof_decl(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* DescriptorProto::_internal_add_oneof_decl() {
+  return _impl_.oneof_decl_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* DescriptorProto::add_oneof_decl() {
+  ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* _add = _internal_add_oneof_decl();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >&
+DescriptorProto::oneof_decl() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
+  return _impl_.oneof_decl_;
+}
+
+// optional .google.protobuf.MessageOptions options = 7;
+inline bool DescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool DescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void DescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MessageOptions& DescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::MessageOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::MessageOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_MessageOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MessageOptions& DescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.options)
+  return _internal_options();
+}
+inline void DescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::MessageOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.DescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MessageOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MessageOptions* DescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::MessageOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
+  return _msg;
+}
+inline void DescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::MessageOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
+}
+
+// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+inline int DescriptorProto::_internal_reserved_range_size() const {
+  return _impl_.reserved_range_.size();
+}
+inline int DescriptorProto::reserved_range_size() const {
+  return _internal_reserved_range_size();
+}
+inline void DescriptorProto::clear_reserved_range() {
+  _impl_.reserved_range_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range)
+  return _impl_.reserved_range_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >*
+DescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range)
+  return &_impl_.reserved_range_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& DescriptorProto::_internal_reserved_range(int index) const {
+  return _impl_.reserved_range_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range)
+  return _internal_reserved_range(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* DescriptorProto::_internal_add_reserved_range() {
+  return _impl_.reserved_range_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() {
+  ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* _add = _internal_add_reserved_range();
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >&
+DescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range)
+  return _impl_.reserved_range_;
+}
+
+// repeated string reserved_name = 10;
+inline int DescriptorProto::_internal_reserved_name_size() const {
+  return _impl_.reserved_name_.size();
+}
+inline int DescriptorProto::reserved_name_size() const {
+  return _internal_reserved_name_size();
+}
+inline void DescriptorProto::clear_reserved_name() {
+  _impl_.reserved_name_.Clear();
+}
+inline std::string* DescriptorProto::add_reserved_name() {
+  std::string* _s = _internal_add_reserved_name();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return _s;
+}
+inline const std::string& DescriptorProto::_internal_reserved_name(int index) const {
+  return _impl_.reserved_name_.Get(index);
+}
+inline const std::string& DescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name)
+  return _internal_reserved_name(index);
+}
+inline std::string* DescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return _impl_.reserved_name_.Mutable(index);
+}
+inline void DescriptorProto::set_reserved_name(int index, const std::string& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, std::string&& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  _impl_.reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline std::string* DescriptorProto::_internal_add_reserved_name() {
+  return _impl_.reserved_name_.Add();
+}
+inline void DescriptorProto::add_reserved_name(const std::string& value) {
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(std::string&& value) {
+  _impl_.reserved_name_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value, size_t size) {
+  _impl_.reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+DescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name)
+  return _impl_.reserved_name_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+DescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name)
+  return &_impl_.reserved_name_;
+}
+
+// -------------------------------------------------------------------
+
+// ExtensionRangeOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int ExtensionRangeOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int ExtensionRangeOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void ExtensionRangeOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ExtensionRangeOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+ExtensionRangeOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ExtensionRangeOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ExtensionRangeOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ExtensionRangeOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ExtensionRangeOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+ExtensionRangeOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ExtensionRangeOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// FieldDescriptorProto
+
+// optional string name = 1;
+inline bool FieldDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void FieldDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& FieldDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.name)
+}
+inline std::string* FieldDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.name)
+}
+
+// optional int32 number = 3;
+inline bool FieldDescriptorProto::_internal_has_number() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000040u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_number() const {
+  return _internal_has_number();
+}
+inline void FieldDescriptorProto::clear_number() {
+  _impl_.number_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000040u;
+}
+inline int32_t FieldDescriptorProto::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t FieldDescriptorProto::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.number)
+  return _internal_number();
+}
+inline void FieldDescriptorProto::_internal_set_number(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  _impl_.number_ = value;
+}
+inline void FieldDescriptorProto::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.number)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+inline bool FieldDescriptorProto::_internal_has_label() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000200u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_label() const {
+  return _internal_has_label();
+}
+inline void FieldDescriptorProto::clear_label() {
+  _impl_.label_ = 1;
+  _impl_._has_bits_[0] &= ~0x00000200u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label FieldDescriptorProto::_internal_label() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label >(_impl_.label_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label FieldDescriptorProto::label() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.label)
+  return _internal_label();
+}
+inline void FieldDescriptorProto::_internal_set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000200u;
+  _impl_.label_ = value;
+}
+inline void FieldDescriptorProto::set_label(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label value) {
+  _internal_set_label(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.label)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+inline bool FieldDescriptorProto::_internal_has_type() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000400u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_type() const {
+  return _internal_has_type();
+}
+inline void FieldDescriptorProto::clear_type() {
+  _impl_.type_ = 1;
+  _impl_._has_bits_[0] &= ~0x00000400u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type FieldDescriptorProto::_internal_type() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type >(_impl_.type_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type FieldDescriptorProto::type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type)
+  return _internal_type();
+}
+inline void FieldDescriptorProto::_internal_set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000400u;
+  _impl_.type_ = value;
+}
+inline void FieldDescriptorProto::set_type(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type value) {
+  _internal_set_type(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type)
+}
+
+// optional string type_name = 6;
+inline bool FieldDescriptorProto::_internal_has_type_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_type_name() const {
+  return _internal_has_type_name();
+}
+inline void FieldDescriptorProto::clear_type_name() {
+  _impl_.type_name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& FieldDescriptorProto::type_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name)
+  return _internal_type_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_type_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.type_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type_name)
+}
+inline std::string* FieldDescriptorProto::mutable_type_name() {
+  std::string* _s = _internal_mutable_type_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_type_name() const {
+  return _impl_.type_name_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_type_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.type_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_type_name() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.type_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_type_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name)
+  if (!_internal_has_type_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.type_name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_name_.IsDefault()) {
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_type_name(std::string* type_name) {
+  if (type_name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.type_name_.SetAllocated(type_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_name_.IsDefault()) {
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name)
+}
+
+// optional string extendee = 2;
+inline bool FieldDescriptorProto::_internal_has_extendee() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_extendee() const {
+  return _internal_has_extendee();
+}
+inline void FieldDescriptorProto::clear_extendee() {
+  _impl_.extendee_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& FieldDescriptorProto::extendee() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee)
+  return _internal_extendee();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_extendee(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.extendee_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.extendee)
+}
+inline std::string* FieldDescriptorProto::mutable_extendee() {
+  std::string* _s = _internal_mutable_extendee();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_extendee() const {
+  return _impl_.extendee_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_extendee(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.extendee_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_extendee() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.extendee_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_extendee() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee)
+  if (!_internal_has_extendee()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.extendee_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.extendee_.IsDefault()) {
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_extendee(std::string* extendee) {
+  if (extendee != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.extendee_.SetAllocated(extendee, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.extendee_.IsDefault()) {
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee)
+}
+
+// optional string default_value = 7;
+inline bool FieldDescriptorProto::_internal_has_default_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_default_value() const {
+  return _internal_has_default_value();
+}
+inline void FieldDescriptorProto::clear_default_value() {
+  _impl_.default_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const std::string& FieldDescriptorProto::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value)
+  return _internal_default_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_default_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000008u;
+ _impl_.default_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.default_value)
+}
+inline std::string* FieldDescriptorProto::mutable_default_value() {
+  std::string* _s = _internal_mutable_default_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_default_value() const {
+  return _impl_.default_value_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_default_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.default_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_default_value() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  return _impl_.default_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value)
+  if (!_internal_has_default_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  auto* p = _impl_.default_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.default_value_.IsDefault()) {
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_default_value(std::string* default_value) {
+  if (default_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.default_value_.SetAllocated(default_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.default_value_.IsDefault()) {
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value)
+}
+
+// optional int32 oneof_index = 9;
+inline bool FieldDescriptorProto::_internal_has_oneof_index() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000080u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_oneof_index() const {
+  return _internal_has_oneof_index();
+}
+inline void FieldDescriptorProto::clear_oneof_index() {
+  _impl_.oneof_index_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000080u;
+}
+inline int32_t FieldDescriptorProto::_internal_oneof_index() const {
+  return _impl_.oneof_index_;
+}
+inline int32_t FieldDescriptorProto::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.oneof_index)
+  return _internal_oneof_index();
+}
+inline void FieldDescriptorProto::_internal_set_oneof_index(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000080u;
+  _impl_.oneof_index_ = value;
+}
+inline void FieldDescriptorProto::set_oneof_index(int32_t value) {
+  _internal_set_oneof_index(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
+}
+
+// optional string json_name = 10;
+inline bool FieldDescriptorProto::_internal_has_json_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_json_name() const {
+  return _internal_has_json_name();
+}
+inline void FieldDescriptorProto::clear_json_name() {
+  _impl_.json_name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline const std::string& FieldDescriptorProto::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
+  return _internal_json_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FieldDescriptorProto::set_json_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000010u;
+ _impl_.json_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline std::string* FieldDescriptorProto::mutable_json_name() {
+  std::string* _s = _internal_mutable_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
+  return _s;
+}
+inline const std::string& FieldDescriptorProto::_internal_json_name() const {
+  return _impl_.json_name_.Get();
+}
+inline void FieldDescriptorProto::_internal_set_json_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.json_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::_internal_mutable_json_name() {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  return _impl_.json_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FieldDescriptorProto::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name)
+  if (!_internal_has_json_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  auto* p = _impl_.json_name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.json_name_.IsDefault()) {
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FieldDescriptorProto::set_allocated_json_name(std::string* json_name) {
+  if (json_name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  _impl_.json_name_.SetAllocated(json_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.json_name_.IsDefault()) {
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+inline bool FieldDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool FieldDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void FieldDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldOptions& FieldDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::FieldOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::FieldOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_FieldOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::FieldOptions& FieldDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.options)
+  return _internal_options();
+}
+inline void FieldDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::FieldOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000020u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000020u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000020u;
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000020u;
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions* FieldDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
+  return _msg;
+}
+inline void FieldDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::FieldOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000020u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000020u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+
+// optional bool proto3_optional = 17;
+inline bool FieldDescriptorProto::_internal_has_proto3_optional() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000100u) != 0;
+  return value;
+}
+inline bool FieldDescriptorProto::has_proto3_optional() const {
+  return _internal_has_proto3_optional();
+}
+inline void FieldDescriptorProto::clear_proto3_optional() {
+  _impl_.proto3_optional_ = false;
+  _impl_._has_bits_[0] &= ~0x00000100u;
+}
+inline bool FieldDescriptorProto::_internal_proto3_optional() const {
+  return _impl_.proto3_optional_;
+}
+inline bool FieldDescriptorProto::proto3_optional() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.proto3_optional)
+  return _internal_proto3_optional();
+}
+inline void FieldDescriptorProto::_internal_set_proto3_optional(bool value) {
+  _impl_._has_bits_[0] |= 0x00000100u;
+  _impl_.proto3_optional_ = value;
+}
+inline void FieldDescriptorProto::set_proto3_optional(bool value) {
+  _internal_set_proto3_optional(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.proto3_optional)
+}
+
+// -------------------------------------------------------------------
+
+// OneofDescriptorProto
+
+// optional string name = 1;
+inline bool OneofDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool OneofDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void OneofDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& OneofDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void OneofDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.OneofDescriptorProto.name)
+}
+inline std::string* OneofDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name)
+  return _s;
+}
+inline const std::string& OneofDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void OneofDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* OneofDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* OneofDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void OneofDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
+}
+
+// optional .google.protobuf.OneofOptions options = 2;
+inline bool OneofDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool OneofDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void OneofDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofOptions& OneofDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::OneofOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::OneofOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_OneofOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::OneofOptions& OneofDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.options)
+  return _internal_options();
+}
+inline void OneofDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::OneofOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::OneofOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::OneofOptions* OneofDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::OneofOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.options)
+  return _msg;
+}
+inline void OneofDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::OneofOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// EnumDescriptorProto_EnumReservedRange
+
+// optional int32 start = 1;
+inline bool EnumDescriptorProto_EnumReservedRange::_internal_has_start() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumDescriptorProto_EnumReservedRange::has_start() const {
+  return _internal_has_start();
+}
+inline void EnumDescriptorProto_EnumReservedRange::clear_start() {
+  _impl_.start_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::_internal_start() const {
+  return _impl_.start_;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.EnumReservedRange.start)
+  return _internal_start();
+}
+inline void EnumDescriptorProto_EnumReservedRange::_internal_set_start(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.start_ = value;
+}
+inline void EnumDescriptorProto_EnumReservedRange::set_start(int32_t value) {
+  _internal_set_start(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.EnumReservedRange.start)
+}
+
+// optional int32 end = 2;
+inline bool EnumDescriptorProto_EnumReservedRange::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool EnumDescriptorProto_EnumReservedRange::has_end() const {
+  return _internal_has_end();
+}
+inline void EnumDescriptorProto_EnumReservedRange::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t EnumDescriptorProto_EnumReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.EnumReservedRange.end)
+  return _internal_end();
+}
+inline void EnumDescriptorProto_EnumReservedRange::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.end_ = value;
+}
+inline void EnumDescriptorProto_EnumReservedRange::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.EnumReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// EnumDescriptorProto
+
+// optional string name = 1;
+inline bool EnumDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void EnumDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& EnumDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void EnumDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.name)
+}
+inline std::string* EnumDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name)
+  return _s;
+}
+inline const std::string& EnumDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void EnumDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* EnumDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* EnumDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void EnumDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.name)
+}
+
+// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+inline int EnumDescriptorProto::_internal_value_size() const {
+  return _impl_.value_.size();
+}
+inline int EnumDescriptorProto::value_size() const {
+  return _internal_value_size();
+}
+inline void EnumDescriptorProto::clear_value() {
+  _impl_.value_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.value)
+  return _impl_.value_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >*
+EnumDescriptorProto::mutable_value() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value)
+  return &_impl_.value_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& EnumDescriptorProto::_internal_value(int index) const {
+  return _impl_.value_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.value)
+  return _internal_value(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* EnumDescriptorProto::_internal_add_value() {
+  return _impl_.value_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
+  ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* _add = _internal_add_value();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >&
+EnumDescriptorProto::value() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
+  return _impl_.value_;
+}
+
+// optional .google.protobuf.EnumOptions options = 3;
+inline bool EnumDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool EnumDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void EnumDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumOptions& EnumDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::EnumOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::EnumOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_EnumOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumOptions& EnumDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.options)
+  return _internal_options();
+}
+inline void EnumDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::EnumOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumOptions* EnumDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::EnumOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
+  return _msg;
+}
+inline void EnumDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
+
+// repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+inline int EnumDescriptorProto::_internal_reserved_range_size() const {
+  return _impl_.reserved_range_.size();
+}
+inline int EnumDescriptorProto::reserved_range_size() const {
+  return _internal_reserved_range_size();
+}
+inline void EnumDescriptorProto::clear_reserved_range() {
+  _impl_.reserved_range_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* EnumDescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _impl_.reserved_range_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >*
+EnumDescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.reserved_range)
+  return &_impl_.reserved_range_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& EnumDescriptorProto::_internal_reserved_range(int index) const {
+  return _impl_.reserved_range_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange& EnumDescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _internal_reserved_range(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* EnumDescriptorProto::_internal_add_reserved_range() {
+  return _impl_.reserved_range_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* EnumDescriptorProto::add_reserved_range() {
+  ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* _add = _internal_add_reserved_range();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >&
+EnumDescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.reserved_range)
+  return _impl_.reserved_range_;
+}
+
+// repeated string reserved_name = 5;
+inline int EnumDescriptorProto::_internal_reserved_name_size() const {
+  return _impl_.reserved_name_.size();
+}
+inline int EnumDescriptorProto::reserved_name_size() const {
+  return _internal_reserved_name_size();
+}
+inline void EnumDescriptorProto::clear_reserved_name() {
+  _impl_.reserved_name_.Clear();
+}
+inline std::string* EnumDescriptorProto::add_reserved_name() {
+  std::string* _s = _internal_add_reserved_name();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _s;
+}
+inline const std::string& EnumDescriptorProto::_internal_reserved_name(int index) const {
+  return _impl_.reserved_name_.Get(index);
+}
+inline const std::string& EnumDescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _internal_reserved_name(index);
+}
+inline std::string* EnumDescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _impl_.reserved_name_.Mutable(index);
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, const std::string& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, std::string&& value) {
+  _impl_.reserved_name_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  _impl_.reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline std::string* EnumDescriptorProto::_internal_add_reserved_name() {
+  return _impl_.reserved_name_.Add();
+}
+inline void EnumDescriptorProto::add_reserved_name(const std::string& value) {
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::add_reserved_name(std::string&& value) {
+  _impl_.reserved_name_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::add_reserved_name(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline void EnumDescriptorProto::add_reserved_name(const char* value, size_t size) {
+  _impl_.reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.EnumDescriptorProto.reserved_name)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+EnumDescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.reserved_name)
+  return _impl_.reserved_name_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+EnumDescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.reserved_name)
+  return &_impl_.reserved_name_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumValueDescriptorProto
+
+// optional string name = 1;
+inline bool EnumValueDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumValueDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void EnumValueDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& EnumValueDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void EnumValueDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.name)
+}
+inline std::string* EnumValueDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name)
+  return _s;
+}
+inline const std::string& EnumValueDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void EnumValueDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* EnumValueDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* EnumValueDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void EnumValueDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.name)
+}
+
+// optional int32 number = 2;
+inline bool EnumValueDescriptorProto::_internal_has_number() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool EnumValueDescriptorProto::has_number() const {
+  return _internal_has_number();
+}
+inline void EnumValueDescriptorProto::clear_number() {
+  _impl_.number_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t EnumValueDescriptorProto::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t EnumValueDescriptorProto::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.number)
+  return _internal_number();
+}
+inline void EnumValueDescriptorProto::_internal_set_number(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.number_ = value;
+}
+inline void EnumValueDescriptorProto::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.number)
+}
+
+// optional .google.protobuf.EnumValueOptions options = 3;
+inline bool EnumValueDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool EnumValueDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void EnumValueDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& EnumValueDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_EnumValueOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& EnumValueDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.options)
+  return _internal_options();
+}
+inline void EnumValueDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValueOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
+  return _msg;
+}
+inline void EnumValueDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::EnumValueOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// ServiceDescriptorProto
+
+// optional string name = 1;
+inline bool ServiceDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool ServiceDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void ServiceDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& ServiceDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void ServiceDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.ServiceDescriptorProto.name)
+}
+inline std::string* ServiceDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name)
+  return _s;
+}
+inline const std::string& ServiceDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void ServiceDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* ServiceDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* ServiceDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void ServiceDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.name)
+}
+
+// repeated .google.protobuf.MethodDescriptorProto method = 2;
+inline int ServiceDescriptorProto::_internal_method_size() const {
+  return _impl_.method_.size();
+}
+inline int ServiceDescriptorProto::method_size() const {
+  return _internal_method_size();
+}
+inline void ServiceDescriptorProto::clear_method() {
+  _impl_.method_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.method)
+  return _impl_.method_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >*
+ServiceDescriptorProto::mutable_method() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method)
+  return &_impl_.method_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& ServiceDescriptorProto::_internal_method(int index) const {
+  return _impl_.method_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.method)
+  return _internal_method(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* ServiceDescriptorProto::_internal_add_method() {
+  return _impl_.method_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
+  ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* _add = _internal_add_method();
+  // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >&
+ServiceDescriptorProto::method() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
+  return _impl_.method_;
+}
+
+// optional .google.protobuf.ServiceOptions options = 3;
+inline bool ServiceDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool ServiceDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void ServiceDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& ServiceDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::ServiceOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::ServiceOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_ServiceOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& ServiceDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.options)
+  return _internal_options();
+}
+inline void ServiceDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::ServiceOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ServiceOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ServiceOptions* ServiceDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::ServiceOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
+  return _msg;
+}
+inline void ServiceDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::ServiceOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
+
+// -------------------------------------------------------------------
+
+// MethodDescriptorProto
+
+// optional string name = 1;
+inline bool MethodDescriptorProto::_internal_has_name() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_name() const {
+  return _internal_has_name();
+}
+inline void MethodDescriptorProto::clear_name() {
+  _impl_.name_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& MethodDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void MethodDescriptorProto::set_name(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.name)
+}
+inline std::string* MethodDescriptorProto::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name)
+  return _s;
+}
+inline const std::string& MethodDescriptorProto::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void MethodDescriptorProto::_internal_set_name(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::_internal_mutable_name() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name)
+  if (!_internal_has_name()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void MethodDescriptorProto::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.name)
+}
+
+// optional string input_type = 2;
+inline bool MethodDescriptorProto::_internal_has_input_type() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_input_type() const {
+  return _internal_has_input_type();
+}
+inline void MethodDescriptorProto::clear_input_type() {
+  _impl_.input_type_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& MethodDescriptorProto::input_type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type)
+  return _internal_input_type();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void MethodDescriptorProto::set_input_type(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.input_type_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.input_type)
+}
+inline std::string* MethodDescriptorProto::mutable_input_type() {
+  std::string* _s = _internal_mutable_input_type();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type)
+  return _s;
+}
+inline const std::string& MethodDescriptorProto::_internal_input_type() const {
+  return _impl_.input_type_.Get();
+}
+inline void MethodDescriptorProto::_internal_set_input_type(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.input_type_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::_internal_mutable_input_type() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.input_type_.Mutable(GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::release_input_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type)
+  if (!_internal_has_input_type()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.input_type_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.input_type_.IsDefault()) {
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void MethodDescriptorProto::set_allocated_input_type(std::string* input_type) {
+  if (input_type != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.input_type_.SetAllocated(input_type, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.input_type_.IsDefault()) {
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type)
+}
+
+// optional string output_type = 3;
+inline bool MethodDescriptorProto::_internal_has_output_type() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_output_type() const {
+  return _internal_has_output_type();
+}
+inline void MethodDescriptorProto::clear_output_type() {
+  _impl_.output_type_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& MethodDescriptorProto::output_type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type)
+  return _internal_output_type();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void MethodDescriptorProto::set_output_type(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.output_type_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.output_type)
+}
+inline std::string* MethodDescriptorProto::mutable_output_type() {
+  std::string* _s = _internal_mutable_output_type();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type)
+  return _s;
+}
+inline const std::string& MethodDescriptorProto::_internal_output_type() const {
+  return _impl_.output_type_.Get();
+}
+inline void MethodDescriptorProto::_internal_set_output_type(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.output_type_.Set(value, GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::_internal_mutable_output_type() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.output_type_.Mutable(GetArenaForAllocation());
+}
+inline std::string* MethodDescriptorProto::release_output_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type)
+  if (!_internal_has_output_type()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.output_type_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.output_type_.IsDefault()) {
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void MethodDescriptorProto::set_allocated_output_type(std::string* output_type) {
+  if (output_type != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.output_type_.SetAllocated(output_type, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.output_type_.IsDefault()) {
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type)
+}
+
+// optional .google.protobuf.MethodOptions options = 4;
+inline bool MethodDescriptorProto::_internal_has_options() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  PROTOBUF_ASSUME(!value || _impl_.options_ != nullptr);
+  return value;
+}
+inline bool MethodDescriptorProto::has_options() const {
+  return _internal_has_options();
+}
+inline void MethodDescriptorProto::clear_options() {
+  if (_impl_.options_ != nullptr) _impl_.options_->Clear();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodOptions& MethodDescriptorProto::_internal_options() const {
+  const ::PROTOBUF_NAMESPACE_ID::MethodOptions* p = _impl_.options_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::MethodOptions&>(
+      ::PROTOBUF_NAMESPACE_ID::_MethodOptions_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::MethodOptions& MethodDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.options)
+  return _internal_options();
+}
+inline void MethodDescriptorProto::unsafe_arena_set_allocated_options(
+    ::PROTOBUF_NAMESPACE_ID::MethodOptions* options) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.options_);
+  }
+  _impl_.options_ = options;
+  if (options) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::release_options() {
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::unsafe_arena_release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options)
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* temp = _impl_.options_;
+  _impl_.options_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::_internal_mutable_options() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  if (_impl_.options_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::MethodOptions>(GetArenaForAllocation());
+    _impl_.options_ = p;
+  }
+  return _impl_.options_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions* MethodDescriptorProto::mutable_options() {
+  ::PROTOBUF_NAMESPACE_ID::MethodOptions* _msg = _internal_mutable_options();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
+  return _msg;
+}
+inline void MethodDescriptorProto::set_allocated_options(::PROTOBUF_NAMESPACE_ID::MethodOptions* options) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete _impl_.options_;
+  }
+  if (options) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(options);
+    if (message_arena != submessage_arena) {
+      options = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, options, submessage_arena);
+    }
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.options_ = options;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+
+// optional bool client_streaming = 5 [default = false];
+inline bool MethodDescriptorProto::_internal_has_client_streaming() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_client_streaming() const {
+  return _internal_has_client_streaming();
+}
+inline void MethodDescriptorProto::clear_client_streaming() {
+  _impl_.client_streaming_ = false;
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline bool MethodDescriptorProto::_internal_client_streaming() const {
+  return _impl_.client_streaming_;
+}
+inline bool MethodDescriptorProto::client_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming)
+  return _internal_client_streaming();
+}
+inline void MethodDescriptorProto::_internal_set_client_streaming(bool value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.client_streaming_ = value;
+}
+inline void MethodDescriptorProto::set_client_streaming(bool value) {
+  _internal_set_client_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming)
+}
+
+// optional bool server_streaming = 6 [default = false];
+inline bool MethodDescriptorProto::_internal_has_server_streaming() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool MethodDescriptorProto::has_server_streaming() const {
+  return _internal_has_server_streaming();
+}
+inline void MethodDescriptorProto::clear_server_streaming() {
+  _impl_.server_streaming_ = false;
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline bool MethodDescriptorProto::_internal_server_streaming() const {
+  return _impl_.server_streaming_;
+}
+inline bool MethodDescriptorProto::server_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming)
+  return _internal_server_streaming();
+}
+inline void MethodDescriptorProto::_internal_set_server_streaming(bool value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.server_streaming_ = value;
+}
+inline void MethodDescriptorProto::set_server_streaming(bool value) {
+  _internal_set_server_streaming(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming)
+}
+
+// -------------------------------------------------------------------
+
+// FileOptions
+
+// optional string java_package = 1;
+inline bool FileOptions::_internal_has_java_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_package() const {
+  return _internal_has_java_package();
+}
+inline void FileOptions::clear_java_package() {
+  _impl_.java_package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& FileOptions::java_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package)
+  return _internal_java_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_java_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.java_package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_package)
+}
+inline std::string* FileOptions::mutable_java_package() {
+  std::string* _s = _internal_mutable_java_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_java_package() const {
+  return _impl_.java_package_.Get();
+}
+inline void FileOptions::_internal_set_java_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.java_package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_java_package() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.java_package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_java_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package)
+  if (!_internal_has_java_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.java_package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_package_.IsDefault()) {
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_java_package(std::string* java_package) {
+  if (java_package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.java_package_.SetAllocated(java_package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_package_.IsDefault()) {
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package)
+}
+
+// optional string java_outer_classname = 8;
+inline bool FileOptions::_internal_has_java_outer_classname() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_outer_classname() const {
+  return _internal_has_java_outer_classname();
+}
+inline void FileOptions::clear_java_outer_classname() {
+  _impl_.java_outer_classname_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& FileOptions::java_outer_classname() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname)
+  return _internal_java_outer_classname();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_java_outer_classname(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.java_outer_classname_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_outer_classname)
+}
+inline std::string* FileOptions::mutable_java_outer_classname() {
+  std::string* _s = _internal_mutable_java_outer_classname();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_java_outer_classname() const {
+  return _impl_.java_outer_classname_.Get();
+}
+inline void FileOptions::_internal_set_java_outer_classname(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.java_outer_classname_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_java_outer_classname() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.java_outer_classname_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_java_outer_classname() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname)
+  if (!_internal_has_java_outer_classname()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.java_outer_classname_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_outer_classname_.IsDefault()) {
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_java_outer_classname(std::string* java_outer_classname) {
+  if (java_outer_classname != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.java_outer_classname_.SetAllocated(java_outer_classname, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.java_outer_classname_.IsDefault()) {
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname)
+}
+
+// optional bool java_multiple_files = 10 [default = false];
+inline bool FileOptions::_internal_has_java_multiple_files() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000400u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_multiple_files() const {
+  return _internal_has_java_multiple_files();
+}
+inline void FileOptions::clear_java_multiple_files() {
+  _impl_.java_multiple_files_ = false;
+  _impl_._has_bits_[0] &= ~0x00000400u;
+}
+inline bool FileOptions::_internal_java_multiple_files() const {
+  return _impl_.java_multiple_files_;
+}
+inline bool FileOptions::java_multiple_files() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_multiple_files)
+  return _internal_java_multiple_files();
+}
+inline void FileOptions::_internal_set_java_multiple_files(bool value) {
+  _impl_._has_bits_[0] |= 0x00000400u;
+  _impl_.java_multiple_files_ = value;
+}
+inline void FileOptions::set_java_multiple_files(bool value) {
+  _internal_set_java_multiple_files(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_multiple_files)
+}
+
+// optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+inline bool FileOptions::_internal_has_java_generate_equals_and_hash() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000800u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_generate_equals_and_hash() const {
+  return _internal_has_java_generate_equals_and_hash();
+}
+inline void FileOptions::clear_java_generate_equals_and_hash() {
+  _impl_.java_generate_equals_and_hash_ = false;
+  _impl_._has_bits_[0] &= ~0x00000800u;
+}
+inline bool FileOptions::_internal_java_generate_equals_and_hash() const {
+  return _impl_.java_generate_equals_and_hash_;
+}
+inline bool FileOptions::java_generate_equals_and_hash() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generate_equals_and_hash)
+  return _internal_java_generate_equals_and_hash();
+}
+inline void FileOptions::_internal_set_java_generate_equals_and_hash(bool value) {
+  _impl_._has_bits_[0] |= 0x00000800u;
+  _impl_.java_generate_equals_and_hash_ = value;
+}
+inline void FileOptions::set_java_generate_equals_and_hash(bool value) {
+  _internal_set_java_generate_equals_and_hash(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generate_equals_and_hash)
+}
+
+// optional bool java_string_check_utf8 = 27 [default = false];
+inline bool FileOptions::_internal_has_java_string_check_utf8() const {
+  bool value = (_impl_._has_bits_[0] & 0x00001000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_string_check_utf8() const {
+  return _internal_has_java_string_check_utf8();
+}
+inline void FileOptions::clear_java_string_check_utf8() {
+  _impl_.java_string_check_utf8_ = false;
+  _impl_._has_bits_[0] &= ~0x00001000u;
+}
+inline bool FileOptions::_internal_java_string_check_utf8() const {
+  return _impl_.java_string_check_utf8_;
+}
+inline bool FileOptions::java_string_check_utf8() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_string_check_utf8)
+  return _internal_java_string_check_utf8();
+}
+inline void FileOptions::_internal_set_java_string_check_utf8(bool value) {
+  _impl_._has_bits_[0] |= 0x00001000u;
+  _impl_.java_string_check_utf8_ = value;
+}
+inline void FileOptions::set_java_string_check_utf8(bool value) {
+  _internal_set_java_string_check_utf8(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_string_check_utf8)
+}
+
+// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+inline bool FileOptions::_internal_has_optimize_for() const {
+  bool value = (_impl_._has_bits_[0] & 0x00040000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_optimize_for() const {
+  return _internal_has_optimize_for();
+}
+inline void FileOptions::clear_optimize_for() {
+  _impl_.optimize_for_ = 1;
+  _impl_._has_bits_[0] &= ~0x00040000u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode FileOptions::_internal_optimize_for() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode >(_impl_.optimize_for_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode FileOptions::optimize_for() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.optimize_for)
+  return _internal_optimize_for();
+}
+inline void FileOptions::_internal_set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00040000u;
+  _impl_.optimize_for_ = value;
+}
+inline void FileOptions::set_optimize_for(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode value) {
+  _internal_set_optimize_for(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.optimize_for)
+}
+
+// optional string go_package = 11;
+inline bool FileOptions::_internal_has_go_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FileOptions::has_go_package() const {
+  return _internal_has_go_package();
+}
+inline void FileOptions::clear_go_package() {
+  _impl_.go_package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& FileOptions::go_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.go_package)
+  return _internal_go_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_go_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.go_package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package)
+}
+inline std::string* FileOptions::mutable_go_package() {
+  std::string* _s = _internal_mutable_go_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_go_package() const {
+  return _impl_.go_package_.Get();
+}
+inline void FileOptions::_internal_set_go_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.go_package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_go_package() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.go_package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_go_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package)
+  if (!_internal_has_go_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.go_package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.go_package_.IsDefault()) {
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_go_package(std::string* go_package) {
+  if (go_package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.go_package_.SetAllocated(go_package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.go_package_.IsDefault()) {
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package)
+}
+
+// optional bool cc_generic_services = 16 [default = false];
+inline bool FileOptions::_internal_has_cc_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00002000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_cc_generic_services() const {
+  return _internal_has_cc_generic_services();
+}
+inline void FileOptions::clear_cc_generic_services() {
+  _impl_.cc_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00002000u;
+}
+inline bool FileOptions::_internal_cc_generic_services() const {
+  return _impl_.cc_generic_services_;
+}
+inline bool FileOptions::cc_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_generic_services)
+  return _internal_cc_generic_services();
+}
+inline void FileOptions::_internal_set_cc_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00002000u;
+  _impl_.cc_generic_services_ = value;
+}
+inline void FileOptions::set_cc_generic_services(bool value) {
+  _internal_set_cc_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_generic_services)
+}
+
+// optional bool java_generic_services = 17 [default = false];
+inline bool FileOptions::_internal_has_java_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00004000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_java_generic_services() const {
+  return _internal_has_java_generic_services();
+}
+inline void FileOptions::clear_java_generic_services() {
+  _impl_.java_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00004000u;
+}
+inline bool FileOptions::_internal_java_generic_services() const {
+  return _impl_.java_generic_services_;
+}
+inline bool FileOptions::java_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generic_services)
+  return _internal_java_generic_services();
+}
+inline void FileOptions::_internal_set_java_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00004000u;
+  _impl_.java_generic_services_ = value;
+}
+inline void FileOptions::set_java_generic_services(bool value) {
+  _internal_set_java_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generic_services)
+}
+
+// optional bool py_generic_services = 18 [default = false];
+inline bool FileOptions::_internal_has_py_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00008000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_py_generic_services() const {
+  return _internal_has_py_generic_services();
+}
+inline void FileOptions::clear_py_generic_services() {
+  _impl_.py_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00008000u;
+}
+inline bool FileOptions::_internal_py_generic_services() const {
+  return _impl_.py_generic_services_;
+}
+inline bool FileOptions::py_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.py_generic_services)
+  return _internal_py_generic_services();
+}
+inline void FileOptions::_internal_set_py_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00008000u;
+  _impl_.py_generic_services_ = value;
+}
+inline void FileOptions::set_py_generic_services(bool value) {
+  _internal_set_py_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
+}
+
+// optional bool php_generic_services = 42 [default = false];
+inline bool FileOptions::_internal_has_php_generic_services() const {
+  bool value = (_impl_._has_bits_[0] & 0x00010000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_generic_services() const {
+  return _internal_has_php_generic_services();
+}
+inline void FileOptions::clear_php_generic_services() {
+  _impl_.php_generic_services_ = false;
+  _impl_._has_bits_[0] &= ~0x00010000u;
+}
+inline bool FileOptions::_internal_php_generic_services() const {
+  return _impl_.php_generic_services_;
+}
+inline bool FileOptions::php_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_generic_services)
+  return _internal_php_generic_services();
+}
+inline void FileOptions::_internal_set_php_generic_services(bool value) {
+  _impl_._has_bits_[0] |= 0x00010000u;
+  _impl_.php_generic_services_ = value;
+}
+inline void FileOptions::set_php_generic_services(bool value) {
+  _internal_set_php_generic_services(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_generic_services)
+}
+
+// optional bool deprecated = 23 [default = false];
+inline bool FileOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00020000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void FileOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00020000u;
+}
+inline bool FileOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool FileOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void FileOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00020000u;
+  _impl_.deprecated_ = value;
+}
+inline void FileOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.deprecated)
+}
+
+// optional bool cc_enable_arenas = 31 [default = true];
+inline bool FileOptions::_internal_has_cc_enable_arenas() const {
+  bool value = (_impl_._has_bits_[0] & 0x00080000u) != 0;
+  return value;
+}
+inline bool FileOptions::has_cc_enable_arenas() const {
+  return _internal_has_cc_enable_arenas();
+}
+inline void FileOptions::clear_cc_enable_arenas() {
+  _impl_.cc_enable_arenas_ = true;
+  _impl_._has_bits_[0] &= ~0x00080000u;
+}
+inline bool FileOptions::_internal_cc_enable_arenas() const {
+  return _impl_.cc_enable_arenas_;
+}
+inline bool FileOptions::cc_enable_arenas() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_enable_arenas)
+  return _internal_cc_enable_arenas();
+}
+inline void FileOptions::_internal_set_cc_enable_arenas(bool value) {
+  _impl_._has_bits_[0] |= 0x00080000u;
+  _impl_.cc_enable_arenas_ = value;
+}
+inline void FileOptions::set_cc_enable_arenas(bool value) {
+  _internal_set_cc_enable_arenas(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_enable_arenas)
+}
+
+// optional string objc_class_prefix = 36;
+inline bool FileOptions::_internal_has_objc_class_prefix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool FileOptions::has_objc_class_prefix() const {
+  return _internal_has_objc_class_prefix();
+}
+inline void FileOptions::clear_objc_class_prefix() {
+  _impl_.objc_class_prefix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline const std::string& FileOptions::objc_class_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.objc_class_prefix)
+  return _internal_objc_class_prefix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_objc_class_prefix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000008u;
+ _impl_.objc_class_prefix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline std::string* FileOptions::mutable_objc_class_prefix() {
+  std::string* _s = _internal_mutable_objc_class_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.objc_class_prefix)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_objc_class_prefix() const {
+  return _impl_.objc_class_prefix_.Get();
+}
+inline void FileOptions::_internal_set_objc_class_prefix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.objc_class_prefix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_objc_class_prefix() {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  return _impl_.objc_class_prefix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_objc_class_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix)
+  if (!_internal_has_objc_class_prefix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000008u;
+  auto* p = _impl_.objc_class_prefix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.objc_class_prefix_.IsDefault()) {
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_objc_class_prefix(std::string* objc_class_prefix) {
+  if (objc_class_prefix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000008u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000008u;
+  }
+  _impl_.objc_class_prefix_.SetAllocated(objc_class_prefix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.objc_class_prefix_.IsDefault()) {
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix)
+}
+
+// optional string csharp_namespace = 37;
+inline bool FileOptions::_internal_has_csharp_namespace() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FileOptions::has_csharp_namespace() const {
+  return _internal_has_csharp_namespace();
+}
+inline void FileOptions::clear_csharp_namespace() {
+  _impl_.csharp_namespace_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline const std::string& FileOptions::csharp_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.csharp_namespace)
+  return _internal_csharp_namespace();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_csharp_namespace(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000010u;
+ _impl_.csharp_namespace_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.csharp_namespace)
+}
+inline std::string* FileOptions::mutable_csharp_namespace() {
+  std::string* _s = _internal_mutable_csharp_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.csharp_namespace)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_csharp_namespace() const {
+  return _impl_.csharp_namespace_.Get();
+}
+inline void FileOptions::_internal_set_csharp_namespace(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.csharp_namespace_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_csharp_namespace() {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  return _impl_.csharp_namespace_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_csharp_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace)
+  if (!_internal_has_csharp_namespace()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000010u;
+  auto* p = _impl_.csharp_namespace_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.csharp_namespace_.IsDefault()) {
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_csharp_namespace(std::string* csharp_namespace) {
+  if (csharp_namespace != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000010u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000010u;
+  }
+  _impl_.csharp_namespace_.SetAllocated(csharp_namespace, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.csharp_namespace_.IsDefault()) {
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace)
+}
+
+// optional string swift_prefix = 39;
+inline bool FileOptions::_internal_has_swift_prefix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool FileOptions::has_swift_prefix() const {
+  return _internal_has_swift_prefix();
+}
+inline void FileOptions::clear_swift_prefix() {
+  _impl_.swift_prefix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline const std::string& FileOptions::swift_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.swift_prefix)
+  return _internal_swift_prefix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_swift_prefix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000020u;
+ _impl_.swift_prefix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.swift_prefix)
+}
+inline std::string* FileOptions::mutable_swift_prefix() {
+  std::string* _s = _internal_mutable_swift_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.swift_prefix)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_swift_prefix() const {
+  return _impl_.swift_prefix_.Get();
+}
+inline void FileOptions::_internal_set_swift_prefix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.swift_prefix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_swift_prefix() {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  return _impl_.swift_prefix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_swift_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.swift_prefix)
+  if (!_internal_has_swift_prefix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000020u;
+  auto* p = _impl_.swift_prefix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.swift_prefix_.IsDefault()) {
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_swift_prefix(std::string* swift_prefix) {
+  if (swift_prefix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000020u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000020u;
+  }
+  _impl_.swift_prefix_.SetAllocated(swift_prefix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.swift_prefix_.IsDefault()) {
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.swift_prefix)
+}
+
+// optional string php_class_prefix = 40;
+inline bool FileOptions::_internal_has_php_class_prefix() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000040u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_class_prefix() const {
+  return _internal_has_php_class_prefix();
+}
+inline void FileOptions::clear_php_class_prefix() {
+  _impl_.php_class_prefix_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000040u;
+}
+inline const std::string& FileOptions::php_class_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_class_prefix)
+  return _internal_php_class_prefix();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_php_class_prefix(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000040u;
+ _impl_.php_class_prefix_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_class_prefix)
+}
+inline std::string* FileOptions::mutable_php_class_prefix() {
+  std::string* _s = _internal_mutable_php_class_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.php_class_prefix)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_php_class_prefix() const {
+  return _impl_.php_class_prefix_.Get();
+}
+inline void FileOptions::_internal_set_php_class_prefix(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  _impl_.php_class_prefix_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_php_class_prefix() {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  return _impl_.php_class_prefix_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_php_class_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.php_class_prefix)
+  if (!_internal_has_php_class_prefix()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000040u;
+  auto* p = _impl_.php_class_prefix_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_class_prefix_.IsDefault()) {
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_php_class_prefix(std::string* php_class_prefix) {
+  if (php_class_prefix != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000040u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000040u;
+  }
+  _impl_.php_class_prefix_.SetAllocated(php_class_prefix, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_class_prefix_.IsDefault()) {
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.php_class_prefix)
+}
+
+// optional string php_namespace = 41;
+inline bool FileOptions::_internal_has_php_namespace() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000080u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_namespace() const {
+  return _internal_has_php_namespace();
+}
+inline void FileOptions::clear_php_namespace() {
+  _impl_.php_namespace_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000080u;
+}
+inline const std::string& FileOptions::php_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_namespace)
+  return _internal_php_namespace();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_php_namespace(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000080u;
+ _impl_.php_namespace_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_namespace)
+}
+inline std::string* FileOptions::mutable_php_namespace() {
+  std::string* _s = _internal_mutable_php_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.php_namespace)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_php_namespace() const {
+  return _impl_.php_namespace_.Get();
+}
+inline void FileOptions::_internal_set_php_namespace(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000080u;
+  _impl_.php_namespace_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_php_namespace() {
+  _impl_._has_bits_[0] |= 0x00000080u;
+  return _impl_.php_namespace_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_php_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.php_namespace)
+  if (!_internal_has_php_namespace()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000080u;
+  auto* p = _impl_.php_namespace_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_namespace_.IsDefault()) {
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_php_namespace(std::string* php_namespace) {
+  if (php_namespace != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000080u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000080u;
+  }
+  _impl_.php_namespace_.SetAllocated(php_namespace, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_namespace_.IsDefault()) {
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.php_namespace)
+}
+
+// optional string php_metadata_namespace = 44;
+inline bool FileOptions::_internal_has_php_metadata_namespace() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000100u) != 0;
+  return value;
+}
+inline bool FileOptions::has_php_metadata_namespace() const {
+  return _internal_has_php_metadata_namespace();
+}
+inline void FileOptions::clear_php_metadata_namespace() {
+  _impl_.php_metadata_namespace_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000100u;
+}
+inline const std::string& FileOptions::php_metadata_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_metadata_namespace)
+  return _internal_php_metadata_namespace();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_php_metadata_namespace(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000100u;
+ _impl_.php_metadata_namespace_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_metadata_namespace)
+}
+inline std::string* FileOptions::mutable_php_metadata_namespace() {
+  std::string* _s = _internal_mutable_php_metadata_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.php_metadata_namespace)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_php_metadata_namespace() const {
+  return _impl_.php_metadata_namespace_.Get();
+}
+inline void FileOptions::_internal_set_php_metadata_namespace(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000100u;
+  _impl_.php_metadata_namespace_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_php_metadata_namespace() {
+  _impl_._has_bits_[0] |= 0x00000100u;
+  return _impl_.php_metadata_namespace_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_php_metadata_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.php_metadata_namespace)
+  if (!_internal_has_php_metadata_namespace()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000100u;
+  auto* p = _impl_.php_metadata_namespace_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_metadata_namespace_.IsDefault()) {
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_php_metadata_namespace(std::string* php_metadata_namespace) {
+  if (php_metadata_namespace != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000100u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000100u;
+  }
+  _impl_.php_metadata_namespace_.SetAllocated(php_metadata_namespace, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.php_metadata_namespace_.IsDefault()) {
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.php_metadata_namespace)
+}
+
+// optional string ruby_package = 45;
+inline bool FileOptions::_internal_has_ruby_package() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000200u) != 0;
+  return value;
+}
+inline bool FileOptions::has_ruby_package() const {
+  return _internal_has_ruby_package();
+}
+inline void FileOptions::clear_ruby_package() {
+  _impl_.ruby_package_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000200u;
+}
+inline const std::string& FileOptions::ruby_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.ruby_package)
+  return _internal_ruby_package();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void FileOptions::set_ruby_package(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000200u;
+ _impl_.ruby_package_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.ruby_package)
+}
+inline std::string* FileOptions::mutable_ruby_package() {
+  std::string* _s = _internal_mutable_ruby_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.ruby_package)
+  return _s;
+}
+inline const std::string& FileOptions::_internal_ruby_package() const {
+  return _impl_.ruby_package_.Get();
+}
+inline void FileOptions::_internal_set_ruby_package(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000200u;
+  _impl_.ruby_package_.Set(value, GetArenaForAllocation());
+}
+inline std::string* FileOptions::_internal_mutable_ruby_package() {
+  _impl_._has_bits_[0] |= 0x00000200u;
+  return _impl_.ruby_package_.Mutable(GetArenaForAllocation());
+}
+inline std::string* FileOptions::release_ruby_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.ruby_package)
+  if (!_internal_has_ruby_package()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000200u;
+  auto* p = _impl_.ruby_package_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.ruby_package_.IsDefault()) {
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void FileOptions::set_allocated_ruby_package(std::string* ruby_package) {
+  if (ruby_package != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000200u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000200u;
+  }
+  _impl_.ruby_package_.SetAllocated(ruby_package, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.ruby_package_.IsDefault()) {
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.ruby_package)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int FileOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int FileOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void FileOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+FileOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FileOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FileOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FileOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+FileOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// MessageOptions
+
+// optional bool message_set_wire_format = 1 [default = false];
+inline bool MessageOptions::_internal_has_message_set_wire_format() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_message_set_wire_format() const {
+  return _internal_has_message_set_wire_format();
+}
+inline void MessageOptions::clear_message_set_wire_format() {
+  _impl_.message_set_wire_format_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool MessageOptions::_internal_message_set_wire_format() const {
+  return _impl_.message_set_wire_format_;
+}
+inline bool MessageOptions::message_set_wire_format() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.message_set_wire_format)
+  return _internal_message_set_wire_format();
+}
+inline void MessageOptions::_internal_set_message_set_wire_format(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.message_set_wire_format_ = value;
+}
+inline void MessageOptions::set_message_set_wire_format(bool value) {
+  _internal_set_message_set_wire_format(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.message_set_wire_format)
+}
+
+// optional bool no_standard_descriptor_accessor = 2 [default = false];
+inline bool MessageOptions::_internal_has_no_standard_descriptor_accessor() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_no_standard_descriptor_accessor() const {
+  return _internal_has_no_standard_descriptor_accessor();
+}
+inline void MessageOptions::clear_no_standard_descriptor_accessor() {
+  _impl_.no_standard_descriptor_accessor_ = false;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline bool MessageOptions::_internal_no_standard_descriptor_accessor() const {
+  return _impl_.no_standard_descriptor_accessor_;
+}
+inline bool MessageOptions::no_standard_descriptor_accessor() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+  return _internal_no_standard_descriptor_accessor();
+}
+inline void MessageOptions::_internal_set_no_standard_descriptor_accessor(bool value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.no_standard_descriptor_accessor_ = value;
+}
+inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
+  _internal_set_no_standard_descriptor_accessor(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool MessageOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void MessageOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline bool MessageOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool MessageOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void MessageOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.deprecated_ = value;
+}
+inline void MessageOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.deprecated)
+}
+
+// optional bool map_entry = 7;
+inline bool MessageOptions::_internal_has_map_entry() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool MessageOptions::has_map_entry() const {
+  return _internal_has_map_entry();
+}
+inline void MessageOptions::clear_map_entry() {
+  _impl_.map_entry_ = false;
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline bool MessageOptions::_internal_map_entry() const {
+  return _impl_.map_entry_;
+}
+inline bool MessageOptions::map_entry() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.map_entry)
+  return _internal_map_entry();
+}
+inline void MessageOptions::_internal_set_map_entry(bool value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.map_entry_ = value;
+}
+inline void MessageOptions::set_map_entry(bool value) {
+  _internal_set_map_entry(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.map_entry)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int MessageOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int MessageOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void MessageOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MessageOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+MessageOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MessageOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MessageOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MessageOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+MessageOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// FieldOptions
+
+// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+inline bool FieldOptions::_internal_has_ctype() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_ctype() const {
+  return _internal_has_ctype();
+}
+inline void FieldOptions::clear_ctype() {
+  _impl_.ctype_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType FieldOptions::_internal_ctype() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType >(_impl_.ctype_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType FieldOptions::ctype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.ctype)
+  return _internal_ctype();
+}
+inline void FieldOptions::_internal_set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.ctype_ = value;
+}
+inline void FieldOptions::set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value) {
+  _internal_set_ctype(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.ctype)
+}
+
+// optional bool packed = 2;
+inline bool FieldOptions::_internal_has_packed() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_packed() const {
+  return _internal_has_packed();
+}
+inline void FieldOptions::clear_packed() {
+  _impl_.packed_ = false;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline bool FieldOptions::_internal_packed() const {
+  return _impl_.packed_;
+}
+inline bool FieldOptions::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.packed)
+  return _internal_packed();
+}
+inline void FieldOptions::_internal_set_packed(bool value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.packed_ = value;
+}
+inline void FieldOptions::set_packed(bool value) {
+  _internal_set_packed(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
+}
+
+// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+inline bool FieldOptions::_internal_has_jstype() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_jstype() const {
+  return _internal_has_jstype();
+}
+inline void FieldOptions::clear_jstype() {
+  _impl_.jstype_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType FieldOptions::_internal_jstype() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType >(_impl_.jstype_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType FieldOptions::jstype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype)
+  return _internal_jstype();
+}
+inline void FieldOptions::_internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value) {
+  assert(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.jstype_ = value;
+}
+inline void FieldOptions::set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value) {
+  _internal_set_jstype(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype)
+}
+
+// optional bool lazy = 5 [default = false];
+inline bool FieldOptions::_internal_has_lazy() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_lazy() const {
+  return _internal_has_lazy();
+}
+inline void FieldOptions::clear_lazy() {
+  _impl_.lazy_ = false;
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline bool FieldOptions::_internal_lazy() const {
+  return _impl_.lazy_;
+}
+inline bool FieldOptions::lazy() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.lazy)
+  return _internal_lazy();
+}
+inline void FieldOptions::_internal_set_lazy(bool value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.lazy_ = value;
+}
+inline void FieldOptions::set_lazy(bool value) {
+  _internal_set_lazy(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.lazy)
+}
+
+// optional bool unverified_lazy = 15 [default = false];
+inline bool FieldOptions::_internal_has_unverified_lazy() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_unverified_lazy() const {
+  return _internal_has_unverified_lazy();
+}
+inline void FieldOptions::clear_unverified_lazy() {
+  _impl_.unverified_lazy_ = false;
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline bool FieldOptions::_internal_unverified_lazy() const {
+  return _impl_.unverified_lazy_;
+}
+inline bool FieldOptions::unverified_lazy() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.unverified_lazy)
+  return _internal_unverified_lazy();
+}
+inline void FieldOptions::_internal_set_unverified_lazy(bool value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.unverified_lazy_ = value;
+}
+inline void FieldOptions::set_unverified_lazy(bool value) {
+  _internal_set_unverified_lazy(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.unverified_lazy)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool FieldOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void FieldOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline bool FieldOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool FieldOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void FieldOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.deprecated_ = value;
+}
+inline void FieldOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.deprecated)
+}
+
+// optional bool weak = 10 [default = false];
+inline bool FieldOptions::_internal_has_weak() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000040u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_weak() const {
+  return _internal_has_weak();
+}
+inline void FieldOptions::clear_weak() {
+  _impl_.weak_ = false;
+  _impl_._has_bits_[0] &= ~0x00000040u;
+}
+inline bool FieldOptions::_internal_weak() const {
+  return _impl_.weak_;
+}
+inline bool FieldOptions::weak() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.weak)
+  return _internal_weak();
+}
+inline void FieldOptions::_internal_set_weak(bool value) {
+  _impl_._has_bits_[0] |= 0x00000040u;
+  _impl_.weak_ = value;
+}
+inline void FieldOptions::set_weak(bool value) {
+  _internal_set_weak(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.weak)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int FieldOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int FieldOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void FieldOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+FieldOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FieldOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FieldOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* FieldOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+FieldOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// OneofOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int OneofOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int OneofOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void OneofOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* OneofOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+OneofOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& OneofOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& OneofOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* OneofOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* OneofOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.OneofOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+OneofOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumOptions
+
+// optional bool allow_alias = 2;
+inline bool EnumOptions::_internal_has_allow_alias() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumOptions::has_allow_alias() const {
+  return _internal_has_allow_alias();
+}
+inline void EnumOptions::clear_allow_alias() {
+  _impl_.allow_alias_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool EnumOptions::_internal_allow_alias() const {
+  return _impl_.allow_alias_;
+}
+inline bool EnumOptions::allow_alias() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.allow_alias)
+  return _internal_allow_alias();
+}
+inline void EnumOptions::_internal_set_allow_alias(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.allow_alias_ = value;
+}
+inline void EnumOptions::set_allow_alias(bool value) {
+  _internal_set_allow_alias(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.allow_alias)
+}
+
+// optional bool deprecated = 3 [default = false];
+inline bool EnumOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool EnumOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void EnumOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline bool EnumOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool EnumOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void EnumOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.deprecated_ = value;
+}
+inline void EnumOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int EnumOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int EnumOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void EnumOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+EnumOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+EnumOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// EnumValueOptions
+
+// optional bool deprecated = 1 [default = false];
+inline bool EnumValueOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool EnumValueOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void EnumValueOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool EnumValueOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool EnumValueOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void EnumValueOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.deprecated_ = value;
+}
+inline void EnumValueOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int EnumValueOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int EnumValueOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void EnumValueOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+EnumValueOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumValueOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumValueOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+EnumValueOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// ServiceOptions
+
+// optional bool deprecated = 33 [default = false];
+inline bool ServiceOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool ServiceOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void ServiceOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool ServiceOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool ServiceOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void ServiceOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.deprecated_ = value;
+}
+inline void ServiceOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.ServiceOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int ServiceOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int ServiceOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void ServiceOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+ServiceOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ServiceOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ServiceOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* ServiceOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+ServiceOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// MethodOptions
+
+// optional bool deprecated = 33 [default = false];
+inline bool MethodOptions::_internal_has_deprecated() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool MethodOptions::has_deprecated() const {
+  return _internal_has_deprecated();
+}
+inline void MethodOptions::clear_deprecated() {
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline bool MethodOptions::_internal_deprecated() const {
+  return _impl_.deprecated_;
+}
+inline bool MethodOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.deprecated)
+  return _internal_deprecated();
+}
+inline void MethodOptions::_internal_set_deprecated(bool value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.deprecated_ = value;
+}
+inline void MethodOptions::set_deprecated(bool value) {
+  _internal_set_deprecated(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.deprecated)
+}
+
+// optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+inline bool MethodOptions::_internal_has_idempotency_level() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool MethodOptions::has_idempotency_level() const {
+  return _internal_has_idempotency_level();
+}
+inline void MethodOptions::clear_idempotency_level() {
+  _impl_.idempotency_level_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel MethodOptions::_internal_idempotency_level() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel >(_impl_.idempotency_level_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel MethodOptions::idempotency_level() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.idempotency_level)
+  return _internal_idempotency_level();
+}
+inline void MethodOptions::_internal_set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value) {
+  assert(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_IsValid(value));
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.idempotency_level_ = value;
+}
+inline void MethodOptions::set_idempotency_level(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel value) {
+  _internal_set_idempotency_level(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.idempotency_level)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int MethodOptions::_internal_uninterpreted_option_size() const {
+  return _impl_.uninterpreted_option_.size();
+}
+inline int MethodOptions::uninterpreted_option_size() const {
+  return _internal_uninterpreted_option_size();
+}
+inline void MethodOptions::clear_uninterpreted_option() {
+  _impl_.uninterpreted_option_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >*
+MethodOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return &_impl_.uninterpreted_option_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MethodOptions::_internal_uninterpreted_option(int index) const {
+  return _impl_.uninterpreted_option_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.uninterpreted_option)
+  return _internal_uninterpreted_option(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MethodOptions::_internal_add_uninterpreted_option() {
+  return _impl_.uninterpreted_option_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* MethodOptions::add_uninterpreted_option() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* _add = _internal_add_uninterpreted_option();
+  // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >&
+MethodOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return _impl_.uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
+// UninterpretedOption_NamePart
+
+// required string name_part = 1;
+inline bool UninterpretedOption_NamePart::_internal_has_name_part() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool UninterpretedOption_NamePart::has_name_part() const {
+  return _internal_has_name_part();
+}
+inline void UninterpretedOption_NamePart::clear_name_part() {
+  _impl_.name_part_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& UninterpretedOption_NamePart::name_part() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part)
+  return _internal_name_part();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption_NamePart::set_name_part(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.name_part_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+inline std::string* UninterpretedOption_NamePart::mutable_name_part() {
+  std::string* _s = _internal_mutable_name_part();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part)
+  return _s;
+}
+inline const std::string& UninterpretedOption_NamePart::_internal_name_part() const {
+  return _impl_.name_part_.Get();
+}
+inline void UninterpretedOption_NamePart::_internal_set_name_part(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.name_part_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption_NamePart::_internal_mutable_name_part() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.name_part_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption_NamePart::release_name_part() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part)
+  if (!_internal_has_name_part()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.name_part_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_part_.IsDefault()) {
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption_NamePart::set_allocated_name_part(std::string* name_part) {
+  if (name_part != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.name_part_.SetAllocated(name_part, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_part_.IsDefault()) {
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+
+// required bool is_extension = 2;
+inline bool UninterpretedOption_NamePart::_internal_has_is_extension() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool UninterpretedOption_NamePart::has_is_extension() const {
+  return _internal_has_is_extension();
+}
+inline void UninterpretedOption_NamePart::clear_is_extension() {
+  _impl_.is_extension_ = false;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline bool UninterpretedOption_NamePart::_internal_is_extension() const {
+  return _impl_.is_extension_;
+}
+inline bool UninterpretedOption_NamePart::is_extension() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.is_extension)
+  return _internal_is_extension();
+}
+inline void UninterpretedOption_NamePart::_internal_set_is_extension(bool value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.is_extension_ = value;
+}
+inline void UninterpretedOption_NamePart::set_is_extension(bool value) {
+  _internal_set_is_extension(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.is_extension)
+}
+
+// -------------------------------------------------------------------
+
+// UninterpretedOption
+
+// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+inline int UninterpretedOption::_internal_name_size() const {
+  return _impl_.name_.size();
+}
+inline int UninterpretedOption::name_size() const {
+  return _internal_name_size();
+}
+inline void UninterpretedOption::clear_name() {
+  _impl_.name_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.name)
+  return _impl_.name_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >*
+UninterpretedOption::mutable_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name)
+  return &_impl_.name_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& UninterpretedOption::_internal_name(int index) const {
+  return _impl_.name_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.name)
+  return _internal_name(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* UninterpretedOption::_internal_add_name() {
+  return _impl_.name_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* UninterpretedOption::add_name() {
+  ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* _add = _internal_add_name();
+  // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >&
+UninterpretedOption::name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
+  return _impl_.name_;
+}
+
+// optional string identifier_value = 3;
+inline bool UninterpretedOption::_internal_has_identifier_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_identifier_value() const {
+  return _internal_has_identifier_value();
+}
+inline void UninterpretedOption::clear_identifier_value() {
+  _impl_.identifier_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& UninterpretedOption::identifier_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value)
+  return _internal_identifier_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption::set_identifier_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.identifier_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.identifier_value)
+}
+inline std::string* UninterpretedOption::mutable_identifier_value() {
+  std::string* _s = _internal_mutable_identifier_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value)
+  return _s;
+}
+inline const std::string& UninterpretedOption::_internal_identifier_value() const {
+  return _impl_.identifier_value_.Get();
+}
+inline void UninterpretedOption::_internal_set_identifier_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.identifier_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::_internal_mutable_identifier_value() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.identifier_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::release_identifier_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value)
+  if (!_internal_has_identifier_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.identifier_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.identifier_value_.IsDefault()) {
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption::set_allocated_identifier_value(std::string* identifier_value) {
+  if (identifier_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.identifier_value_.SetAllocated(identifier_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.identifier_value_.IsDefault()) {
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value)
+}
+
+// optional uint64 positive_int_value = 4;
+inline bool UninterpretedOption::_internal_has_positive_int_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_positive_int_value() const {
+  return _internal_has_positive_int_value();
+}
+inline void UninterpretedOption::clear_positive_int_value() {
+  _impl_.positive_int_value_ = uint64_t{0u};
+  _impl_._has_bits_[0] &= ~0x00000008u;
+}
+inline uint64_t UninterpretedOption::_internal_positive_int_value() const {
+  return _impl_.positive_int_value_;
+}
+inline uint64_t UninterpretedOption::positive_int_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.positive_int_value)
+  return _internal_positive_int_value();
+}
+inline void UninterpretedOption::_internal_set_positive_int_value(uint64_t value) {
+  _impl_._has_bits_[0] |= 0x00000008u;
+  _impl_.positive_int_value_ = value;
+}
+inline void UninterpretedOption::set_positive_int_value(uint64_t value) {
+  _internal_set_positive_int_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.positive_int_value)
+}
+
+// optional int64 negative_int_value = 5;
+inline bool UninterpretedOption::_internal_has_negative_int_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_negative_int_value() const {
+  return _internal_has_negative_int_value();
+}
+inline void UninterpretedOption::clear_negative_int_value() {
+  _impl_.negative_int_value_ = int64_t{0};
+  _impl_._has_bits_[0] &= ~0x00000010u;
+}
+inline int64_t UninterpretedOption::_internal_negative_int_value() const {
+  return _impl_.negative_int_value_;
+}
+inline int64_t UninterpretedOption::negative_int_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.negative_int_value)
+  return _internal_negative_int_value();
+}
+inline void UninterpretedOption::_internal_set_negative_int_value(int64_t value) {
+  _impl_._has_bits_[0] |= 0x00000010u;
+  _impl_.negative_int_value_ = value;
+}
+inline void UninterpretedOption::set_negative_int_value(int64_t value) {
+  _internal_set_negative_int_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.negative_int_value)
+}
+
+// optional double double_value = 6;
+inline bool UninterpretedOption::_internal_has_double_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000020u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_double_value() const {
+  return _internal_has_double_value();
+}
+inline void UninterpretedOption::clear_double_value() {
+  _impl_.double_value_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000020u;
+}
+inline double UninterpretedOption::_internal_double_value() const {
+  return _impl_.double_value_;
+}
+inline double UninterpretedOption::double_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.double_value)
+  return _internal_double_value();
+}
+inline void UninterpretedOption::_internal_set_double_value(double value) {
+  _impl_._has_bits_[0] |= 0x00000020u;
+  _impl_.double_value_ = value;
+}
+inline void UninterpretedOption::set_double_value(double value) {
+  _internal_set_double_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.double_value)
+}
+
+// optional bytes string_value = 7;
+inline bool UninterpretedOption::_internal_has_string_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_string_value() const {
+  return _internal_has_string_value();
+}
+inline void UninterpretedOption::clear_string_value() {
+  _impl_.string_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& UninterpretedOption::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value)
+  return _internal_string_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption::set_string_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.string_value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.string_value)
+}
+inline std::string* UninterpretedOption::mutable_string_value() {
+  std::string* _s = _internal_mutable_string_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value)
+  return _s;
+}
+inline const std::string& UninterpretedOption::_internal_string_value() const {
+  return _impl_.string_value_.Get();
+}
+inline void UninterpretedOption::_internal_set_string_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.string_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::_internal_mutable_string_value() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.string_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value)
+  if (!_internal_has_string_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.string_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.string_value_.IsDefault()) {
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption::set_allocated_string_value(std::string* string_value) {
+  if (string_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.string_value_.SetAllocated(string_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.string_value_.IsDefault()) {
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value)
+}
+
+// optional string aggregate_value = 8;
+inline bool UninterpretedOption::_internal_has_aggregate_value() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool UninterpretedOption::has_aggregate_value() const {
+  return _internal_has_aggregate_value();
+}
+inline void UninterpretedOption::clear_aggregate_value() {
+  _impl_.aggregate_value_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline const std::string& UninterpretedOption::aggregate_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value)
+  return _internal_aggregate_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void UninterpretedOption::set_aggregate_value(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000004u;
+ _impl_.aggregate_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.aggregate_value)
+}
+inline std::string* UninterpretedOption::mutable_aggregate_value() {
+  std::string* _s = _internal_mutable_aggregate_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value)
+  return _s;
+}
+inline const std::string& UninterpretedOption::_internal_aggregate_value() const {
+  return _impl_.aggregate_value_.Get();
+}
+inline void UninterpretedOption::_internal_set_aggregate_value(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.aggregate_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::_internal_mutable_aggregate_value() {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  return _impl_.aggregate_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* UninterpretedOption::release_aggregate_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value)
+  if (!_internal_has_aggregate_value()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000004u;
+  auto* p = _impl_.aggregate_value_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.aggregate_value_.IsDefault()) {
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void UninterpretedOption::set_allocated_aggregate_value(std::string* aggregate_value) {
+  if (aggregate_value != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000004u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000004u;
+  }
+  _impl_.aggregate_value_.SetAllocated(aggregate_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.aggregate_value_.IsDefault()) {
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value)
+}
+
+// -------------------------------------------------------------------
+
+// SourceCodeInfo_Location
+
+// repeated int32 path = 1 [packed = true];
+inline int SourceCodeInfo_Location::_internal_path_size() const {
+  return _impl_.path_.size();
+}
+inline int SourceCodeInfo_Location::path_size() const {
+  return _internal_path_size();
+}
+inline void SourceCodeInfo_Location::clear_path() {
+  _impl_.path_.Clear();
+}
+inline int32_t SourceCodeInfo_Location::_internal_path(int index) const {
+  return _impl_.path_.Get(index);
+}
+inline int32_t SourceCodeInfo_Location::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.path)
+  return _internal_path(index);
+}
+inline void SourceCodeInfo_Location::set_path(int index, int32_t value) {
+  _impl_.path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.path)
+}
+inline void SourceCodeInfo_Location::_internal_add_path(int32_t value) {
+  _impl_.path_.Add(value);
+}
+inline void SourceCodeInfo_Location::add_path(int32_t value) {
+  _internal_add_path(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.path)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::_internal_path() const {
+  return _impl_.path_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.path)
+  return _internal_path();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::_internal_mutable_path() {
+  return &_impl_.path_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.path)
+  return _internal_mutable_path();
+}
+
+// repeated int32 span = 2 [packed = true];
+inline int SourceCodeInfo_Location::_internal_span_size() const {
+  return _impl_.span_.size();
+}
+inline int SourceCodeInfo_Location::span_size() const {
+  return _internal_span_size();
+}
+inline void SourceCodeInfo_Location::clear_span() {
+  _impl_.span_.Clear();
+}
+inline int32_t SourceCodeInfo_Location::_internal_span(int index) const {
+  return _impl_.span_.Get(index);
+}
+inline int32_t SourceCodeInfo_Location::span(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.span)
+  return _internal_span(index);
+}
+inline void SourceCodeInfo_Location::set_span(int index, int32_t value) {
+  _impl_.span_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.span)
+}
+inline void SourceCodeInfo_Location::_internal_add_span(int32_t value) {
+  _impl_.span_.Add(value);
+}
+inline void SourceCodeInfo_Location::add_span(int32_t value) {
+  _internal_add_span(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.span)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::_internal_span() const {
+  return _impl_.span_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+SourceCodeInfo_Location::span() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.span)
+  return _internal_span();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::_internal_mutable_span() {
+  return &_impl_.span_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+SourceCodeInfo_Location::mutable_span() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.span)
+  return _internal_mutable_span();
+}
+
+// optional string leading_comments = 3;
+inline bool SourceCodeInfo_Location::_internal_has_leading_comments() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool SourceCodeInfo_Location::has_leading_comments() const {
+  return _internal_has_leading_comments();
+}
+inline void SourceCodeInfo_Location::clear_leading_comments() {
+  _impl_.leading_comments_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& SourceCodeInfo_Location::leading_comments() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  return _internal_leading_comments();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void SourceCodeInfo_Location::set_leading_comments(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.leading_comments_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+inline std::string* SourceCodeInfo_Location::mutable_leading_comments() {
+  std::string* _s = _internal_mutable_leading_comments();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  return _s;
+}
+inline const std::string& SourceCodeInfo_Location::_internal_leading_comments() const {
+  return _impl_.leading_comments_.Get();
+}
+inline void SourceCodeInfo_Location::_internal_set_leading_comments(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.leading_comments_.Set(value, GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::_internal_mutable_leading_comments() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.leading_comments_.Mutable(GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::release_leading_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  if (!_internal_has_leading_comments()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.leading_comments_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.leading_comments_.IsDefault()) {
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void SourceCodeInfo_Location::set_allocated_leading_comments(std::string* leading_comments) {
+  if (leading_comments != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.leading_comments_.SetAllocated(leading_comments, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.leading_comments_.IsDefault()) {
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+
+// optional string trailing_comments = 4;
+inline bool SourceCodeInfo_Location::_internal_has_trailing_comments() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool SourceCodeInfo_Location::has_trailing_comments() const {
+  return _internal_has_trailing_comments();
+}
+inline void SourceCodeInfo_Location::clear_trailing_comments() {
+  _impl_.trailing_comments_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline const std::string& SourceCodeInfo_Location::trailing_comments() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  return _internal_trailing_comments();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void SourceCodeInfo_Location::set_trailing_comments(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000002u;
+ _impl_.trailing_comments_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+inline std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
+  std::string* _s = _internal_mutable_trailing_comments();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  return _s;
+}
+inline const std::string& SourceCodeInfo_Location::_internal_trailing_comments() const {
+  return _impl_.trailing_comments_.Get();
+}
+inline void SourceCodeInfo_Location::_internal_set_trailing_comments(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.trailing_comments_.Set(value, GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::_internal_mutable_trailing_comments() {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  return _impl_.trailing_comments_.Mutable(GetArenaForAllocation());
+}
+inline std::string* SourceCodeInfo_Location::release_trailing_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  if (!_internal_has_trailing_comments()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000002u;
+  auto* p = _impl_.trailing_comments_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.trailing_comments_.IsDefault()) {
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void SourceCodeInfo_Location::set_allocated_trailing_comments(std::string* trailing_comments) {
+  if (trailing_comments != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000002u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000002u;
+  }
+  _impl_.trailing_comments_.SetAllocated(trailing_comments, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.trailing_comments_.IsDefault()) {
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+
+// repeated string leading_detached_comments = 6;
+inline int SourceCodeInfo_Location::_internal_leading_detached_comments_size() const {
+  return _impl_.leading_detached_comments_.size();
+}
+inline int SourceCodeInfo_Location::leading_detached_comments_size() const {
+  return _internal_leading_detached_comments_size();
+}
+inline void SourceCodeInfo_Location::clear_leading_detached_comments() {
+  _impl_.leading_detached_comments_.Clear();
+}
+inline std::string* SourceCodeInfo_Location::add_leading_detached_comments() {
+  std::string* _s = _internal_add_leading_detached_comments();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _s;
+}
+inline const std::string& SourceCodeInfo_Location::_internal_leading_detached_comments(int index) const {
+  return _impl_.leading_detached_comments_.Get(index);
+}
+inline const std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _internal_leading_detached_comments(index);
+}
+inline std::string* SourceCodeInfo_Location::mutable_leading_detached_comments(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _impl_.leading_detached_comments_.Mutable(index);
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const std::string& value) {
+  _impl_.leading_detached_comments_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, std::string&& value) {
+  _impl_.leading_detached_comments_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.leading_detached_comments_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value, size_t size) {
+  _impl_.leading_detached_comments_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline std::string* SourceCodeInfo_Location::_internal_add_leading_detached_comments() {
+  return _impl_.leading_detached_comments_.Add();
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const std::string& value) {
+  _impl_.leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(std::string&& value) {
+  _impl_.leading_detached_comments_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value, size_t size) {
+  _impl_.leading_detached_comments_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+SourceCodeInfo_Location::leading_detached_comments() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return _impl_.leading_detached_comments_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+SourceCodeInfo_Location::mutable_leading_detached_comments() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return &_impl_.leading_detached_comments_;
+}
+
+// -------------------------------------------------------------------
+
+// SourceCodeInfo
+
+// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+inline int SourceCodeInfo::_internal_location_size() const {
+  return _impl_.location_.size();
+}
+inline int SourceCodeInfo::location_size() const {
+  return _internal_location_size();
+}
+inline void SourceCodeInfo::clear_location() {
+  _impl_.location_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.location)
+  return _impl_.location_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >*
+SourceCodeInfo::mutable_location() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location)
+  return &_impl_.location_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& SourceCodeInfo::_internal_location(int index) const {
+  return _impl_.location_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.location)
+  return _internal_location(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* SourceCodeInfo::_internal_add_location() {
+  return _impl_.location_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* SourceCodeInfo::add_location() {
+  ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* _add = _internal_add_location();
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >&
+SourceCodeInfo::location() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
+  return _impl_.location_;
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo_Annotation
+
+// repeated int32 path = 1 [packed = true];
+inline int GeneratedCodeInfo_Annotation::_internal_path_size() const {
+  return _impl_.path_.size();
+}
+inline int GeneratedCodeInfo_Annotation::path_size() const {
+  return _internal_path_size();
+}
+inline void GeneratedCodeInfo_Annotation::clear_path() {
+  _impl_.path_.Clear();
+}
+inline int32_t GeneratedCodeInfo_Annotation::_internal_path(int index) const {
+  return _impl_.path_.Get(index);
+}
+inline int32_t GeneratedCodeInfo_Annotation::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return _internal_path(index);
+}
+inline void GeneratedCodeInfo_Annotation::set_path(int index, int32_t value) {
+  _impl_.path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline void GeneratedCodeInfo_Annotation::_internal_add_path(int32_t value) {
+  _impl_.path_.Add(value);
+}
+inline void GeneratedCodeInfo_Annotation::add_path(int32_t value) {
+  _internal_add_path(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+GeneratedCodeInfo_Annotation::_internal_path() const {
+  return _impl_.path_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >&
+GeneratedCodeInfo_Annotation::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return _internal_path();
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+GeneratedCodeInfo_Annotation::_internal_mutable_path() {
+  return &_impl_.path_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< int32_t >*
+GeneratedCodeInfo_Annotation::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return _internal_mutable_path();
+}
+
+// optional string source_file = 2;
+inline bool GeneratedCodeInfo_Annotation::_internal_has_source_file() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000001u) != 0;
+  return value;
+}
+inline bool GeneratedCodeInfo_Annotation::has_source_file() const {
+  return _internal_has_source_file();
+}
+inline void GeneratedCodeInfo_Annotation::clear_source_file() {
+  _impl_.source_file_.ClearToEmpty();
+  _impl_._has_bits_[0] &= ~0x00000001u;
+}
+inline const std::string& GeneratedCodeInfo_Annotation::source_file() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return _internal_source_file();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void GeneratedCodeInfo_Annotation::set_source_file(ArgT0&& arg0, ArgT... args) {
+ _impl_._has_bits_[0] |= 0x00000001u;
+ _impl_.source_file_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline std::string* GeneratedCodeInfo_Annotation::mutable_source_file() {
+  std::string* _s = _internal_mutable_source_file();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return _s;
+}
+inline const std::string& GeneratedCodeInfo_Annotation::_internal_source_file() const {
+  return _impl_.source_file_.Get();
+}
+inline void GeneratedCodeInfo_Annotation::_internal_set_source_file(const std::string& value) {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  _impl_.source_file_.Set(value, GetArenaForAllocation());
+}
+inline std::string* GeneratedCodeInfo_Annotation::_internal_mutable_source_file() {
+  _impl_._has_bits_[0] |= 0x00000001u;
+  return _impl_.source_file_.Mutable(GetArenaForAllocation());
+}
+inline std::string* GeneratedCodeInfo_Annotation::release_source_file() {
+  // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  if (!_internal_has_source_file()) {
+    return nullptr;
+  }
+  _impl_._has_bits_[0] &= ~0x00000001u;
+  auto* p = _impl_.source_file_.Release();
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.source_file_.IsDefault()) {
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  return p;
+}
+inline void GeneratedCodeInfo_Annotation::set_allocated_source_file(std::string* source_file) {
+  if (source_file != nullptr) {
+    _impl_._has_bits_[0] |= 0x00000001u;
+  } else {
+    _impl_._has_bits_[0] &= ~0x00000001u;
+  }
+  _impl_.source_file_.SetAllocated(source_file, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.source_file_.IsDefault()) {
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+
+// optional int32 begin = 3;
+inline bool GeneratedCodeInfo_Annotation::_internal_has_begin() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000002u) != 0;
+  return value;
+}
+inline bool GeneratedCodeInfo_Annotation::has_begin() const {
+  return _internal_has_begin();
+}
+inline void GeneratedCodeInfo_Annotation::clear_begin() {
+  _impl_.begin_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000002u;
+}
+inline int32_t GeneratedCodeInfo_Annotation::_internal_begin() const {
+  return _impl_.begin_;
+}
+inline int32_t GeneratedCodeInfo_Annotation::begin() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+  return _internal_begin();
+}
+inline void GeneratedCodeInfo_Annotation::_internal_set_begin(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000002u;
+  _impl_.begin_ = value;
+}
+inline void GeneratedCodeInfo_Annotation::set_begin(int32_t value) {
+  _internal_set_begin(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+}
+
+// optional int32 end = 4;
+inline bool GeneratedCodeInfo_Annotation::_internal_has_end() const {
+  bool value = (_impl_._has_bits_[0] & 0x00000004u) != 0;
+  return value;
+}
+inline bool GeneratedCodeInfo_Annotation::has_end() const {
+  return _internal_has_end();
+}
+inline void GeneratedCodeInfo_Annotation::clear_end() {
+  _impl_.end_ = 0;
+  _impl_._has_bits_[0] &= ~0x00000004u;
+}
+inline int32_t GeneratedCodeInfo_Annotation::_internal_end() const {
+  return _impl_.end_;
+}
+inline int32_t GeneratedCodeInfo_Annotation::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end)
+  return _internal_end();
+}
+inline void GeneratedCodeInfo_Annotation::_internal_set_end(int32_t value) {
+  _impl_._has_bits_[0] |= 0x00000004u;
+  _impl_.end_ = value;
+}
+inline void GeneratedCodeInfo_Annotation::set_end(int32_t value) {
+  _internal_set_end(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo
+
+// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+inline int GeneratedCodeInfo::_internal_annotation_size() const {
+  return _impl_.annotation_.size();
+}
+inline int GeneratedCodeInfo::annotation_size() const {
+  return _internal_annotation_size();
+}
+inline void GeneratedCodeInfo::clear_annotation() {
+  _impl_.annotation_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation)
+  return _impl_.annotation_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >*
+GeneratedCodeInfo::mutable_annotation() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return &_impl_.annotation_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::_internal_annotation(int index) const {
+  return _impl_.annotation_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation)
+  return _internal_annotation(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::_internal_add_annotation() {
+  return _impl_.annotation_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() {
+  ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* _add = _internal_add_annotation();
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >&
+GeneratedCodeInfo::annotation() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return _impl_.annotation_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>() {
+  return ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>() {
+  return ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>() {
+  return ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fdescriptor_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor_database.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor_database.h
new file mode 100644
index 0000000..f4f06bb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/descriptor_database.h
@@ -0,0 +1,398 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Interface for manipulating databases of descriptors.
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
+#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
+
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class DescriptorDatabase;
+class SimpleDescriptorDatabase;
+class EncodedDescriptorDatabase;
+class DescriptorPoolDatabase;
+class MergedDescriptorDatabase;
+
+// Abstract interface for a database of descriptors.
+//
+// This is useful if you want to create a DescriptorPool which loads
+// descriptors on-demand from some sort of large database.  If the database
+// is large, it may be inefficient to enumerate every .proto file inside it
+// calling DescriptorPool::BuildFile() for each one.  Instead, a DescriptorPool
+// can be created which wraps a DescriptorDatabase and only builds particular
+// descriptors when they are needed.
+class PROTOBUF_EXPORT DescriptorDatabase {
+ public:
+  inline DescriptorDatabase() {}
+  virtual ~DescriptorDatabase();
+
+  // Find a file by file name.  Fills in in *output and returns true if found.
+  // Otherwise, returns false, leaving the contents of *output undefined.
+  virtual bool FindFileByName(const std::string& filename,
+                              FileDescriptorProto* output) = 0;
+
+  // Find the file that declares the given fully-qualified symbol name.
+  // If found, fills in *output and returns true, otherwise returns false
+  // and leaves *output undefined.
+  virtual bool FindFileContainingSymbol(const std::string& symbol_name,
+                                        FileDescriptorProto* output) = 0;
+
+  // Find the file which defines an extension extending the given message type
+  // with the given field number.  If found, fills in *output and returns true,
+  // otherwise returns false and leaves *output undefined.  containing_type
+  // must be a fully-qualified type name.
+  virtual bool FindFileContainingExtension(const std::string& containing_type,
+                                           int field_number,
+                                           FileDescriptorProto* output) = 0;
+
+  // Finds the tag numbers used by all known extensions of
+  // extendee_type, and appends them to output in an undefined
+  // order. This method is best-effort: it's not guaranteed that the
+  // database will find all extensions, and it's not guaranteed that
+  // FindFileContainingExtension will return true on all of the found
+  // numbers. Returns true if the search was successful, otherwise
+  // returns false and leaves output unchanged.
+  //
+  // This method has a default implementation that always returns
+  // false.
+  virtual bool FindAllExtensionNumbers(const std::string& /* extendee_type */,
+                                       std::vector<int>* /* output */) {
+    return false;
+  }
+
+
+  // Finds the file names and appends them to the output in an
+  // undefined order. This method is best-effort: it's not guaranteed that the
+  // database will find all files. Returns true if the database supports
+  // searching all file names, otherwise returns false and leaves output
+  // unchanged.
+  //
+  // This method has a default implementation that always returns
+  // false.
+  virtual bool FindAllFileNames(std::vector<std::string>* /*output*/) {
+    return false;
+  }
+
+  // Finds the package names and appends them to the output in an
+  // undefined order. This method is best-effort: it's not guaranteed that the
+  // database will find all packages. Returns true if the database supports
+  // searching all package names, otherwise returns false and leaves output
+  // unchanged.
+  bool FindAllPackageNames(std::vector<std::string>* output);
+
+  // Finds the message names and appends them to the output in an
+  // undefined order. This method is best-effort: it's not guaranteed that the
+  // database will find all messages. Returns true if the database supports
+  // searching all message names, otherwise returns false and leaves output
+  // unchanged.
+  bool FindAllMessageNames(std::vector<std::string>* output);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
+};
+
+// A DescriptorDatabase into which you can insert files manually.
+//
+// FindFileContainingSymbol() is fully-implemented.  When you add a file, its
+// symbols will be indexed for this purpose.  Note that the implementation
+// may return false positives, but only if it isn't possible for the symbol
+// to be defined in any other file.  In particular, if a file defines a symbol
+// "Foo", then searching for "Foo.[anything]" will match that file.  This way,
+// the database does not need to aggressively index all children of a symbol.
+//
+// FindFileContainingExtension() is mostly-implemented.  It works if and only
+// if the original FieldDescriptorProto defining the extension has a
+// fully-qualified type name in its "extendee" field (i.e. starts with a '.').
+// If the extendee is a relative name, SimpleDescriptorDatabase will not
+// attempt to resolve the type, so it will not know what type the extension is
+// extending.  Therefore, calling FindFileContainingExtension() with the
+// extension's containing type will never actually find that extension.  Note
+// that this is an unlikely problem, as all FileDescriptorProtos created by the
+// protocol compiler (as well as ones created by calling
+// FileDescriptor::CopyTo()) will always use fully-qualified names for all
+// types.  You only need to worry if you are constructing FileDescriptorProtos
+// yourself, or are calling compiler::Parser directly.
+class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
+ public:
+  SimpleDescriptorDatabase();
+  ~SimpleDescriptorDatabase() override;
+
+  // Adds the FileDescriptorProto to the database, making a copy.  The object
+  // can be deleted after Add() returns.  Returns false if the file conflicted
+  // with a file already in the database, in which case an error will have
+  // been written to GOOGLE_LOG(ERROR).
+  bool Add(const FileDescriptorProto& file);
+
+  // Adds the FileDescriptorProto to the database and takes ownership of it.
+  bool AddAndOwn(const FileDescriptorProto* file);
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+
+  bool FindAllFileNames(std::vector<std::string>* output) override;
+
+ private:
+  // An index mapping file names, symbol names, and extension numbers to
+  // some sort of values.
+  template <typename Value>
+  class DescriptorIndex {
+   public:
+    // Helpers to recursively add particular descriptors and all their contents
+    // to the index.
+    bool AddFile(const FileDescriptorProto& file, Value value);
+    bool AddSymbol(const std::string& name, Value value);
+    bool AddNestedExtensions(const std::string& filename,
+                             const DescriptorProto& message_type, Value value);
+    bool AddExtension(const std::string& filename,
+                      const FieldDescriptorProto& field, Value value);
+
+    Value FindFile(const std::string& filename);
+    Value FindSymbol(const std::string& name);
+    Value FindExtension(const std::string& containing_type, int field_number);
+    bool FindAllExtensionNumbers(const std::string& containing_type,
+                                 std::vector<int>* output);
+    void FindAllFileNames(std::vector<std::string>* output);
+
+   private:
+    std::map<std::string, Value> by_name_;
+    std::map<std::string, Value> by_symbol_;
+    std::map<std::pair<std::string, int>, Value> by_extension_;
+
+    // Invariant:  The by_symbol_ map does not contain any symbols which are
+    // prefixes of other symbols in the map.  For example, "foo.bar" is a
+    // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
+    //
+    // This invariant is important because it means that given a symbol name,
+    // we can find a key in the map which is a prefix of the symbol in O(lg n)
+    // time, and we know that there is at most one such key.
+    //
+    // The prefix lookup algorithm works like so:
+    // 1) Find the last key in the map which is less than or equal to the
+    //    search key.
+    // 2) If the found key is a prefix of the search key, then return it.
+    //    Otherwise, there is no match.
+    //
+    // I am sure this algorithm has been described elsewhere, but since I
+    // wasn't able to find it quickly I will instead prove that it works
+    // myself.  The key to the algorithm is that if a match exists, step (1)
+    // will find it.  Proof:
+    // 1) Define the "search key" to be the key we are looking for, the "found
+    //    key" to be the key found in step (1), and the "match key" to be the
+    //    key which actually matches the search key (i.e. the key we're trying
+    //    to find).
+    // 2) The found key must be less than or equal to the search key by
+    //    definition.
+    // 3) The match key must also be less than or equal to the search key
+    //    (because it is a prefix).
+    // 4) The match key cannot be greater than the found key, because if it
+    //    were, then step (1) of the algorithm would have returned the match
+    //    key instead (since it finds the *greatest* key which is less than or
+    //    equal to the search key).
+    // 5) Therefore, the found key must be between the match key and the search
+    //    key, inclusive.
+    // 6) Since the search key must be a sub-symbol of the match key, if it is
+    //    not equal to the match key, then search_key[match_key.size()] must
+    //    be '.'.
+    // 7) Since '.' sorts before any other character that is valid in a symbol
+    //    name, then if the found key is not equal to the match key, then
+    //    found_key[match_key.size()] must also be '.', because any other value
+    //    would make it sort after the search key.
+    // 8) Therefore, if the found key is not equal to the match key, then the
+    //    found key must be a sub-symbol of the match key.  However, this would
+    //    contradict our map invariant which says that no symbol in the map is
+    //    a sub-symbol of any other.
+    // 9) Therefore, the found key must match the match key.
+    //
+    // The above proof assumes the match key exists.  In the case that the
+    // match key does not exist, then step (1) will return some other symbol.
+    // That symbol cannot be a super-symbol of the search key since if it were,
+    // then it would be a match, and we're assuming the match key doesn't exist.
+    // Therefore, step 2 will correctly return no match.
+  };
+
+  DescriptorIndex<const FileDescriptorProto*> index_;
+  std::vector<std::unique_ptr<const FileDescriptorProto>> files_to_delete_;
+
+  // If file is non-nullptr, copy it into *output and return true, otherwise
+  // return false.
+  bool MaybeCopy(const FileDescriptorProto* file, FileDescriptorProto* output);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
+};
+
+// Very similar to SimpleDescriptorDatabase, but stores all the descriptors
+// as raw bytes and generally tries to use as little memory as possible.
+//
+// The same caveats regarding FindFileContainingExtension() apply as with
+// SimpleDescriptorDatabase.
+class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
+ public:
+  EncodedDescriptorDatabase();
+  ~EncodedDescriptorDatabase() override;
+
+  // Adds the FileDescriptorProto to the database.  The descriptor is provided
+  // in encoded form.  The database does not make a copy of the bytes, nor
+  // does it take ownership; it's up to the caller to make sure the bytes
+  // remain valid for the life of the database.  Returns false and logs an error
+  // if the bytes are not a valid FileDescriptorProto or if the file conflicted
+  // with a file already in the database.
+  bool Add(const void* encoded_file_descriptor, int size);
+
+  // Like Add(), but makes a copy of the data, so that the caller does not
+  // need to keep it around.
+  bool AddCopy(const void* encoded_file_descriptor, int size);
+
+  // Like FindFileContainingSymbol but returns only the name of the file.
+  bool FindNameOfFileContainingSymbol(const std::string& symbol_name,
+                                      std::string* output);
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+  bool FindAllFileNames(std::vector<std::string>* output) override;
+
+ private:
+  class DescriptorIndex;
+  // Keep DescriptorIndex by pointer to hide the implementation to keep a
+  // cleaner header.
+  std::unique_ptr<DescriptorIndex> index_;
+  std::vector<void*> files_to_delete_;
+
+  // If encoded_file.first is non-nullptr, parse the data into *output and
+  // return true, otherwise return false.
+  bool MaybeParse(std::pair<const void*, int> encoded_file,
+                  FileDescriptorProto* output);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase);
+};
+
+// A DescriptorDatabase that fetches files from a given pool.
+class PROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
+ public:
+  explicit DescriptorPoolDatabase(const DescriptorPool& pool);
+  ~DescriptorPoolDatabase() override;
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+
+ private:
+  const DescriptorPool& pool_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase);
+};
+
+// A DescriptorDatabase that wraps two or more others.  It first searches the
+// first database and, if that fails, tries the second, and so on.
+class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
+ public:
+  // Merge just two databases.  The sources remain property of the caller.
+  MergedDescriptorDatabase(DescriptorDatabase* source1,
+                           DescriptorDatabase* source2);
+  // Merge more than two databases.  The sources remain property of the caller.
+  // The vector may be deleted after the constructor returns but the
+  // DescriptorDatabases need to stick around.
+  explicit MergedDescriptorDatabase(
+      const std::vector<DescriptorDatabase*>& sources);
+  ~MergedDescriptorDatabase() override;
+
+  // implements DescriptorDatabase -----------------------------------
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
+  bool FindFileContainingSymbol(const std::string& symbol_name,
+                                FileDescriptorProto* output) override;
+  bool FindFileContainingExtension(const std::string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output) override;
+  // Merges the results of calling all databases. Returns true iff any
+  // of the databases returned true.
+  bool FindAllExtensionNumbers(const std::string& extendee_type,
+                               std::vector<int>* output) override;
+
+
+  // This function is best-effort. Returns true if at least one underlying
+  // DescriptorDatabase returns true.
+  bool FindAllFileNames(std::vector<std::string>* output) override;
+
+ private:
+  std::vector<DescriptorDatabase*> sources_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/duration.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/duration.pb.h
new file mode 100644
index 0000000..a5272c8
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/duration.pb.h
@@ -0,0 +1,278 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fduration_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fduration_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fduration_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fduration_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Duration;
+struct DurationDefaultTypeInternal;
+PROTOBUF_EXPORT extern DurationDefaultTypeInternal _Duration_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Duration* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Duration>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Duration final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Duration) */ {
+ public:
+  inline Duration() : Duration(nullptr) {}
+  ~Duration() override;
+  explicit PROTOBUF_CONSTEXPR Duration(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Duration(const Duration& from);
+  Duration(Duration&& from) noexcept
+    : Duration() {
+    *this = ::std::move(from);
+  }
+
+  inline Duration& operator=(const Duration& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Duration& operator=(Duration&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Duration& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Duration* internal_default_instance() {
+    return reinterpret_cast<const Duration*>(
+               &_Duration_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Duration& a, Duration& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Duration* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Duration* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Duration* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Duration>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Duration& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Duration& from) {
+    Duration::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Duration* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Duration";
+  }
+  protected:
+  explicit Duration(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kSecondsFieldNumber = 1,
+    kNanosFieldNumber = 2,
+  };
+  // int64 seconds = 1;
+  void clear_seconds();
+  int64_t seconds() const;
+  void set_seconds(int64_t value);
+  private:
+  int64_t _internal_seconds() const;
+  void _internal_set_seconds(int64_t value);
+  public:
+
+  // int32 nanos = 2;
+  void clear_nanos();
+  int32_t nanos() const;
+  void set_nanos(int32_t value);
+  private:
+  int32_t _internal_nanos() const;
+  void _internal_set_nanos(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Duration)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int64_t seconds_;
+    int32_t nanos_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fduration_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Duration
+
+// int64 seconds = 1;
+inline void Duration::clear_seconds() {
+  _impl_.seconds_ = int64_t{0};
+}
+inline int64_t Duration::_internal_seconds() const {
+  return _impl_.seconds_;
+}
+inline int64_t Duration::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.seconds)
+  return _internal_seconds();
+}
+inline void Duration::_internal_set_seconds(int64_t value) {
+  
+  _impl_.seconds_ = value;
+}
+inline void Duration::set_seconds(int64_t value) {
+  _internal_set_seconds(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.seconds)
+}
+
+// int32 nanos = 2;
+inline void Duration::clear_nanos() {
+  _impl_.nanos_ = 0;
+}
+inline int32_t Duration::_internal_nanos() const {
+  return _impl_.nanos_;
+}
+inline int32_t Duration::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.nanos)
+  return _internal_nanos();
+}
+inline void Duration::_internal_set_nanos(int32_t value) {
+  
+  _impl_.nanos_ = value;
+}
+inline void Duration::set_nanos(int32_t value) {
+  _internal_set_nanos(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.nanos)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fduration_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/dynamic_message.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/dynamic_message.h
new file mode 100644
index 0000000..6fa6425
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/dynamic_message.h
@@ -0,0 +1,227 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Defines an implementation of Message which can emulate types which are not
+// known at compile-time.
+
+#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
+#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
+
+
+#include <algorithm>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/repeated_field.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Defined in other files.
+class Descriptor;      // descriptor.h
+class DescriptorPool;  // descriptor.h
+
+// Constructs implementations of Message which can emulate types which are not
+// known at compile-time.
+//
+// Sometimes you want to be able to manipulate protocol types that you don't
+// know about at compile time.  It would be nice to be able to construct
+// a Message object which implements the message type given by any arbitrary
+// Descriptor.  DynamicMessage provides this.
+//
+// As it turns out, a DynamicMessage needs to construct extra
+// information about its type in order to operate.  Most of this information
+// can be shared between all DynamicMessages of the same type.  But, caching
+// this information in some sort of global map would be a bad idea, since
+// the cached information for a particular descriptor could outlive the
+// descriptor itself.  To avoid this problem, DynamicMessageFactory
+// encapsulates this "cache".  All DynamicMessages of the same type created
+// from the same factory will share the same support data.  Any Descriptors
+// used with a particular factory must outlive the factory.
+class PROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
+ public:
+  // Construct a DynamicMessageFactory that will search for extensions in
+  // the DescriptorPool in which the extendee is defined.
+  DynamicMessageFactory();
+
+  // Construct a DynamicMessageFactory that will search for extensions in
+  // the given DescriptorPool.
+  //
+  // DEPRECATED:  Use CodedInputStream::SetExtensionRegistry() to tell the
+  //   parser to look for extensions in an alternate pool.  However, note that
+  //   this is almost never what you want to do.  Almost all users should use
+  //   the zero-arg constructor.
+  DynamicMessageFactory(const DescriptorPool* pool);
+
+  ~DynamicMessageFactory() override;
+
+  // Call this to tell the DynamicMessageFactory that if it is given a
+  // Descriptor d for which:
+  //   d->file()->pool() == DescriptorPool::generated_pool(),
+  // then it should delegate to MessageFactory::generated_factory() instead
+  // of constructing a dynamic implementation of the message.  In theory there
+  // is no down side to doing this, so it may become the default in the future.
+  void SetDelegateToGeneratedFactory(bool enable) {
+    delegate_to_generated_factory_ = enable;
+  }
+
+  // implements MessageFactory ---------------------------------------
+
+  // Given a Descriptor, constructs the default (prototype) Message of that
+  // type.  You can then call that message's New() method to construct a
+  // mutable message of that type.
+  //
+  // Calling this method twice with the same Descriptor returns the same
+  // object.  The returned object remains property of the factory and will
+  // be destroyed when the factory is destroyed.  Also, any objects created
+  // by calling the prototype's New() method share some data with the
+  // prototype, so these must be destroyed before the DynamicMessageFactory
+  // is destroyed.
+  //
+  // The given descriptor must outlive the returned message, and hence must
+  // outlive the DynamicMessageFactory.
+  //
+  // The method is thread-safe.
+  const Message* GetPrototype(const Descriptor* type) override;
+
+ private:
+  const DescriptorPool* pool_;
+  bool delegate_to_generated_factory_;
+
+  struct TypeInfo;
+  std::unordered_map<const Descriptor*, const TypeInfo*> prototypes_;
+  mutable internal::WrappedMutex prototypes_mutex_;
+
+  friend class DynamicMessage;
+  const Message* GetPrototypeNoLock(const Descriptor* type);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
+};
+
+// Helper for computing a sorted list of map entries via reflection.
+class PROTOBUF_EXPORT DynamicMapSorter {
+ public:
+  static std::vector<const Message*> Sort(const Message& message, int map_size,
+                                          const Reflection* reflection,
+                                          const FieldDescriptor* field) {
+    std::vector<const Message*> result;
+    result.reserve(map_size);
+    RepeatedFieldRef<Message> map_field =
+        reflection->GetRepeatedFieldRef<Message>(message, field);
+    for (auto it = map_field.begin(); it != map_field.end(); ++it) {
+      result.push_back(&*it);
+    }
+    MapEntryMessageComparator comparator(field->message_type());
+    std::stable_sort(result.begin(), result.end(), comparator);
+    // Complain if the keys aren't in ascending order.
+#ifndef NDEBUG
+    for (size_t j = 1; j < static_cast<size_t>(map_size); j++) {
+      if (!comparator(result[j - 1], result[j])) {
+        GOOGLE_LOG(ERROR) << (comparator(result[j], result[j - 1])
+                           ? "internal error in map key sorting"
+                           : "map keys are not unique");
+      }
+    }
+#endif
+    return result;
+  }
+
+ private:
+  class PROTOBUF_EXPORT MapEntryMessageComparator {
+   public:
+    explicit MapEntryMessageComparator(const Descriptor* descriptor)
+        : field_(descriptor->field(0)) {}
+
+    bool operator()(const Message* a, const Message* b) {
+      const Reflection* reflection = a->GetReflection();
+      switch (field_->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_BOOL: {
+          bool first = reflection->GetBool(*a, field_);
+          bool second = reflection->GetBool(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_INT32: {
+          int32_t first = reflection->GetInt32(*a, field_);
+          int32_t second = reflection->GetInt32(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_INT64: {
+          int64_t first = reflection->GetInt64(*a, field_);
+          int64_t second = reflection->GetInt64(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_UINT32: {
+          uint32_t first = reflection->GetUInt32(*a, field_);
+          uint32_t second = reflection->GetUInt32(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_UINT64: {
+          uint64_t first = reflection->GetUInt64(*a, field_);
+          uint64_t second = reflection->GetUInt64(*b, field_);
+          return first < second;
+        }
+        case FieldDescriptor::CPPTYPE_STRING: {
+          std::string first = reflection->GetString(*a, field_);
+          std::string second = reflection->GetString(*b, field_);
+          return first < second;
+        }
+        default:
+          GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+          return true;
+      }
+    }
+
+   private:
+    const FieldDescriptor* field_;
+  };
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/empty.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/empty.pb.h
new file mode 100644
index 0000000..bcb6478
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/empty.pb.h
@@ -0,0 +1,198 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fempty_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fempty_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_bases.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fempty_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fempty_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Empty;
+struct EmptyDefaultTypeInternal;
+PROTOBUF_EXPORT extern EmptyDefaultTypeInternal _Empty_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Empty* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Empty>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Empty final :
+    public ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
+ public:
+  inline Empty() : Empty(nullptr) {}
+  explicit PROTOBUF_CONSTEXPR Empty(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Empty(const Empty& from);
+  Empty(Empty&& from) noexcept
+    : Empty() {
+    *this = ::std::move(from);
+  }
+
+  inline Empty& operator=(const Empty& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Empty& operator=(Empty&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Empty& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Empty* internal_default_instance() {
+    return reinterpret_cast<const Empty*>(
+               &_Empty_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Empty& a, Empty& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Empty* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Empty* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Empty* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Empty>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyFrom;
+  inline void CopyFrom(const Empty& from) {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyImpl(*this, from);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeFrom;
+  void MergeFrom(const Empty& from) {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeImpl(*this, from);
+  }
+  public:
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Empty";
+  }
+  protected:
+  explicit Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Empty)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+  };
+  friend struct ::TableStruct_google_2fprotobuf_2fempty_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Empty
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fempty_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/endian.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/endian.h
new file mode 100644
index 0000000..e0ee6cd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/endian.h
@@ -0,0 +1,198 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_ENDIAN_H__
+#define GOOGLE_PROTOBUF_ENDIAN_H__
+
+#if defined(_MSC_VER)
+#include <stdlib.h>
+#endif
+
+#include <cstdint>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline uint64_t BSwap64(uint64_t host_int) {
+#if defined(PROTOBUF_BUILTIN_BSWAP64)
+  return PROTOBUF_BUILTIN_BSWAP64(host_int);
+#elif defined(_MSC_VER)
+  return _byteswap_uint64(host_int);
+#else
+  return (((host_int & uint64_t{0xFF}) << 56) |
+          ((host_int & uint64_t{0xFF00}) << 40) |
+          ((host_int & uint64_t{0xFF0000}) << 24) |
+          ((host_int & uint64_t{0xFF000000}) << 8) |
+          ((host_int & uint64_t{0xFF00000000}) >> 8) |
+          ((host_int & uint64_t{0xFF0000000000}) >> 24) |
+          ((host_int & uint64_t{0xFF000000000000}) >> 40) |
+          ((host_int & uint64_t{0xFF00000000000000}) >> 56));
+#endif
+}
+
+inline uint32_t BSwap32(uint32_t host_int) {
+#if defined(PROTOBUF_BUILTIN_BSWAP32)
+  return PROTOBUF_BUILTIN_BSWAP32(host_int);
+#elif defined(_MSC_VER)
+  return _byteswap_ulong(host_int);
+#else
+  return (((host_int & uint32_t{0xFF}) << 24) |
+          ((host_int & uint32_t{0xFF00}) << 8) |
+          ((host_int & uint32_t{0xFF0000}) >> 8) |
+          ((host_int & uint32_t{0xFF000000}) >> 24));
+#endif
+}
+
+inline uint16_t BSwap16(uint16_t host_int) {
+#if defined(PROTOBUF_BUILTIN_BSWAP16)
+  return PROTOBUF_BUILTIN_BSWAP16(host_int);
+#elif defined(_MSC_VER)
+  return _byteswap_ushort(host_int);
+#else
+  return (((host_int & uint16_t{0xFF}) << 8) |
+          ((host_int & uint16_t{0xFF00}) >> 8));
+#endif
+}
+
+namespace little_endian {
+
+inline uint16_t FromHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap16(value);
+#else
+  return value;
+#endif
+}
+
+inline uint32_t FromHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap32(value);
+#else
+  return value;
+#endif
+}
+
+inline uint64_t FromHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap64(value);
+#else
+  return value;
+#endif
+}
+
+inline uint16_t ToHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap16(value);
+#else
+  return value;
+#endif
+}
+
+inline uint32_t ToHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap32(value);
+#else
+  return value;
+#endif
+}
+
+inline uint64_t ToHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return BSwap64(value);
+#else
+  return value;
+#endif
+}
+
+}  // namespace little_endian
+
+namespace big_endian {
+
+inline uint16_t FromHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap16(value);
+#endif
+}
+
+inline uint32_t FromHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap32(value);
+#endif
+}
+
+inline uint64_t FromHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap64(value);
+#endif
+}
+
+inline uint16_t ToHost(uint16_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap16(value);
+#endif
+}
+
+inline uint32_t ToHost(uint32_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap32(value);
+#endif
+}
+
+inline uint64_t ToHost(uint64_t value) {
+#if defined(PROTOBUF_BIG_ENDIAN)
+  return value;
+#else
+  return BSwap64(value);
+#endif
+}
+
+}  // namespace big_endian
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ENDIAN_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/explicitly_constructed.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/explicitly_constructed.h
new file mode 100644
index 0000000..174c59a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/explicitly_constructed.h
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_EXPLICITLY_CONSTRUCTED_H__
+#define GOOGLE_PROTOBUF_EXPLICITLY_CONSTRUCTED_H__
+
+#include <stdint.h>
+
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Wraps a variable whose constructor and destructor are explicitly
+// called. It is particularly useful for a global variable, without its
+// constructor and destructor run on start and end of the program lifetime.
+// This circumvents the initial construction order fiasco, while keeping
+// the address of the empty string a compile time constant.
+//
+// Pay special attention to the initialization state of the object.
+// 1. The object is "uninitialized" to begin with.
+// 2. Call Construct() or DefaultConstruct() only if the object is
+//    uninitialized. After the call, the object becomes "initialized".
+// 3. Call get() and get_mutable() only if the object is initialized.
+// 4. Call Destruct() only if the object is initialized.
+//    After the call, the object becomes uninitialized.
+template <typename T, size_t min_align = 1>
+class ExplicitlyConstructed {
+ public:
+  void DefaultConstruct() { new (&union_) T(); }
+
+  template <typename... Args>
+  void Construct(Args&&... args) {
+    new (&union_) T(std::forward<Args>(args)...);
+  }
+
+  void Destruct() { get_mutable()->~T(); }
+
+  constexpr const T& get() const { return reinterpret_cast<const T&>(union_); }
+  T* get_mutable() { return reinterpret_cast<T*>(&union_); }
+
+ private:
+  union AlignedUnion {
+    alignas(min_align > alignof(T) ? min_align
+                                   : alignof(T)) char space[sizeof(T)];
+    int64_t align_to_int64;
+    void* align_to_ptr;
+  } union_;
+};
+
+// ArenaStringPtr compatible explicitly constructed string type.
+// This empty string type is aligned with a minimum alignment of 8 bytes
+// which is the minimum requirement of ArenaStringPtr
+using ExplicitlyConstructedArenaString = ExplicitlyConstructed<std::string, 8>;
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_EXPLICITLY_CONSTRUCTED_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/extension_set.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/extension_set.h
new file mode 100644
index 0000000..b534368
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/extension_set.h
@@ -0,0 +1,1561 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+
+#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__
+#define GOOGLE_PROTOBUF_EXTENSION_SET_H__
+
+
+#include <algorithm>
+#include <cassert>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>  // Must be last
+// clang-format on
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class Arena;
+class Descriptor;       // descriptor.h
+class FieldDescriptor;  // descriptor.h
+class DescriptorPool;   // descriptor.h
+class MessageLite;      // message_lite.h
+class Message;          // message.h
+class MessageFactory;   // message.h
+class Reflection;       // message.h
+class UnknownFieldSet;  // unknown_field_set.h
+namespace internal {
+class FieldSkipper;  // wire_format_lite.h
+enum class LazyVerifyOption;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class InternalMetadata;
+
+// Used to store values of type WireFormatLite::FieldType without having to
+// #include wire_format_lite.h.  Also, ensures that we use only one byte to
+// store these values, which is important to keep the layout of
+// ExtensionSet::Extension small.
+typedef uint8_t FieldType;
+
+// A function which, given an integer value, returns true if the number
+// matches one of the defined values for the corresponding enum type.  This
+// is used with RegisterEnumExtension, below.
+typedef bool EnumValidityFunc(int number);
+
+// Version of the above which takes an argument.  This is needed to deal with
+// extensions that are not compiled in.
+typedef bool EnumValidityFuncWithArg(const void* arg, int number);
+
+// Information about a registered extension.
+struct ExtensionInfo {
+  constexpr ExtensionInfo() : enum_validity_check() {}
+  constexpr ExtensionInfo(const MessageLite* extendee, int param_number,
+                          FieldType type_param, bool isrepeated, bool ispacked,
+                          LazyEagerVerifyFnType verify_func)
+      : message(extendee),
+        number(param_number),
+        type(type_param),
+        is_repeated(isrepeated),
+        is_packed(ispacked),
+        enum_validity_check(),
+        lazy_eager_verify_func(verify_func) {}
+
+  const MessageLite* message = nullptr;
+  int number = 0;
+
+  FieldType type = 0;
+  bool is_repeated = false;
+  bool is_packed = false;
+
+  struct EnumValidityCheck {
+    EnumValidityFuncWithArg* func;
+    const void* arg;
+  };
+
+  struct MessageInfo {
+    const MessageLite* prototype;
+  };
+
+  union {
+    EnumValidityCheck enum_validity_check;
+    MessageInfo message_info;
+  };
+
+  // The descriptor for this extension, if one exists and is known.  May be
+  // nullptr.  Must not be nullptr if the descriptor for the extension does not
+  // live in the same pool as the descriptor for the containing type.
+  const FieldDescriptor* descriptor = nullptr;
+
+  // If this field is potentially lazy this function can be used as a cheap
+  // verification of the raw bytes.
+  // If nullptr then no verification is performed.
+  LazyEagerVerifyFnType lazy_eager_verify_func = nullptr;
+};
+
+// An ExtensionFinder is an object which looks up extension definitions.  It
+// must implement this method:
+//
+// bool Find(int number, ExtensionInfo* output);
+
+// GeneratedExtensionFinder is an ExtensionFinder which finds extensions
+// defined in .proto files which have been compiled into the binary.
+class PROTOBUF_EXPORT GeneratedExtensionFinder {
+ public:
+  explicit GeneratedExtensionFinder(const MessageLite* extendee)
+      : extendee_(extendee) {}
+
+  // Returns true and fills in *output if found, otherwise returns false.
+  bool Find(int number, ExtensionInfo* output);
+
+ private:
+  const MessageLite* extendee_;
+};
+
+// Note:  extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
+// finding extensions from a DescriptorPool.
+
+// This is an internal helper class intended for use within the protocol buffer
+// library and generated classes.  Clients should not use it directly.  Instead,
+// use the generated accessors such as GetExtension() of the class being
+// extended.
+//
+// This class manages extensions for a protocol message object.  The
+// message's HasExtension(), GetExtension(), MutableExtension(), and
+// ClearExtension() methods are just thin wrappers around the embedded
+// ExtensionSet.  When parsing, if a tag number is encountered which is
+// inside one of the message type's extension ranges, the tag is passed
+// off to the ExtensionSet for parsing.  Etc.
+class PROTOBUF_EXPORT ExtensionSet {
+ public:
+  constexpr ExtensionSet();
+  explicit ExtensionSet(Arena* arena);
+  ExtensionSet(ArenaInitialized, Arena* arena) : ExtensionSet(arena) {}
+  ~ExtensionSet();
+
+  // These are called at startup by protocol-compiler-generated code to
+  // register known extensions.  The registrations are used by ParseField()
+  // to look up extensions for parsed field numbers.  Note that dynamic parsing
+  // does not use ParseField(); only protocol-compiler-generated parsing
+  // methods do.
+  static void RegisterExtension(const MessageLite* extendee, int number,
+                                FieldType type, bool is_repeated,
+                                bool is_packed,
+                                LazyEagerVerifyFnType verify_func);
+  static void RegisterEnumExtension(const MessageLite* extendee, int number,
+                                    FieldType type, bool is_repeated,
+                                    bool is_packed, EnumValidityFunc* is_valid);
+  static void RegisterMessageExtension(const MessageLite* extendee, int number,
+                                       FieldType type, bool is_repeated,
+                                       bool is_packed,
+                                       const MessageLite* prototype,
+                                       LazyEagerVerifyFnType verify_func);
+
+  // =================================================================
+
+  // Add all fields which are currently present to the given vector.  This
+  // is useful to implement Reflection::ListFields().
+  void AppendToList(const Descriptor* extendee, const DescriptorPool* pool,
+                    std::vector<const FieldDescriptor*>* output) const;
+
+  // =================================================================
+  // Accessors
+  //
+  // Generated message classes include type-safe templated wrappers around
+  // these methods.  Generally you should use those rather than call these
+  // directly, unless you are doing low-level memory management.
+  //
+  // When calling any of these accessors, the extension number requested
+  // MUST exist in the DescriptorPool provided to the constructor.  Otherwise,
+  // the method will fail an assert.  Normally, though, you would not call
+  // these directly; you would either call the generated accessors of your
+  // message class (e.g. GetExtension()) or you would call the accessors
+  // of the reflection interface.  In both cases, it is impossible to
+  // trigger this assert failure:  the generated accessors only accept
+  // linked-in extension types as parameters, while the Reflection interface
+  // requires you to provide the FieldDescriptor describing the extension.
+  //
+  // When calling any of these accessors, a protocol-compiler-generated
+  // implementation of the extension corresponding to the number MUST
+  // be linked in, and the FieldDescriptor used to refer to it MUST be
+  // the one generated by that linked-in code.  Otherwise, the method will
+  // die on an assert failure.  The message objects returned by the message
+  // accessors are guaranteed to be of the correct linked-in type.
+  //
+  // These methods pretty much match Reflection except that:
+  // - They're not virtual.
+  // - They identify fields by number rather than FieldDescriptors.
+  // - They identify enum values using integers rather than descriptors.
+  // - Strings provide Mutable() in addition to Set() accessors.
+
+  bool Has(int number) const;
+  int ExtensionSize(int number) const;  // Size of a repeated extension.
+  int NumExtensions() const;            // The number of extensions
+  FieldType ExtensionType(int number) const;
+  void ClearExtension(int number);
+
+  // singular fields -------------------------------------------------
+
+  int32_t GetInt32(int number, int32_t default_value) const;
+  int64_t GetInt64(int number, int64_t default_value) const;
+  uint32_t GetUInt32(int number, uint32_t default_value) const;
+  uint64_t GetUInt64(int number, uint64_t default_value) const;
+  float GetFloat(int number, float default_value) const;
+  double GetDouble(int number, double default_value) const;
+  bool GetBool(int number, bool default_value) const;
+  int GetEnum(int number, int default_value) const;
+  const std::string& GetString(int number,
+                               const std::string& default_value) const;
+  const MessageLite& GetMessage(int number,
+                                const MessageLite& default_value) const;
+  const MessageLite& GetMessage(int number, const Descriptor* message_type,
+                                MessageFactory* factory) const;
+
+  // |descriptor| may be nullptr so long as it is known that the descriptor for
+  // the extension lives in the same pool as the descriptor for the containing
+  // type.
+#define desc const FieldDescriptor* descriptor  // avoid line wrapping
+  void SetInt32(int number, FieldType type, int32_t value, desc);
+  void SetInt64(int number, FieldType type, int64_t value, desc);
+  void SetUInt32(int number, FieldType type, uint32_t value, desc);
+  void SetUInt64(int number, FieldType type, uint64_t value, desc);
+  void SetFloat(int number, FieldType type, float value, desc);
+  void SetDouble(int number, FieldType type, double value, desc);
+  void SetBool(int number, FieldType type, bool value, desc);
+  void SetEnum(int number, FieldType type, int value, desc);
+  void SetString(int number, FieldType type, std::string value, desc);
+  std::string* MutableString(int number, FieldType type, desc);
+  MessageLite* MutableMessage(int number, FieldType type,
+                              const MessageLite& prototype, desc);
+  MessageLite* MutableMessage(const FieldDescriptor* descriptor,
+                              MessageFactory* factory);
+  // Adds the given message to the ExtensionSet, taking ownership of the
+  // message object. Existing message with the same number will be deleted.
+  // If "message" is nullptr, this is equivalent to "ClearExtension(number)".
+  void SetAllocatedMessage(int number, FieldType type,
+                           const FieldDescriptor* descriptor,
+                           MessageLite* message);
+  void UnsafeArenaSetAllocatedMessage(int number, FieldType type,
+                                      const FieldDescriptor* descriptor,
+                                      MessageLite* message);
+  PROTOBUF_NODISCARD MessageLite* ReleaseMessage(int number,
+                                                 const MessageLite& prototype);
+  MessageLite* UnsafeArenaReleaseMessage(int number,
+                                         const MessageLite& prototype);
+
+  PROTOBUF_NODISCARD MessageLite* ReleaseMessage(
+      const FieldDescriptor* descriptor, MessageFactory* factory);
+  MessageLite* UnsafeArenaReleaseMessage(const FieldDescriptor* descriptor,
+                                         MessageFactory* factory);
+#undef desc
+  Arena* GetArena() const { return arena_; }
+
+  // repeated fields -------------------------------------------------
+
+  // Fetches a RepeatedField extension by number; returns |default_value|
+  // if no such extension exists. User should not touch this directly; it is
+  // used by the GetRepeatedExtension() method.
+  const void* GetRawRepeatedField(int number, const void* default_value) const;
+  // Fetches a mutable version of a RepeatedField extension by number,
+  // instantiating one if none exists. Similar to above, user should not use
+  // this directly; it underlies MutableRepeatedExtension().
+  void* MutableRawRepeatedField(int number, FieldType field_type, bool packed,
+                                const FieldDescriptor* desc);
+
+  // This is an overload of MutableRawRepeatedField to maintain compatibility
+  // with old code using a previous API. This version of
+  // MutableRawRepeatedField() will GOOGLE_CHECK-fail on a missing extension.
+  // (E.g.: borg/clients/internal/proto1/proto2_reflection.cc.)
+  void* MutableRawRepeatedField(int number);
+
+  int32_t GetRepeatedInt32(int number, int index) const;
+  int64_t GetRepeatedInt64(int number, int index) const;
+  uint32_t GetRepeatedUInt32(int number, int index) const;
+  uint64_t GetRepeatedUInt64(int number, int index) const;
+  float GetRepeatedFloat(int number, int index) const;
+  double GetRepeatedDouble(int number, int index) const;
+  bool GetRepeatedBool(int number, int index) const;
+  int GetRepeatedEnum(int number, int index) const;
+  const std::string& GetRepeatedString(int number, int index) const;
+  const MessageLite& GetRepeatedMessage(int number, int index) const;
+
+  void SetRepeatedInt32(int number, int index, int32_t value);
+  void SetRepeatedInt64(int number, int index, int64_t value);
+  void SetRepeatedUInt32(int number, int index, uint32_t value);
+  void SetRepeatedUInt64(int number, int index, uint64_t value);
+  void SetRepeatedFloat(int number, int index, float value);
+  void SetRepeatedDouble(int number, int index, double value);
+  void SetRepeatedBool(int number, int index, bool value);
+  void SetRepeatedEnum(int number, int index, int value);
+  void SetRepeatedString(int number, int index, std::string value);
+  std::string* MutableRepeatedString(int number, int index);
+  MessageLite* MutableRepeatedMessage(int number, int index);
+
+#define desc const FieldDescriptor* descriptor  // avoid line wrapping
+  void AddInt32(int number, FieldType type, bool packed, int32_t value, desc);
+  void AddInt64(int number, FieldType type, bool packed, int64_t value, desc);
+  void AddUInt32(int number, FieldType type, bool packed, uint32_t value, desc);
+  void AddUInt64(int number, FieldType type, bool packed, uint64_t value, desc);
+  void AddFloat(int number, FieldType type, bool packed, float value, desc);
+  void AddDouble(int number, FieldType type, bool packed, double value, desc);
+  void AddBool(int number, FieldType type, bool packed, bool value, desc);
+  void AddEnum(int number, FieldType type, bool packed, int value, desc);
+  void AddString(int number, FieldType type, std::string value, desc);
+  std::string* AddString(int number, FieldType type, desc);
+  MessageLite* AddMessage(int number, FieldType type,
+                          const MessageLite& prototype, desc);
+  MessageLite* AddMessage(const FieldDescriptor* descriptor,
+                          MessageFactory* factory);
+  void AddAllocatedMessage(const FieldDescriptor* descriptor,
+                           MessageLite* new_entry);
+  void UnsafeArenaAddAllocatedMessage(const FieldDescriptor* descriptor,
+                                      MessageLite* new_entry);
+#undef desc
+
+  void RemoveLast(int number);
+  PROTOBUF_NODISCARD MessageLite* ReleaseLast(int number);
+  MessageLite* UnsafeArenaReleaseLast(int number);
+  void SwapElements(int number, int index1, int index2);
+
+  // =================================================================
+  // convenience methods for implementing methods of Message
+  //
+  // These could all be implemented in terms of the other methods of this
+  // class, but providing them here helps keep the generated code size down.
+
+  void Clear();
+  void MergeFrom(const MessageLite* extendee, const ExtensionSet& other);
+  void Swap(const MessageLite* extendee, ExtensionSet* other);
+  void InternalSwap(ExtensionSet* other);
+  void SwapExtension(const MessageLite* extendee, ExtensionSet* other,
+                     int number);
+  void UnsafeShallowSwapExtension(ExtensionSet* other, int number);
+  bool IsInitialized() const;
+
+  // Lite parser
+  const char* ParseField(uint64_t tag, const char* ptr,
+                         const MessageLite* extendee,
+                         internal::InternalMetadata* metadata,
+                         internal::ParseContext* ctx);
+  // Full parser
+  const char* ParseField(uint64_t tag, const char* ptr, const Message* extendee,
+                         internal::InternalMetadata* metadata,
+                         internal::ParseContext* ctx);
+  template <typename Msg>
+  const char* ParseMessageSet(const char* ptr, const Msg* extendee,
+                              InternalMetadata* metadata,
+                              internal::ParseContext* ctx) {
+    struct MessageSetItem {
+      const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+        return me->ParseMessageSetItem(ptr, extendee, metadata, ctx);
+      }
+      ExtensionSet* me;
+      const Msg* extendee;
+      InternalMetadata* metadata;
+    } item{this, extendee, metadata};
+    while (!ctx->Done(&ptr)) {
+      uint32_t tag;
+      ptr = ReadTag(ptr, &tag);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (tag == WireFormatLite::kMessageSetItemStartTag) {
+        ptr = ctx->ParseGroup(&item, ptr, tag);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      } else {
+        if (tag == 0 || (tag & 7) == 4) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        ptr = ParseField(tag, ptr, extendee, metadata, ctx);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      }
+    }
+    return ptr;
+  }
+
+  // Write all extension fields with field numbers in the range
+  //   [start_field_number, end_field_number)
+  // to the output stream, using the cached sizes computed when ByteSize() was
+  // last called.  Note that the range bounds are inclusive-exclusive.
+  void SerializeWithCachedSizes(const MessageLite* extendee,
+                                int start_field_number, int end_field_number,
+                                io::CodedOutputStream* output) const {
+    output->SetCur(_InternalSerialize(extendee, start_field_number,
+                                      end_field_number, output->Cur(),
+                                      output->EpsCopy()));
+  }
+
+  // Same as SerializeWithCachedSizes, but without any bounds checking.
+  // The caller must ensure that target has sufficient capacity for the
+  // serialized extensions.
+  //
+  // Returns a pointer past the last written byte.
+
+  uint8_t* _InternalSerialize(const MessageLite* extendee,
+                              int start_field_number, int end_field_number,
+                              uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const {
+    if (flat_size_ == 0) {
+      assert(!is_large());
+      return target;
+    }
+    return _InternalSerializeImpl(extendee, start_field_number,
+                                  end_field_number, target, stream);
+  }
+
+  // Like above but serializes in MessageSet format.
+  void SerializeMessageSetWithCachedSizes(const MessageLite* extendee,
+                                          io::CodedOutputStream* output) const {
+    output->SetCur(InternalSerializeMessageSetWithCachedSizesToArray(
+        extendee, output->Cur(), output->EpsCopy()));
+  }
+  uint8_t* InternalSerializeMessageSetWithCachedSizesToArray(
+      const MessageLite* extendee, uint8_t* target,
+      io::EpsCopyOutputStream* stream) const;
+
+  // For backward-compatibility, versions of two of the above methods that
+  // serialize deterministically iff SetDefaultSerializationDeterministic()
+  // has been called.
+  uint8_t* SerializeWithCachedSizesToArray(int start_field_number,
+                                           int end_field_number,
+                                           uint8_t* target) const;
+  uint8_t* SerializeMessageSetWithCachedSizesToArray(
+      const MessageLite* extendee, uint8_t* target) const;
+
+  // Returns the total serialized size of all the extensions.
+  size_t ByteSize() const;
+
+  // Like ByteSize() but uses MessageSet format.
+  size_t MessageSetByteSize() const;
+
+  // Returns (an estimate of) the total number of bytes used for storing the
+  // extensions in memory, excluding sizeof(*this).  If the ExtensionSet is
+  // for a lite message (and thus possibly contains lite messages), the results
+  // are undefined (might work, might crash, might corrupt data, might not even
+  // be linked in).  It's up to the protocol compiler to avoid calling this on
+  // such ExtensionSets (easy enough since lite messages don't implement
+  // SpaceUsed()).
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  // This method just calls SpaceUsedExcludingSelfLong() but it can not be
+  // inlined because the definition of SpaceUsedExcludingSelfLong() is not
+  // included in lite runtime and when an inline method refers to it MSVC
+  // will complain about unresolved symbols when building the lite runtime
+  // as .dll.
+  int SpaceUsedExcludingSelf() const;
+
+ private:
+  template <typename Type>
+  friend class PrimitiveTypeTraits;
+
+  template <typename Type>
+  friend class RepeatedPrimitiveTypeTraits;
+
+  template <typename Type, bool IsValid(int)>
+  friend class EnumTypeTraits;
+
+  template <typename Type, bool IsValid(int)>
+  friend class RepeatedEnumTypeTraits;
+
+  friend class google::protobuf::Reflection;
+
+  const int32_t& GetRefInt32(int number, const int32_t& default_value) const;
+  const int64_t& GetRefInt64(int number, const int64_t& default_value) const;
+  const uint32_t& GetRefUInt32(int number, const uint32_t& default_value) const;
+  const uint64_t& GetRefUInt64(int number, const uint64_t& default_value) const;
+  const float& GetRefFloat(int number, const float& default_value) const;
+  const double& GetRefDouble(int number, const double& default_value) const;
+  const bool& GetRefBool(int number, const bool& default_value) const;
+  const int& GetRefEnum(int number, const int& default_value) const;
+  const int32_t& GetRefRepeatedInt32(int number, int index) const;
+  const int64_t& GetRefRepeatedInt64(int number, int index) const;
+  const uint32_t& GetRefRepeatedUInt32(int number, int index) const;
+  const uint64_t& GetRefRepeatedUInt64(int number, int index) const;
+  const float& GetRefRepeatedFloat(int number, int index) const;
+  const double& GetRefRepeatedDouble(int number, int index) const;
+  const bool& GetRefRepeatedBool(int number, int index) const;
+  const int& GetRefRepeatedEnum(int number, int index) const;
+
+  // Implementation of _InternalSerialize for non-empty map_.
+  uint8_t* _InternalSerializeImpl(const MessageLite* extendee,
+                                  int start_field_number, int end_field_number,
+                                  uint8_t* target,
+                                  io::EpsCopyOutputStream* stream) const;
+  // Interface of a lazily parsed singular message extension.
+  class PROTOBUF_EXPORT LazyMessageExtension {
+   public:
+    LazyMessageExtension() {}
+    virtual ~LazyMessageExtension() {}
+
+    virtual LazyMessageExtension* New(Arena* arena) const = 0;
+    virtual const MessageLite& GetMessage(const MessageLite& prototype,
+                                          Arena* arena) const = 0;
+    virtual MessageLite* MutableMessage(const MessageLite& prototype,
+                                        Arena* arena) = 0;
+    virtual void SetAllocatedMessage(MessageLite* message, Arena* arena) = 0;
+    virtual void UnsafeArenaSetAllocatedMessage(MessageLite* message,
+                                                Arena* arena) = 0;
+    PROTOBUF_NODISCARD virtual MessageLite* ReleaseMessage(
+        const MessageLite& prototype, Arena* arena) = 0;
+    virtual MessageLite* UnsafeArenaReleaseMessage(const MessageLite& prototype,
+                                                   Arena* arena) = 0;
+
+    virtual bool IsInitialized() const = 0;
+
+    PROTOBUF_DEPRECATED_MSG("Please use ByteSizeLong() instead")
+    virtual int ByteSize() const { return internal::ToIntSize(ByteSizeLong()); }
+    virtual size_t ByteSizeLong() const = 0;
+    virtual size_t SpaceUsedLong() const = 0;
+
+    virtual void MergeFrom(const MessageLite* prototype,
+                           const LazyMessageExtension& other, Arena* arena) = 0;
+    virtual void MergeFromMessage(const MessageLite& msg, Arena* arena) = 0;
+    virtual void Clear() = 0;
+
+    virtual const char* _InternalParse(const Message& prototype, Arena* arena,
+                                       LazyVerifyOption option, const char* ptr,
+                                       ParseContext* ctx) = 0;
+    virtual uint8_t* WriteMessageToArray(
+        const MessageLite* prototype, int number, uint8_t* target,
+        io::EpsCopyOutputStream* stream) const = 0;
+
+   private:
+    virtual void UnusedKeyMethod();  // Dummy key method to avoid weak vtable.
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
+  };
+  // Give access to function defined below to see LazyMessageExtension.
+  friend LazyMessageExtension* MaybeCreateLazyExtension(Arena* arena);
+  struct Extension {
+    // The order of these fields packs Extension into 24 bytes when using 8
+    // byte alignment. Consider this when adding or removing fields here.
+    union {
+      int32_t int32_t_value;
+      int64_t int64_t_value;
+      uint32_t uint32_t_value;
+      uint64_t uint64_t_value;
+      float float_value;
+      double double_value;
+      bool bool_value;
+      int enum_value;
+      std::string* string_value;
+      MessageLite* message_value;
+      LazyMessageExtension* lazymessage_value;
+
+      RepeatedField<int32_t>* repeated_int32_t_value;
+      RepeatedField<int64_t>* repeated_int64_t_value;
+      RepeatedField<uint32_t>* repeated_uint32_t_value;
+      RepeatedField<uint64_t>* repeated_uint64_t_value;
+      RepeatedField<float>* repeated_float_value;
+      RepeatedField<double>* repeated_double_value;
+      RepeatedField<bool>* repeated_bool_value;
+      RepeatedField<int>* repeated_enum_value;
+      RepeatedPtrField<std::string>* repeated_string_value;
+      RepeatedPtrField<MessageLite>* repeated_message_value;
+    };
+
+    FieldType type;
+    bool is_repeated;
+
+    // For singular types, indicates if the extension is "cleared".  This
+    // happens when an extension is set and then later cleared by the caller.
+    // We want to keep the Extension object around for reuse, so instead of
+    // removing it from the map, we just set is_cleared = true.  This has no
+    // meaning for repeated types; for those, the size of the RepeatedField
+    // simply becomes zero when cleared.
+    bool is_cleared : 4;
+
+    // For singular message types, indicates whether lazy parsing is enabled
+    // for this extension. This field is only valid when type == TYPE_MESSAGE
+    // and !is_repeated because we only support lazy parsing for singular
+    // message types currently. If is_lazy = true, the extension is stored in
+    // lazymessage_value. Otherwise, the extension will be message_value.
+    bool is_lazy : 4;
+
+    // For repeated types, this indicates if the [packed=true] option is set.
+    bool is_packed;
+
+    // For packed fields, the size of the packed data is recorded here when
+    // ByteSize() is called then used during serialization.
+    // TODO(kenton):  Use atomic<int> when C++ supports it.
+    mutable int cached_size;
+
+    // The descriptor for this extension, if one exists and is known.  May be
+    // nullptr.  Must not be nullptr if the descriptor for the extension does
+    // not live in the same pool as the descriptor for the containing type.
+    const FieldDescriptor* descriptor;
+
+    // Some helper methods for operations on a single Extension.
+    uint8_t* InternalSerializeFieldWithCachedSizesToArray(
+        const MessageLite* extendee, const ExtensionSet* extension_set,
+        int number, uint8_t* target, io::EpsCopyOutputStream* stream) const;
+    uint8_t* InternalSerializeMessageSetItemWithCachedSizesToArray(
+        const MessageLite* extendee, const ExtensionSet* extension_set,
+        int number, uint8_t* target, io::EpsCopyOutputStream* stream) const;
+    size_t ByteSize(int number) const;
+    size_t MessageSetItemByteSize(int number) const;
+    void Clear();
+    int GetSize() const;
+    void Free();
+    size_t SpaceUsedExcludingSelfLong() const;
+    bool IsInitialized() const;
+  };
+
+  // The Extension struct is small enough to be passed by value, so we use it
+  // directly as the value type in mappings rather than use pointers.  We use
+  // sorted maps rather than hash-maps because we expect most ExtensionSets will
+  // only contain a small number of extension.  Also, we want AppendToList and
+  // deterministic serialization to order fields by field number.
+
+  struct KeyValue {
+    int first;
+    Extension second;
+
+    struct FirstComparator {
+      bool operator()(const KeyValue& lhs, const KeyValue& rhs) const {
+        return lhs.first < rhs.first;
+      }
+      bool operator()(const KeyValue& lhs, int key) const {
+        return lhs.first < key;
+      }
+      bool operator()(int key, const KeyValue& rhs) const {
+        return key < rhs.first;
+      }
+    };
+  };
+
+  typedef std::map<int, Extension> LargeMap;
+
+  // Wrapper API that switches between flat-map and LargeMap.
+
+  // Finds a key (if present) in the ExtensionSet.
+  const Extension* FindOrNull(int key) const;
+  Extension* FindOrNull(int key);
+
+  // Helper-functions that only inspect the LargeMap.
+  const Extension* FindOrNullInLargeMap(int key) const;
+  Extension* FindOrNullInLargeMap(int key);
+
+  // Inserts a new (key, Extension) into the ExtensionSet (and returns true), or
+  // finds the already-existing Extension for that key (returns false).
+  // The Extension* will point to the new-or-found Extension.
+  std::pair<Extension*, bool> Insert(int key);
+
+  // Grows the flat_capacity_.
+  // If flat_capacity_ > kMaximumFlatCapacity, converts to LargeMap.
+  void GrowCapacity(size_t minimum_new_capacity);
+  static constexpr uint16_t kMaximumFlatCapacity = 256;
+  bool is_large() const { return static_cast<int16_t>(flat_size_) < 0; }
+
+  // Removes a key from the ExtensionSet.
+  void Erase(int key);
+
+  size_t Size() const {
+    return PROTOBUF_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_;
+  }
+
+  // Similar to std::for_each.
+  // Each Iterator is decomposed into ->first and ->second fields, so
+  // that the KeyValueFunctor can be agnostic vis-a-vis KeyValue-vs-std::pair.
+  template <typename Iterator, typename KeyValueFunctor>
+  static KeyValueFunctor ForEach(Iterator begin, Iterator end,
+                                 KeyValueFunctor func) {
+    for (Iterator it = begin; it != end; ++it) func(it->first, it->second);
+    return func;
+  }
+
+  // Applies a functor to the <int, Extension&> pairs in sorted order.
+  template <typename KeyValueFunctor>
+  KeyValueFunctor ForEach(KeyValueFunctor func) {
+    if (PROTOBUF_PREDICT_FALSE(is_large())) {
+      return ForEach(map_.large->begin(), map_.large->end(), std::move(func));
+    }
+    return ForEach(flat_begin(), flat_end(), std::move(func));
+  }
+
+  // Applies a functor to the <int, const Extension&> pairs in sorted order.
+  template <typename KeyValueFunctor>
+  KeyValueFunctor ForEach(KeyValueFunctor func) const {
+    if (PROTOBUF_PREDICT_FALSE(is_large())) {
+      return ForEach(map_.large->begin(), map_.large->end(), std::move(func));
+    }
+    return ForEach(flat_begin(), flat_end(), std::move(func));
+  }
+
+  // Merges existing Extension from other_extension
+  void InternalExtensionMergeFrom(const MessageLite* extendee, int number,
+                                  const Extension& other_extension,
+                                  Arena* other_arena);
+
+  inline static bool is_packable(WireFormatLite::WireType type) {
+    switch (type) {
+      case WireFormatLite::WIRETYPE_VARINT:
+      case WireFormatLite::WIRETYPE_FIXED64:
+      case WireFormatLite::WIRETYPE_FIXED32:
+        return true;
+      case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
+      case WireFormatLite::WIRETYPE_START_GROUP:
+      case WireFormatLite::WIRETYPE_END_GROUP:
+        return false;
+
+        // Do not add a default statement. Let the compiler complain when
+        // someone
+        // adds a new wire type.
+    }
+    PROTOBUF_ASSUME(false);  // switch handles all possible enum values
+    return false;
+  }
+
+  // Returns true and fills field_number and extension if extension is found.
+  // Note to support packed repeated field compatibility, it also fills whether
+  // the tag on wire is packed, which can be different from
+  // extension->is_packed (whether packed=true is specified).
+  template <typename ExtensionFinder>
+  bool FindExtensionInfoFromTag(uint32_t tag, ExtensionFinder* extension_finder,
+                                int* field_number, ExtensionInfo* extension,
+                                bool* was_packed_on_wire) {
+    *field_number = WireFormatLite::GetTagFieldNumber(tag);
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+    return FindExtensionInfoFromFieldNumber(wire_type, *field_number,
+                                            extension_finder, extension,
+                                            was_packed_on_wire);
+  }
+
+  // Returns true and fills extension if extension is found.
+  // Note to support packed repeated field compatibility, it also fills whether
+  // the tag on wire is packed, which can be different from
+  // extension->is_packed (whether packed=true is specified).
+  template <typename ExtensionFinder>
+  bool FindExtensionInfoFromFieldNumber(int wire_type, int field_number,
+                                        ExtensionFinder* extension_finder,
+                                        ExtensionInfo* extension,
+                                        bool* was_packed_on_wire) const {
+    if (!extension_finder->Find(field_number, extension)) {
+      return false;
+    }
+
+    GOOGLE_DCHECK(extension->type > 0 &&
+           extension->type <= WireFormatLite::MAX_FIELD_TYPE);
+    auto real_type = static_cast<WireFormatLite::FieldType>(extension->type);
+
+    WireFormatLite::WireType expected_wire_type =
+        WireFormatLite::WireTypeForFieldType(real_type);
+
+    // Check if this is a packed field.
+    *was_packed_on_wire = false;
+    if (extension->is_repeated &&
+        wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED &&
+        is_packable(expected_wire_type)) {
+      *was_packed_on_wire = true;
+      return true;
+    }
+    // Otherwise the wire type must match.
+    return expected_wire_type == wire_type;
+  }
+
+  // Find the prototype for a LazyMessage from the extension registry. Returns
+  // null if the extension is not found.
+  const MessageLite* GetPrototypeForLazyMessage(const MessageLite* extendee,
+                                                int number) const;
+
+  // Returns true if extension is present and lazy.
+  bool HasLazy(int number) const;
+
+  // Gets the extension with the given number, creating it if it does not
+  // already exist.  Returns true if the extension did not already exist.
+  bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
+                         Extension** result);
+
+  // Gets the repeated extension for the given descriptor, creating it if
+  // it does not exist.
+  Extension* MaybeNewRepeatedExtension(const FieldDescriptor* descriptor);
+
+  bool FindExtension(int wire_type, uint32_t field, const MessageLite* extendee,
+                     const internal::ParseContext* /*ctx*/,
+                     ExtensionInfo* extension, bool* was_packed_on_wire) {
+    GeneratedExtensionFinder finder(extendee);
+    return FindExtensionInfoFromFieldNumber(wire_type, field, &finder,
+                                            extension, was_packed_on_wire);
+  }
+  inline bool FindExtension(int wire_type, uint32_t field,
+                            const Message* extendee,
+                            const internal::ParseContext* ctx,
+                            ExtensionInfo* extension, bool* was_packed_on_wire);
+  // Used for MessageSet only
+  const char* ParseFieldMaybeLazily(uint64_t tag, const char* ptr,
+                                    const MessageLite* extendee,
+                                    internal::InternalMetadata* metadata,
+                                    internal::ParseContext* ctx) {
+    // Lite MessageSet doesn't implement lazy.
+    return ParseField(tag, ptr, extendee, metadata, ctx);
+  }
+  const char* ParseFieldMaybeLazily(uint64_t tag, const char* ptr,
+                                    const Message* extendee,
+                                    internal::InternalMetadata* metadata,
+                                    internal::ParseContext* ctx);
+  const char* ParseMessageSetItem(const char* ptr, const MessageLite* extendee,
+                                  internal::InternalMetadata* metadata,
+                                  internal::ParseContext* ctx);
+  const char* ParseMessageSetItem(const char* ptr, const Message* extendee,
+                                  internal::InternalMetadata* metadata,
+                                  internal::ParseContext* ctx);
+
+  // Implemented in extension_set_inl.h to keep code out of the header file.
+  template <typename T>
+  const char* ParseFieldWithExtensionInfo(int number, bool was_packed_on_wire,
+                                          const ExtensionInfo& info,
+                                          internal::InternalMetadata* metadata,
+                                          const char* ptr,
+                                          internal::ParseContext* ctx);
+  template <typename Msg, typename T>
+  const char* ParseMessageSetItemTmpl(const char* ptr, const Msg* extendee,
+                                      internal::InternalMetadata* metadata,
+                                      internal::ParseContext* ctx);
+
+  // Hack:  RepeatedPtrFieldBase declares ExtensionSet as a friend.  This
+  //   friendship should automatically extend to ExtensionSet::Extension, but
+  //   unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this
+  //   correctly.  So, we must provide helpers for calling methods of that
+  //   class.
+
+  // Defined in extension_set_heavy.cc.
+  static inline size_t RepeatedMessage_SpaceUsedExcludingSelfLong(
+      RepeatedPtrFieldBase* field);
+
+  KeyValue* flat_begin() {
+    assert(!is_large());
+    return map_.flat;
+  }
+  const KeyValue* flat_begin() const {
+    assert(!is_large());
+    return map_.flat;
+  }
+  KeyValue* flat_end() {
+    assert(!is_large());
+    return map_.flat + flat_size_;
+  }
+  const KeyValue* flat_end() const {
+    assert(!is_large());
+    return map_.flat + flat_size_;
+  }
+
+  Arena* arena_;
+
+  // Manual memory-management:
+  // map_.flat is an allocated array of flat_capacity_ elements.
+  // [map_.flat, map_.flat + flat_size_) is the currently-in-use prefix.
+  uint16_t flat_capacity_;
+  uint16_t flat_size_;  // negative int16_t(flat_size_) indicates is_large()
+  union AllocatedData {
+    KeyValue* flat;
+
+    // If flat_capacity_ > kMaximumFlatCapacity, switch to LargeMap,
+    // which guarantees O(n lg n) CPU but larger constant factors.
+    LargeMap* large;
+  } map_;
+
+  static void DeleteFlatMap(const KeyValue* flat, uint16_t flat_capacity);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
+};
+
+constexpr ExtensionSet::ExtensionSet()
+    : arena_(nullptr), flat_capacity_(0), flat_size_(0), map_{nullptr} {}
+
+// These are just for convenience...
+inline void ExtensionSet::SetString(int number, FieldType type,
+                                    std::string value,
+                                    const FieldDescriptor* descriptor) {
+  MutableString(number, type, descriptor)->assign(std::move(value));
+}
+inline void ExtensionSet::SetRepeatedString(int number, int index,
+                                            std::string value) {
+  MutableRepeatedString(number, index)->assign(std::move(value));
+}
+inline void ExtensionSet::AddString(int number, FieldType type,
+                                    std::string value,
+                                    const FieldDescriptor* descriptor) {
+  AddString(number, type, descriptor)->assign(std::move(value));
+}
+// ===================================================================
+// Glue for generated extension accessors
+
+// -------------------------------------------------------------------
+// Template magic
+
+// First we have a set of classes representing "type traits" for different
+// field types.  A type traits class knows how to implement basic accessors
+// for extensions of a particular type given an ExtensionSet.  The signature
+// for a type traits class looks like this:
+//
+//   class TypeTraits {
+//    public:
+//     typedef ? ConstType;
+//     typedef ? MutableType;
+//     // TypeTraits for singular fields and repeated fields will define the
+//     // symbol "Singular" or "Repeated" respectively. These two symbols will
+//     // be used in extension accessors to distinguish between singular
+//     // extensions and repeated extensions. If the TypeTraits for the passed
+//     // in extension doesn't have the expected symbol defined, it means the
+//     // user is passing a repeated extension to a singular accessor, or the
+//     // opposite. In that case the C++ compiler will generate an error
+//     // message "no matching member function" to inform the user.
+//     typedef ? Singular
+//     typedef ? Repeated
+//
+//     static inline ConstType Get(int number, const ExtensionSet& set);
+//     static inline void Set(int number, ConstType value, ExtensionSet* set);
+//     static inline MutableType Mutable(int number, ExtensionSet* set);
+//
+//     // Variants for repeated fields.
+//     static inline ConstType Get(int number, const ExtensionSet& set,
+//                                 int index);
+//     static inline void Set(int number, int index,
+//                            ConstType value, ExtensionSet* set);
+//     static inline MutableType Mutable(int number, int index,
+//                                       ExtensionSet* set);
+//     static inline void Add(int number, ConstType value, ExtensionSet* set);
+//     static inline MutableType Add(int number, ExtensionSet* set);
+//     This is used by the ExtensionIdentifier constructor to register
+//     the extension at dynamic initialization.
+//     template <typename ExtendeeT>
+//     static void Register(int number, FieldType type, bool is_packed);
+//   };
+//
+// Not all of these methods make sense for all field types.  For example, the
+// "Mutable" methods only make sense for strings and messages, and the
+// repeated methods only make sense for repeated types.  So, each type
+// traits class implements only the set of methods from this signature that it
+// actually supports.  This will cause a compiler error if the user tries to
+// access an extension using a method that doesn't make sense for its type.
+// For example, if "foo" is an extension of type "optional int32", then if you
+// try to write code like:
+//   my_message.MutableExtension(foo)
+// you will get a compile error because PrimitiveTypeTraits<int32_t> does not
+// have a "Mutable()" method.
+
+// -------------------------------------------------------------------
+// PrimitiveTypeTraits
+
+// Since the ExtensionSet has different methods for each primitive type,
+// we must explicitly define the methods of the type traits class for each
+// known type.
+template <typename Type>
+class PrimitiveTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef PrimitiveTypeTraits<Type> Singular;
+
+  static inline ConstType Get(int number, const ExtensionSet& set,
+                              ConstType default_value);
+
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        const ConstType& default_value);
+  static inline void Set(int number, FieldType field_type, ConstType value,
+                         ExtensionSet* set);
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, false, is_packed, verify_func);
+  }
+};
+
+template <typename Type>
+class RepeatedPrimitiveTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef RepeatedPrimitiveTypeTraits<Type> Repeated;
+
+  typedef RepeatedField<Type> RepeatedFieldType;
+
+  static inline Type Get(int number, const ExtensionSet& set, int index);
+  static inline const Type* GetPtr(int number, const ExtensionSet& set,
+                                   int index);
+  static inline const RepeatedField<ConstType>* GetRepeatedPtr(
+      int number, const ExtensionSet& set);
+  static inline void Set(int number, int index, Type value, ExtensionSet* set);
+  static inline void Add(int number, FieldType field_type, bool is_packed,
+                         Type value, ExtensionSet* set);
+
+  static inline const RepeatedField<ConstType>& GetRepeated(
+      int number, const ExtensionSet& set);
+  static inline RepeatedField<Type>* MutableRepeated(int number,
+                                                     FieldType field_type,
+                                                     bool is_packed,
+                                                     ExtensionSet* set);
+
+  static const RepeatedFieldType* GetDefaultRepeatedField();
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, true, is_packed, verify_func);
+  }
+};
+
+class PROTOBUF_EXPORT RepeatedPrimitiveDefaults {
+ private:
+  template <typename Type>
+  friend class RepeatedPrimitiveTypeTraits;
+  static const RepeatedPrimitiveDefaults* default_instance();
+  RepeatedField<int32_t> default_repeated_field_int32_t_;
+  RepeatedField<int64_t> default_repeated_field_int64_t_;
+  RepeatedField<uint32_t> default_repeated_field_uint32_t_;
+  RepeatedField<uint64_t> default_repeated_field_uint64_t_;
+  RepeatedField<double> default_repeated_field_double_;
+  RepeatedField<float> default_repeated_field_float_;
+  RepeatedField<bool> default_repeated_field_bool_;
+};
+
+#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD)                           \
+  template <>                                                                  \
+  inline TYPE PrimitiveTypeTraits<TYPE>::Get(                                  \
+      int number, const ExtensionSet& set, TYPE default_value) {               \
+    return set.Get##METHOD(number, default_value);                             \
+  }                                                                            \
+  template <>                                                                  \
+  inline const TYPE* PrimitiveTypeTraits<TYPE>::GetPtr(                        \
+      int number, const ExtensionSet& set, const TYPE& default_value) {        \
+    return &set.GetRef##METHOD(number, default_value);                         \
+  }                                                                            \
+  template <>                                                                  \
+  inline void PrimitiveTypeTraits<TYPE>::Set(int number, FieldType field_type, \
+                                             TYPE value, ExtensionSet* set) {  \
+    set->Set##METHOD(number, field_type, value, nullptr);                      \
+  }                                                                            \
+                                                                               \
+  template <>                                                                  \
+  inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get(                          \
+      int number, const ExtensionSet& set, int index) {                        \
+    return set.GetRepeated##METHOD(number, index);                             \
+  }                                                                            \
+  template <>                                                                  \
+  inline const TYPE* RepeatedPrimitiveTypeTraits<TYPE>::GetPtr(                \
+      int number, const ExtensionSet& set, int index) {                        \
+    return &set.GetRefRepeated##METHOD(number, index);                         \
+  }                                                                            \
+  template <>                                                                  \
+  inline void RepeatedPrimitiveTypeTraits<TYPE>::Set(                          \
+      int number, int index, TYPE value, ExtensionSet* set) {                  \
+    set->SetRepeated##METHOD(number, index, value);                            \
+  }                                                                            \
+  template <>                                                                  \
+  inline void RepeatedPrimitiveTypeTraits<TYPE>::Add(                          \
+      int number, FieldType field_type, bool is_packed, TYPE value,            \
+      ExtensionSet* set) {                                                     \
+    set->Add##METHOD(number, field_type, is_packed, value, nullptr);           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const RepeatedField<TYPE>*                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() {               \
+    return &RepeatedPrimitiveDefaults::default_instance()                      \
+                ->default_repeated_field_##TYPE##_;                            \
+  }                                                                            \
+  template <>                                                                  \
+  inline const RepeatedField<TYPE>&                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetRepeated(int number,                   \
+                                                 const ExtensionSet& set) {    \
+    return *reinterpret_cast<const RepeatedField<TYPE>*>(                      \
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const RepeatedField<TYPE>*                                            \
+  RepeatedPrimitiveTypeTraits<TYPE>::GetRepeatedPtr(int number,                \
+                                                    const ExtensionSet& set) { \
+    return &GetRepeated(number, set);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline RepeatedField<TYPE>*                                                  \
+  RepeatedPrimitiveTypeTraits<TYPE>::MutableRepeated(                          \
+      int number, FieldType field_type, bool is_packed, ExtensionSet* set) {   \
+    return reinterpret_cast<RepeatedField<TYPE>*>(                             \
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr)); \
+  }
+
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(int32_t, Int32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(int64_t, Int64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32_t, UInt32)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64_t, UInt64)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(float, Float)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double)
+PROTOBUF_DEFINE_PRIMITIVE_TYPE(bool, Bool)
+
+#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE
+
+// -------------------------------------------------------------------
+// StringTypeTraits
+
+// Strings support both Set() and Mutable().
+class PROTOBUF_EXPORT StringTypeTraits {
+ public:
+  typedef const std::string& ConstType;
+  typedef std::string* MutableType;
+  typedef StringTypeTraits Singular;
+
+  static inline const std::string& Get(int number, const ExtensionSet& set,
+                                       ConstType default_value) {
+    return set.GetString(number, default_value);
+  }
+  static inline const std::string* GetPtr(int number, const ExtensionSet& set,
+                                          ConstType default_value) {
+    return &Get(number, set, default_value);
+  }
+  static inline void Set(int number, FieldType field_type,
+                         const std::string& value, ExtensionSet* set) {
+    set->SetString(number, field_type, value, nullptr);
+  }
+  static inline std::string* Mutable(int number, FieldType field_type,
+                                     ExtensionSet* set) {
+    return set->MutableString(number, field_type, nullptr);
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, false, is_packed, verify_func);
+  }
+};
+
+class PROTOBUF_EXPORT RepeatedStringTypeTraits {
+ public:
+  typedef const std::string& ConstType;
+  typedef std::string* MutableType;
+  typedef RepeatedStringTypeTraits Repeated;
+
+  typedef RepeatedPtrField<std::string> RepeatedFieldType;
+
+  static inline const std::string& Get(int number, const ExtensionSet& set,
+                                       int index) {
+    return set.GetRepeatedString(number, index);
+  }
+  static inline const std::string* GetPtr(int number, const ExtensionSet& set,
+                                          int index) {
+    return &Get(number, set, index);
+  }
+  static inline const RepeatedPtrField<std::string>* GetRepeatedPtr(
+      int number, const ExtensionSet& set) {
+    return &GetRepeated(number, set);
+  }
+  static inline void Set(int number, int index, const std::string& value,
+                         ExtensionSet* set) {
+    set->SetRepeatedString(number, index, value);
+  }
+  static inline std::string* Mutable(int number, int index, ExtensionSet* set) {
+    return set->MutableRepeatedString(number, index);
+  }
+  static inline void Add(int number, FieldType field_type, bool /*is_packed*/,
+                         const std::string& value, ExtensionSet* set) {
+    set->AddString(number, field_type, value, nullptr);
+  }
+  static inline std::string* Add(int number, FieldType field_type,
+                                 ExtensionSet* set) {
+    return set->AddString(number, field_type, nullptr);
+  }
+  static inline const RepeatedPtrField<std::string>& GetRepeated(
+      int number, const ExtensionSet& set) {
+    return *reinterpret_cast<const RepeatedPtrField<std::string>*>(
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+  }
+
+  static inline RepeatedPtrField<std::string>* MutableRepeated(
+      int number, FieldType field_type, bool is_packed, ExtensionSet* set) {
+    return reinterpret_cast<RepeatedPtrField<std::string>*>(
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr));
+  }
+
+  static const RepeatedFieldType* GetDefaultRepeatedField();
+
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
+                                    type, true, is_packed, fn);
+  }
+
+ private:
+  static void InitializeDefaultRepeatedFields();
+  static void DestroyDefaultRepeatedFields();
+};
+
+// -------------------------------------------------------------------
+// EnumTypeTraits
+
+// ExtensionSet represents enums using integers internally, so we have to
+// static_cast around.
+template <typename Type, bool IsValid(int)>
+class EnumTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef EnumTypeTraits<Type, IsValid> Singular;
+
+  static inline ConstType Get(int number, const ExtensionSet& set,
+                              ConstType default_value) {
+    return static_cast<Type>(set.GetEnum(number, default_value));
+  }
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        const ConstType& default_value) {
+    return reinterpret_cast<const Type*>(
+        &set.GetRefEnum(number, default_value));
+  }
+  static inline void Set(int number, FieldType field_type, ConstType value,
+                         ExtensionSet* set) {
+    GOOGLE_DCHECK(IsValid(value));
+    set->SetEnum(number, field_type, value, nullptr);
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number,
+                                        type, false, is_packed, IsValid);
+  }
+};
+
+template <typename Type, bool IsValid(int)>
+class RepeatedEnumTypeTraits {
+ public:
+  typedef Type ConstType;
+  typedef Type MutableType;
+  typedef RepeatedEnumTypeTraits<Type, IsValid> Repeated;
+
+  typedef RepeatedField<Type> RepeatedFieldType;
+
+  static inline ConstType Get(int number, const ExtensionSet& set, int index) {
+    return static_cast<Type>(set.GetRepeatedEnum(number, index));
+  }
+  static inline const ConstType* GetPtr(int number, const ExtensionSet& set,
+                                        int index) {
+    return reinterpret_cast<const Type*>(
+        &set.GetRefRepeatedEnum(number, index));
+  }
+  static inline void Set(int number, int index, ConstType value,
+                         ExtensionSet* set) {
+    GOOGLE_DCHECK(IsValid(value));
+    set->SetRepeatedEnum(number, index, value);
+  }
+  static inline void Add(int number, FieldType field_type, bool is_packed,
+                         ConstType value, ExtensionSet* set) {
+    GOOGLE_DCHECK(IsValid(value));
+    set->AddEnum(number, field_type, is_packed, value, nullptr);
+  }
+  static inline const RepeatedField<Type>& GetRepeated(
+      int number, const ExtensionSet& set) {
+    // Hack: the `Extension` struct stores a RepeatedField<int> for enums.
+    // RepeatedField<int> cannot implicitly convert to RepeatedField<EnumType>
+    // so we need to do some casting magic. See message.h for similar
+    // contortions for non-extension fields.
+    return *reinterpret_cast<const RepeatedField<Type>*>(
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+  }
+  static inline const RepeatedField<Type>* GetRepeatedPtr(
+      int number, const ExtensionSet& set) {
+    return &GetRepeated(number, set);
+  }
+  static inline RepeatedField<Type>* MutableRepeated(int number,
+                                                     FieldType field_type,
+                                                     bool is_packed,
+                                                     ExtensionSet* set) {
+    return reinterpret_cast<RepeatedField<Type>*>(
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr));
+  }
+
+  static const RepeatedFieldType* GetDefaultRepeatedField() {
+    // Hack: as noted above, repeated enum fields are internally stored as a
+    // RepeatedField<int>. We need to be able to instantiate global static
+    // objects to return as default (empty) repeated fields on non-existent
+    // extensions. We would not be able to know a-priori all of the enum types
+    // (values of |Type|) to instantiate all of these, so we just re-use
+    // int32_t's default repeated field object.
+    return reinterpret_cast<const RepeatedField<Type>*>(
+        RepeatedPrimitiveTypeTraits<int32_t>::GetDefaultRepeatedField());
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number,
+                                        type, true, is_packed, IsValid);
+  }
+};
+
+// -------------------------------------------------------------------
+// MessageTypeTraits
+
+// ExtensionSet guarantees that when manipulating extensions with message
+// types, the implementation used will be the compiled-in class representing
+// that type.  So, we can static_cast down to the exact type we expect.
+template <typename Type>
+class MessageTypeTraits {
+ public:
+  typedef const Type& ConstType;
+  typedef Type* MutableType;
+  typedef MessageTypeTraits<Type> Singular;
+
+  static inline ConstType Get(int number, const ExtensionSet& set,
+                              ConstType default_value) {
+    return static_cast<const Type&>(set.GetMessage(number, default_value));
+  }
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
+                                      ConstType /* default_value */) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline MutableType Mutable(int number, FieldType field_type,
+                                    ExtensionSet* set) {
+    return static_cast<Type*>(set->MutableMessage(
+        number, field_type, Type::default_instance(), nullptr));
+  }
+  static inline void SetAllocated(int number, FieldType field_type,
+                                  MutableType message, ExtensionSet* set) {
+    set->SetAllocatedMessage(number, field_type, nullptr, message);
+  }
+  static inline void UnsafeArenaSetAllocated(int number, FieldType field_type,
+                                             MutableType message,
+                                             ExtensionSet* set) {
+    set->UnsafeArenaSetAllocatedMessage(number, field_type, nullptr, message);
+  }
+  PROTOBUF_NODISCARD static inline MutableType Release(
+      int number, FieldType /* field_type */, ExtensionSet* set) {
+    return static_cast<Type*>(
+        set->ReleaseMessage(number, Type::default_instance()));
+  }
+  static inline MutableType UnsafeArenaRelease(int number,
+                                               FieldType /* field_type */,
+                                               ExtensionSet* set) {
+    return static_cast<Type*>(
+        set->UnsafeArenaReleaseMessage(number, Type::default_instance()));
+  }
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(),
+                                           number, type, false, is_packed,
+                                           &Type::default_instance(), fn);
+  }
+};
+
+// Used by WireFormatVerify to extract the verify function from the registry.
+LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
+    const MessageLite* extendee, int number);
+
+// forward declaration.
+class RepeatedMessageGenericTypeTraits;
+
+template <typename Type>
+class RepeatedMessageTypeTraits {
+ public:
+  typedef const Type& ConstType;
+  typedef Type* MutableType;
+  typedef RepeatedMessageTypeTraits<Type> Repeated;
+
+  typedef RepeatedPtrField<Type> RepeatedFieldType;
+
+  static inline ConstType Get(int number, const ExtensionSet& set, int index) {
+    return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
+  }
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
+                                      int /* index */) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline std::nullptr_t GetRepeatedPtr(int /* number */,
+                                              const ExtensionSet& /* set */) {
+    // Cannot be implemented because of forward declared messages?
+    return nullptr;
+  }
+  static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
+    return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
+  }
+  static inline MutableType Add(int number, FieldType field_type,
+                                ExtensionSet* set) {
+    return static_cast<Type*>(
+        set->AddMessage(number, field_type, Type::default_instance(), nullptr));
+  }
+  static inline const RepeatedPtrField<Type>& GetRepeated(
+      int number, const ExtensionSet& set) {
+    // See notes above in RepeatedEnumTypeTraits::GetRepeated(): same
+    // casting hack applies here, because a RepeatedPtrField<MessageLite>
+    // cannot naturally become a RepeatedPtrType<Type> even though Type is
+    // presumably a message. google::protobuf::Message goes through similar contortions
+    // with a reinterpret_cast<>.
+    return *reinterpret_cast<const RepeatedPtrField<Type>*>(
+        set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
+  }
+  static inline RepeatedPtrField<Type>* MutableRepeated(int number,
+                                                        FieldType field_type,
+                                                        bool is_packed,
+                                                        ExtensionSet* set) {
+    return reinterpret_cast<RepeatedPtrField<Type>*>(
+        set->MutableRawRepeatedField(number, field_type, is_packed, nullptr));
+  }
+
+  static const RepeatedFieldType* GetDefaultRepeatedField();
+  template <typename ExtendeeT>
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
+    ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(),
+                                           number, type, true, is_packed,
+                                           &Type::default_instance(), fn);
+  }
+};
+
+template <typename Type>
+inline const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
+RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
+  static auto instance = OnShutdownDelete(new RepeatedFieldType);
+  return instance;
+}
+
+// -------------------------------------------------------------------
+// ExtensionIdentifier
+
+// This is the type of actual extension objects.  E.g. if you have:
+//   extend Foo {
+//     optional int32 bar = 1234;
+//   }
+// then "bar" will be defined in C++ as:
+//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32_t>, 5, false> bar(1234);
+//
+// Note that we could, in theory, supply the field number as a template
+// parameter, and thus make an instance of ExtensionIdentifier have no
+// actual contents.  However, if we did that, then using an extension
+// identifier would not necessarily cause the compiler to output any sort
+// of reference to any symbol defined in the extension's .pb.o file.  Some
+// linkers will actually drop object files that are not explicitly referenced,
+// but that would be bad because it would cause this extension to not be
+// registered at static initialization, and therefore using it would crash.
+
+template <typename ExtendeeType, typename TypeTraitsType, FieldType field_type,
+          bool is_packed>
+class ExtensionIdentifier {
+ public:
+  typedef TypeTraitsType TypeTraits;
+  typedef ExtendeeType Extendee;
+
+  ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value,
+                      LazyEagerVerifyFnType verify_func = nullptr)
+      : number_(number), default_value_(default_value) {
+    Register(number, verify_func);
+  }
+  inline int number() const { return number_; }
+  typename TypeTraits::ConstType default_value() const {
+    return default_value_;
+  }
+
+  static void Register(int number, LazyEagerVerifyFnType verify_func) {
+    TypeTraits::template Register<ExtendeeType>(number, field_type, is_packed,
+                                                verify_func);
+  }
+
+  typename TypeTraits::ConstType const& default_value_ref() const {
+    return default_value_;
+  }
+
+ private:
+  const int number_;
+  typename TypeTraits::ConstType default_value_;
+};
+
+// -------------------------------------------------------------------
+// Generated accessors
+
+
+// Used to retrieve a lazy extension, may return nullptr in some environments.
+extern PROTOBUF_ATTRIBUTE_WEAK ExtensionSet::LazyMessageExtension*
+MaybeCreateLazyExtension(Arena* arena);
+
+}  // namespace internal
+
+// Call this function to ensure that this extensions's reflection is linked into
+// the binary:
+//
+//   google::protobuf::LinkExtensionReflection(Foo::my_extension);
+//
+// This will ensure that the following lookup will succeed:
+//
+//   DescriptorPool::generated_pool()->FindExtensionByName("Foo.my_extension");
+//
+// This is often relevant for parsing extensions in text mode.
+//
+// As a side-effect, it will also guarantee that anything else from the same
+// .proto file will also be available for lookup in the generated pool.
+//
+// This function does not actually register the extension, so it does not need
+// to be called before the lookup.  However it does need to occur in a function
+// that cannot be stripped from the binary (ie. it must be reachable from main).
+//
+// Best practice is to call this function as close as possible to where the
+// reflection is actually needed.  This function is very cheap to call, so you
+// should not need to worry about its runtime overhead except in tight loops (on
+// x86-64 it compiles into two "mov" instructions).
+template <typename ExtendeeType, typename TypeTraitsType,
+          internal::FieldType field_type, bool is_packed>
+void LinkExtensionReflection(
+    const google::protobuf::internal::ExtensionIdentifier<
+        ExtendeeType, TypeTraitsType, field_type, is_packed>& extension) {
+  internal::StrongReference(extension);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_EXTENSION_SET_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/extension_set_inl.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/extension_set_inl.h
new file mode 100644
index 0000000..50c04cd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/extension_set_inl.h
@@ -0,0 +1,285 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+#define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template <typename T>
+const char* ExtensionSet::ParseFieldWithExtensionInfo(
+    int number, bool was_packed_on_wire, const ExtensionInfo& extension,
+    InternalMetadata* metadata, const char* ptr, internal::ParseContext* ctx) {
+  if (was_packed_on_wire) {
+    switch (extension.type) {
+#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
+  case WireFormatLite::TYPE_##UPPERCASE:                                     \
+    return internal::Packed##CPP_CAMELCASE##Parser(                          \
+        MutableRawRepeatedField(number, extension.type, extension.is_packed, \
+                                extension.descriptor),                       \
+        ptr, ctx);
+      HANDLE_TYPE(INT32, Int32);
+      HANDLE_TYPE(INT64, Int64);
+      HANDLE_TYPE(UINT32, UInt32);
+      HANDLE_TYPE(UINT64, UInt64);
+      HANDLE_TYPE(SINT32, SInt32);
+      HANDLE_TYPE(SINT64, SInt64);
+      HANDLE_TYPE(FIXED32, Fixed32);
+      HANDLE_TYPE(FIXED64, Fixed64);
+      HANDLE_TYPE(SFIXED32, SFixed32);
+      HANDLE_TYPE(SFIXED64, SFixed64);
+      HANDLE_TYPE(FLOAT, Float);
+      HANDLE_TYPE(DOUBLE, Double);
+      HANDLE_TYPE(BOOL, Bool);
+#undef HANDLE_TYPE
+
+      case WireFormatLite::TYPE_ENUM:
+        return internal::PackedEnumParserArg<T>(
+            MutableRawRepeatedField(number, extension.type, extension.is_packed,
+                                    extension.descriptor),
+            ptr, ctx, extension.enum_validity_check.func,
+            extension.enum_validity_check.arg, metadata, number);
+      case WireFormatLite::TYPE_STRING:
+      case WireFormatLite::TYPE_BYTES:
+      case WireFormatLite::TYPE_GROUP:
+      case WireFormatLite::TYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+        break;
+    }
+  } else {
+    switch (extension.type) {
+#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    uint64_t value;                                                         \
+    ptr = VarintParse(ptr, &value);                                         \
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_VARINT_TYPE(INT32, Int32);
+      HANDLE_VARINT_TYPE(INT64, Int64);
+      HANDLE_VARINT_TYPE(UINT32, UInt32);
+      HANDLE_VARINT_TYPE(UINT64, UInt64);
+      HANDLE_VARINT_TYPE(BOOL, Bool);
+#undef HANDLE_VARINT_TYPE
+#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    uint64_t val;                                                           \
+    ptr = VarintParse(ptr, &val);                                           \
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
+    auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
+      HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
+#undef HANDLE_SVARINT_TYPE
+#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    auto value = UnalignedLoad<CPPTYPE>(ptr);                               \
+    ptr += sizeof(CPPTYPE);                                                 \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32_t);
+      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64_t);
+      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32_t);
+      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64_t);
+      HANDLE_FIXED_TYPE(FLOAT, Float, float);
+      HANDLE_FIXED_TYPE(DOUBLE, Double, double);
+#undef HANDLE_FIXED_TYPE
+
+      case WireFormatLite::TYPE_ENUM: {
+        uint64_t val;
+        ptr = VarintParse(ptr, &val);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        int value = val;
+
+        if (!extension.enum_validity_check.func(
+                extension.enum_validity_check.arg, value)) {
+          WriteVarint(number, val, metadata->mutable_unknown_fields<T>());
+        } else if (extension.is_repeated) {
+          AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
+                  extension.descriptor);
+        } else {
+          SetEnum(number, WireFormatLite::TYPE_ENUM, value,
+                  extension.descriptor);
+        }
+        break;
+      }
+
+      case WireFormatLite::TYPE_BYTES:
+      case WireFormatLite::TYPE_STRING: {
+        std::string* value =
+            extension.is_repeated
+                ? AddString(number, WireFormatLite::TYPE_STRING,
+                            extension.descriptor)
+                : MutableString(number, WireFormatLite::TYPE_STRING,
+                                extension.descriptor);
+        int size = ReadSize(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        return ctx->ReadString(ptr, size, value);
+      }
+
+      case WireFormatLite::TYPE_GROUP: {
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
+        uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
+        return ctx->ParseGroup(value, ptr, tag);
+      }
+
+      case WireFormatLite::TYPE_MESSAGE: {
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
+        return ctx->ParseMessage(value, ptr);
+      }
+    }
+  }
+  return ptr;
+}
+
+template <typename Msg, typename T>
+const char* ExtensionSet::ParseMessageSetItemTmpl(
+    const char* ptr, const Msg* extendee, internal::InternalMetadata* metadata,
+    internal::ParseContext* ctx) {
+  std::string payload;
+  uint32_t type_id = 0;
+  enum class State { kNoTag, kHasType, kHasPayload, kDone };
+  State state = State::kNoTag;
+
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag = static_cast<uint8_t>(*ptr++);
+    if (tag == WireFormatLite::kMessageSetTypeIdTag) {
+      uint64_t tmp;
+      ptr = ParseBigVarint(ptr, &tmp);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (state == State::kNoTag) {
+        type_id = tmp;
+        state = State::kHasType;
+      } else if (state == State::kHasPayload) {
+        type_id = tmp;
+        ExtensionInfo extension;
+        bool was_packed_on_wire;
+        if (!FindExtension(2, type_id, extendee, ctx, &extension,
+                           &was_packed_on_wire)) {
+          WriteLengthDelimited(type_id, payload,
+                               metadata->mutable_unknown_fields<T>());
+        } else {
+          MessageLite* value =
+              extension.is_repeated
+                  ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
+                               *extension.message_info.prototype,
+                               extension.descriptor)
+                  : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
+                                   *extension.message_info.prototype,
+                                   extension.descriptor);
+
+          const char* p;
+          // We can't use regular parse from string as we have to track
+          // proper recursion depth and descriptor pools.
+          ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
+          tmp_ctx.data().pool = ctx->data().pool;
+          tmp_ctx.data().factory = ctx->data().factory;
+          GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
+                                         tmp_ctx.EndedAtLimit());
+        }
+        state = State::kDone;
+      }
+    } else if (tag == WireFormatLite::kMessageSetMessageTag) {
+      if (state == State::kHasType) {
+        ptr = ParseFieldMaybeLazily(static_cast<uint64_t>(type_id) * 8 + 2, ptr,
+                                    extendee, metadata, ctx);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+        state = State::kDone;
+      } else {
+        std::string tmp;
+        int32_t size = ReadSize(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        ptr = ctx->ReadString(ptr, size, &tmp);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        if (state == State::kNoTag) {
+          payload = std::move(tmp);
+          state = State::kHasPayload;
+        }
+      }
+    } else {
+      ptr = ReadTag(ptr - 1, &tag);
+      if (tag == 0 || (tag & 7) == 4) {
+        ctx->SetLastTag(tag);
+        return ptr;
+      }
+      ptr = ParseField(tag, ptr, extendee, metadata, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+  }
+  return ptr;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/field_access_listener.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/field_access_listener.h
new file mode 100644
index 0000000..47422e6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/field_access_listener.h
@@ -0,0 +1,172 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
+#define GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
+
+#include <cstddef>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message_lite.h>
+
+
+namespace google {
+namespace protobuf {
+
+// A default/no-op implementation of message hooks.
+//
+// See go/statically-dispatched-message-hooks for details.
+template <typename Proto>
+struct NoOpAccessListener {
+  // Number of fields are provided at compile time for the trackers to be able
+  // to have stack allocated bitmaps for the fields. This is useful for
+  // performance critical trackers. This is also to avoid cyclic dependencies
+  // if the number of fields is needed.
+  static constexpr int kFields = Proto::_kInternalFieldNumber;
+  // Default constructor is called during the static global initialization of
+  // the program.
+  // We provide a pointer to extract the name of the proto not to get cyclic
+  // dependencies on GetDescriptor() and OnGetMetadata() calls. If you want
+  // to differentiate the protos during the runtime before the start of the
+  // program, use this functor to get its name. We either way need it for
+  // LITE_RUNTIME protos as they don't have descriptors at all.
+  explicit NoOpAccessListener(StringPiece (*name_extractor)()) {}
+  // called repeatedly during serialization/deserialization/ByteSize of
+  // Reflection as:
+  //   AccessListener<MessageT>::OnSerialize(this);
+  static void OnSerialize(const MessageLite* msg) {}
+  static void OnDeserialize(const MessageLite* msg) {}
+  static void OnByteSize(const MessageLite* msg) {}
+  static void OnMergeFrom(const MessageLite* to, const MessageLite* from) {}
+
+  // NOTE: This function can be called pre-main. Make sure it does not make
+  // the state of the listener invalid.
+  static void OnGetMetadata() {}
+
+  // called from accessors as:
+  //   AccessListener<MessageT>::On$operation(this, &field_storage_);
+  // If you need to override this with type, in your hook implementation
+  // introduce
+  // template <int kFieldNum, typename T>
+  // static void On$operation(const MessageLite* msg,
+  //                          const T* field) {}
+  // And overloads for std::nullptr_t for incomplete types such as Messages,
+  // Maps. Extract them using reflection if you need. Consequently, second
+  // argument can be null pointer.
+  // For an example, see proto_hooks/testing/memory_test_field_listener.h
+  // And argument template deduction will deduce the type itself without
+  // changing the generated code.
+
+  // add_<field>(f)
+  template <int kFieldNum>
+  static void OnAdd(const MessageLite* msg, const void* field) {}
+
+  // add_<field>()
+  template <int kFieldNum>
+  static void OnAddMutable(const MessageLite* msg, const void* field) {}
+
+  // <field>() and <repeated_field>(i)
+  template <int kFieldNum>
+  static void OnGet(const MessageLite* msg, const void* field) {}
+
+  // clear_<field>()
+  template <int kFieldNum>
+  static void OnClear(const MessageLite* msg, const void* field) {}
+
+  // has_<field>()
+  template <int kFieldNum>
+  static void OnHas(const MessageLite* msg, const void* field) {}
+
+  // <repeated_field>()
+  template <int kFieldNum>
+  static void OnList(const MessageLite* msg, const void* field) {}
+
+  // mutable_<field>()
+  template <int kFieldNum>
+  static void OnMutable(const MessageLite* msg, const void* field) {}
+
+  // mutable_<repeated_field>()
+  template <int kFieldNum>
+  static void OnMutableList(const MessageLite* msg, const void* field) {}
+
+  // release_<field>()
+  template <int kFieldNum>
+  static void OnRelease(const MessageLite* msg, const void* field) {}
+
+  // set_<field>() and set_<repeated_field>(i)
+  template <int kFieldNum>
+  static void OnSet(const MessageLite* msg, const void* field) {}
+
+  // <repeated_field>_size()
+  template <int kFieldNum>
+  static void OnSize(const MessageLite* msg, const void* field) {}
+
+  static void OnHasExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  // TODO(b/190614678): Support clear in the proto compiler.
+  static void OnClearExtension(const MessageLite* msg, int extension_tag,
+                               const void* field) {}
+  static void OnExtensionSize(const MessageLite* msg, int extension_tag,
+                              const void* field) {}
+  static void OnGetExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnMutableExtension(const MessageLite* msg, int extension_tag,
+                                 const void* field) {}
+  static void OnSetExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnReleaseExtension(const MessageLite* msg, int extension_tag,
+                                 const void* field) {}
+  static void OnAddExtension(const MessageLite* msg, int extension_tag,
+                             const void* field) {}
+  static void OnAddMutableExtension(const MessageLite* msg, int extension_tag,
+                                    const void* field) {}
+  static void OnListExtension(const MessageLite* msg, int extension_tag,
+                              const void* field) {}
+  static void OnMutableListExtension(const MessageLite* msg, int extension_tag,
+                                     const void* field) {}
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#ifndef REPLACE_PROTO_LISTENER_IMPL
+namespace google {
+namespace protobuf {
+template <class T>
+using AccessListener = NoOpAccessListener<T>;
+}  // namespace protobuf
+}  // namespace google
+#else
+// You can put your implementations of hooks/listeners here.
+// All hooks are subject to approval by protobuf-team@.
+
+#endif  // !REPLACE_PROTO_LISTENER_IMPL
+
+#endif  // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/field_mask.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/field_mask.pb.h
new file mode 100644
index 0000000..8f90e4c
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/field_mask.pb.h
@@ -0,0 +1,317 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ffield_5fmask_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class FieldMask;
+struct FieldMaskDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldMask* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldMask>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT FieldMask final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldMask) */ {
+ public:
+  inline FieldMask() : FieldMask(nullptr) {}
+  ~FieldMask() override;
+  explicit PROTOBUF_CONSTEXPR FieldMask(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FieldMask(const FieldMask& from);
+  FieldMask(FieldMask&& from) noexcept
+    : FieldMask() {
+    *this = ::std::move(from);
+  }
+
+  inline FieldMask& operator=(const FieldMask& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FieldMask& operator=(FieldMask&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FieldMask& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FieldMask* internal_default_instance() {
+    return reinterpret_cast<const FieldMask*>(
+               &_FieldMask_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(FieldMask& a, FieldMask& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FieldMask* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldMask* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FieldMask* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FieldMask>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FieldMask& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FieldMask& from) {
+    FieldMask::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FieldMask* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FieldMask";
+  }
+  protected:
+  explicit FieldMask(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kPathsFieldNumber = 1,
+  };
+  // repeated string paths = 1;
+  int paths_size() const;
+  private:
+  int _internal_paths_size() const;
+  public:
+  void clear_paths();
+  const std::string& paths(int index) const;
+  std::string* mutable_paths(int index);
+  void set_paths(int index, const std::string& value);
+  void set_paths(int index, std::string&& value);
+  void set_paths(int index, const char* value);
+  void set_paths(int index, const char* value, size_t size);
+  std::string* add_paths();
+  void add_paths(const std::string& value);
+  void add_paths(std::string&& value);
+  void add_paths(const char* value);
+  void add_paths(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& paths() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_paths();
+  private:
+  const std::string& _internal_paths(int index) const;
+  std::string* _internal_add_paths();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldMask)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> paths_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// FieldMask
+
+// repeated string paths = 1;
+inline int FieldMask::_internal_paths_size() const {
+  return _impl_.paths_.size();
+}
+inline int FieldMask::paths_size() const {
+  return _internal_paths_size();
+}
+inline void FieldMask::clear_paths() {
+  _impl_.paths_.Clear();
+}
+inline std::string* FieldMask::add_paths() {
+  std::string* _s = _internal_add_paths();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths)
+  return _s;
+}
+inline const std::string& FieldMask::_internal_paths(int index) const {
+  return _impl_.paths_.Get(index);
+}
+inline const std::string& FieldMask::paths(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldMask.paths)
+  return _internal_paths(index);
+}
+inline std::string* FieldMask::mutable_paths(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldMask.paths)
+  return _impl_.paths_.Mutable(index);
+}
+inline void FieldMask::set_paths(int index, const std::string& value) {
+  _impl_.paths_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::set_paths(int index, std::string&& value) {
+  _impl_.paths_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::set_paths(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.paths_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::set_paths(int index, const char* value, size_t size) {
+  _impl_.paths_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths)
+}
+inline std::string* FieldMask::_internal_add_paths() {
+  return _impl_.paths_.Add();
+}
+inline void FieldMask::add_paths(const std::string& value) {
+  _impl_.paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(std::string&& value) {
+  _impl_.paths_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(const char* value, size_t size) {
+  _impl_.paths_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FieldMask.paths)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+FieldMask::paths() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldMask.paths)
+  return _impl_.paths_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+FieldMask::mutable_paths() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldMask.paths)
+  return &_impl_.paths_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_enum_reflection.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_enum_reflection.h
new file mode 100644
index 0000000..b96a9c6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_enum_reflection.h
@@ -0,0 +1,100 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jasonh@google.com (Jason Hsueh)
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+// It provides reflection support for generated enums, and is included in
+// generated .pb.h files and should have minimal dependencies. The methods are
+// implemented in generated_message_reflection.cc.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+
+
+#include <string>
+
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/generated_enum_util.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class EnumDescriptor;
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+
+// Returns the EnumDescriptor for enum type E, which must be a
+// proto-declared enum type.  Code generated by the protocol compiler
+// will include specializations of this template for each enum type declared.
+template <typename E>
+const EnumDescriptor* GetEnumDescriptor();
+
+namespace internal {
+
+// Helper for EnumType_Parse functions: try to parse the string 'name' as
+// an enum name of the given type, returning true and filling in value on
+// success, or returning false and leaving value unchanged on failure.
+PROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
+                                    ConstStringParam name, int* value);
+
+template <typename EnumType>
+bool ParseNamedEnum(const EnumDescriptor* descriptor, ConstStringParam name,
+                    EnumType* value) {
+  int tmp;
+  if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
+  *value = static_cast<EnumType>(tmp);
+  return true;
+}
+
+// Just a wrapper around printing the name of a value. The main point of this
+// function is not to be inlined, so that you can do this without including
+// descriptor.h.
+PROTOBUF_EXPORT const std::string& NameOfEnum(const EnumDescriptor* descriptor,
+                                              int value);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_enum_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_enum_util.h
new file mode 100644
index 0000000..5d10ac0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_enum_util.h
@@ -0,0 +1,85 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+
+
+#include <type_traits>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// This type trait can be used to cause templates to only match proto2 enum
+// types.
+template <typename T>
+struct is_proto_enum : ::std::false_type {};
+
+namespace internal {
+
+// The table entry format for storing enum name-to-value mapping used with lite
+// protos. This struct and the following related functions should only be used
+// by protobuf generated code.
+struct EnumEntry {
+  StringPiece name;
+  int value;
+};
+
+// Looks up a numeric enum value given the string name.
+PROTOBUF_EXPORT bool LookUpEnumValue(const EnumEntry* enums, size_t size,
+                                     StringPiece name, int* value);
+
+// Looks up an enum name given the numeric value.
+PROTOBUF_EXPORT int LookUpEnumName(const EnumEntry* enums,
+                                   const int* sorted_indices, size_t size,
+                                   int value);
+
+// Initializes the list of enum names in std::string form.
+PROTOBUF_EXPORT bool InitializeEnumStrings(
+    const EnumEntry* enums, const int* sorted_indices, size_t size,
+    internal::ExplicitlyConstructed<std::string>* enum_strings);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_bases.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_bases.h
new file mode 100644
index 0000000..b295218
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_bases.h
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains helpers for generated code.
+//
+//  Nothing in this file should be directly referenced by users of protobufs.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
+
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/parse_context.h>
+
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// To save code size, protos without any fields are derived from ZeroFieldsBase
+// rather than Message.
+class PROTOBUF_EXPORT ZeroFieldsBase : public Message {
+ public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final { return true; }
+  size_t ByteSizeLong() const final;
+  int GetCachedSize() const final { return _cached_size_.Get(); }
+  const char* _InternalParse(const char* ptr,
+                             internal::ParseContext* ctx) final;
+  ::uint8_t* _InternalSerialize(::uint8_t* target,
+                                io::EpsCopyOutputStream* stream) const final;
+
+ protected:
+  constexpr ZeroFieldsBase() {}
+  explicit ZeroFieldsBase(Arena* arena, bool is_message_owned)
+      : Message(arena, is_message_owned) {}
+  ZeroFieldsBase(const ZeroFieldsBase&) = delete;
+  ZeroFieldsBase& operator=(const ZeroFieldsBase&) = delete;
+  ~ZeroFieldsBase() override;
+
+  void SetCachedSize(int size) const final { _cached_size_.Set(size); }
+
+  static void MergeImpl(Message& to, const Message& from);
+  static void CopyImpl(Message& to, const Message& from);
+  void InternalSwap(ZeroFieldsBase* other);
+
+  mutable internal::CachedSize _cached_size_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_reflection.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_reflection.h
new file mode 100644
index 0000000..334b2cc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_reflection.h
@@ -0,0 +1,354 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class MapKey;
+class MapValueRef;
+class MessageLayoutInspector;
+class Message;
+struct Metadata;
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+class DefaultEmptyOneof;
+// Defined in other files.
+class ExtensionSet;  // extension_set.h
+class WeakFieldMap;  // weak_field_map.h
+
+// This struct describes the internal layout of the message, hence this is
+// used to act on the message reflectively.
+//   default_instance:  The default instance of the message.  This is only
+//                  used to obtain pointers to default instances of embedded
+//                  messages, which GetMessage() will return if the particular
+//                  sub-message has not been initialized yet.  (Thus, all
+//                  embedded message fields *must* have non-null pointers
+//                  in the default instance.)
+//   offsets:       An array of ints giving the byte offsets.
+//                  For each oneof or weak field, the offset is relative to the
+//                  default_instance. These can be computed at compile time
+//                  using the
+//                  PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET()
+//                  macro. For each none oneof field, the offset is related to
+//                  the start of the message object.  These can be computed at
+//                  compile time using the
+//                  PROTO2_GENERATED_MESSAGE_FIELD_OFFSET() macro.
+//                  Besides offsets for all fields, this array also contains
+//                  offsets for oneof unions. The offset of the i-th oneof union
+//                  is offsets[descriptor->field_count() + i].
+//   has_bit_indices:  Mapping from field indexes to their index in the has
+//                  bit array.
+//   has_bits_offset:  Offset in the message of an array of uint32s of size
+//                  descriptor->field_count()/32, rounded up.  This is a
+//                  bitfield where each bit indicates whether or not the
+//                  corresponding field of the message has been initialized.
+//                  The bit for field index i is obtained by the expression:
+//                    has_bits[i / 32] & (1 << (i % 32))
+//   unknown_fields_offset:  Offset in the message of the UnknownFieldSet for
+//                  the message.
+//   extensions_offset:  Offset in the message of the ExtensionSet for the
+//                  message, or -1 if the message type has no extension
+//                  ranges.
+//   oneof_case_offset:  Offset in the message of an array of uint32s of
+//                  size descriptor->oneof_decl_count().  Each uint32_t
+//                  indicates what field is set for each oneof.
+//   object_size:   The size of a message object of this type, as measured
+//                  by sizeof().
+//   arena_offset:  If a message doesn't have a unknown_field_set that stores
+//                  the arena, it must have a direct pointer to the arena.
+//   weak_field_map_offset: If the message proto has weak fields, this is the
+//                  offset of _weak_field_map_ in the generated proto. Otherwise
+//                  -1.
+struct ReflectionSchema {
+ public:
+  // Size of a google::protobuf::Message object of this type.
+  uint32_t GetObjectSize() const { return static_cast<uint32_t>(object_size_); }
+
+  bool InRealOneof(const FieldDescriptor* field) const {
+    return field->containing_oneof() &&
+           !field->containing_oneof()->is_synthetic();
+  }
+
+  // Offset of a non-oneof field.  Getting a field offset is slightly more
+  // efficient when we know statically that it is not a oneof field.
+  uint32_t GetFieldOffsetNonOneof(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK(!InRealOneof(field));
+    return OffsetValue(offsets_[field->index()], field->type());
+  }
+
+  // Offset of any field.
+  uint32_t GetFieldOffset(const FieldDescriptor* field) const {
+    if (InRealOneof(field)) {
+      size_t offset =
+          static_cast<size_t>(field->containing_type()->field_count()) +
+          field->containing_oneof()->index();
+      return OffsetValue(offsets_[offset], field->type());
+    } else {
+      return GetFieldOffsetNonOneof(field);
+    }
+  }
+
+  bool IsFieldInlined(const FieldDescriptor* field) const {
+    return Inlined(offsets_[field->index()], field->type());
+  }
+
+  uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
+    return static_cast<uint32_t>(oneof_case_offset_) +
+           static_cast<uint32_t>(
+               static_cast<size_t>(oneof_descriptor->index()) *
+               sizeof(uint32_t));
+  }
+
+  bool HasHasbits() const { return has_bits_offset_ != -1; }
+
+  // Bit index within the bit array of hasbits.  Bit order is low-to-high.
+  uint32_t HasBitIndex(const FieldDescriptor* field) const {
+    if (has_bits_offset_ == -1) return static_cast<uint32_t>(-1);
+    GOOGLE_DCHECK(HasHasbits());
+    return has_bit_indices_[field->index()];
+  }
+
+  // Byte offset of the hasbits array.
+  uint32_t HasBitsOffset() const {
+    GOOGLE_DCHECK(HasHasbits());
+    return static_cast<uint32_t>(has_bits_offset_);
+  }
+
+  bool HasInlinedString() const { return inlined_string_donated_offset_ != -1; }
+
+  // Bit index within the bit array of _inlined_string_donated_.  Bit order is
+  // low-to-high.
+  uint32_t InlinedStringIndex(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK(HasInlinedString());
+    return inlined_string_indices_[field->index()];
+  }
+
+  // Byte offset of the _inlined_string_donated_ array.
+  uint32_t InlinedStringDonatedOffset() const {
+    GOOGLE_DCHECK(HasInlinedString());
+    return static_cast<uint32_t>(inlined_string_donated_offset_);
+  }
+
+  // The offset of the InternalMetadataWithArena member.
+  // For Lite this will actually be an InternalMetadataWithArenaLite.
+  // The schema doesn't contain enough information to distinguish between
+  // these two cases.
+  uint32_t GetMetadataOffset() const {
+    return static_cast<uint32_t>(metadata_offset_);
+  }
+
+  // Whether this message has an ExtensionSet.
+  bool HasExtensionSet() const { return extensions_offset_ != -1; }
+
+  // The offset of the ExtensionSet in this message.
+  uint32_t GetExtensionSetOffset() const {
+    GOOGLE_DCHECK(HasExtensionSet());
+    return static_cast<uint32_t>(extensions_offset_);
+  }
+
+  // The off set of WeakFieldMap when the message contains weak fields.
+  // The default is 0 for now.
+  int GetWeakFieldMapOffset() const { return weak_field_map_offset_; }
+
+  bool IsDefaultInstance(const Message& message) const {
+    return &message == default_instance_;
+  }
+
+  // Returns a pointer to the default value for this field.  The size and type
+  // of the underlying data depends on the field's type.
+  const void* GetFieldDefault(const FieldDescriptor* field) const {
+    return reinterpret_cast<const uint8_t*>(default_instance_) +
+           OffsetValue(offsets_[field->index()], field->type());
+  }
+
+  // Returns true if the field is implicitly backed by LazyField.
+  bool IsEagerlyVerifiedLazyField(const FieldDescriptor* field) const {
+    GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE);
+    (void)field;
+    return false;
+  }
+
+  bool IsFieldStripped(const FieldDescriptor* field) const {
+    (void)field;
+    return false;
+  }
+
+  bool IsMessageStripped(const Descriptor* descriptor) const {
+    (void)descriptor;
+    return false;
+  }
+
+
+  bool HasWeakFields() const { return weak_field_map_offset_ > 0; }
+
+  // These members are intended to be private, but we cannot actually make them
+  // private because this prevents us from using aggregate initialization of
+  // them, ie.
+  //
+  //   ReflectionSchema schema = {a, b, c, d, e, ...};
+  // private:
+  const Message* default_instance_;
+  const uint32_t* offsets_;
+  const uint32_t* has_bit_indices_;
+  int has_bits_offset_;
+  int metadata_offset_;
+  int extensions_offset_;
+  int oneof_case_offset_;
+  int object_size_;
+  int weak_field_map_offset_;
+  const uint32_t* inlined_string_indices_;
+  int inlined_string_donated_offset_;
+
+  // We tag offset values to provide additional data about fields (such as
+  // "unused" or "lazy" or "inlined").
+  static uint32_t OffsetValue(uint32_t v, FieldDescriptor::Type type) {
+    if (type == FieldDescriptor::TYPE_MESSAGE ||
+        type == FieldDescriptor::TYPE_STRING ||
+        type == FieldDescriptor::TYPE_BYTES) {
+      return v & 0xFFFFFFFEu;
+    }
+    return v;
+  }
+
+  static bool Inlined(uint32_t v, FieldDescriptor::Type type) {
+    if (type == FieldDescriptor::TYPE_STRING ||
+        type == FieldDescriptor::TYPE_BYTES) {
+      return (v & 1u) != 0u;
+    } else {
+      // Non string/byte fields are not inlined.
+      return false;
+    }
+  }
+};
+
+// Structs that the code generator emits directly to describe a message.
+// These should never used directly except to build a ReflectionSchema
+// object.
+//
+// EXPERIMENTAL: these are changing rapidly, and may completely disappear
+// or merge with ReflectionSchema.
+struct MigrationSchema {
+  int32_t offsets_index;
+  int32_t has_bit_indices_index;
+  int32_t inlined_string_indices_index;
+  int object_size;
+};
+
+// This struct tries to reduce unnecessary padding.
+// The num_xxx might not be close to their respective pointer, but this saves
+// padding.
+struct PROTOBUF_EXPORT DescriptorTable {
+  mutable bool is_initialized;
+  bool is_eager;
+  int size;  // of serialized descriptor
+  const char* descriptor;
+  const char* filename;
+  once_flag* once;
+  const DescriptorTable* const* deps;
+  int num_deps;
+  int num_messages;
+  const MigrationSchema* schemas;
+  const Message* const* default_instances;
+  const uint32_t* offsets;
+  // update the following descriptor arrays.
+  Metadata* file_level_metadata;
+  const EnumDescriptor** file_level_enum_descriptors;
+  const ServiceDescriptor** file_level_service_descriptors;
+};
+
+enum {
+  // Tag used on offsets for fields that don't have a real offset.
+  // For example, weak message fields go into the WeakFieldMap and not in an
+  // actual field.
+  kInvalidFieldOffsetTag = 0x40000000u,
+};
+
+// AssignDescriptors() pulls the compiled FileDescriptor from the DescriptorPool
+// and uses it to populate all of the global variables which store pointers to
+// the descriptor objects.  It also constructs the reflection objects.  It is
+// called the first time anyone calls descriptor() or GetReflection() on one of
+// the types defined in the file.  AssignDescriptors() is thread-safe.
+void PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* table,
+                                       bool eager = false);
+
+// Overload used to implement GetMetadataStatic in the generated code.
+// See comments in compiler/cpp/internal/file.cc as to why.
+// It takes a `Metadata` and returns it to allow for tail calls and reduce
+// binary size.
+Metadata PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* (*table)(),
+                                           internal::once_flag* once,
+                                           const Metadata& metadata);
+
+// These cannot be in lite so we put them in the reflection.
+PROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8_t* base,
+                                               uint32_t offset, uint32_t tag,
+                                               uint32_t has_offset,
+                                               io::CodedOutputStream* output);
+
+struct PROTOBUF_EXPORT AddDescriptorsRunner {
+  explicit AddDescriptorsRunner(const DescriptorTable* table);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_tctable_decl.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_tctable_decl.h
new file mode 100644
index 0000000..b1bb1de
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_tctable_decl.h
@@ -0,0 +1,312 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains declarations needed in generated headers for messages
+// that use tail-call table parsing. Everything in this file is for internal
+// use only.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Additional information about this field:
+struct TcFieldData {
+  constexpr TcFieldData() : data(0) {}
+
+  // Fast table entry constructor:
+  constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
+                        uint16_t offset)
+      : data(uint64_t{offset} << 48 |      //
+             uint64_t{aux_idx} << 24 |     //
+             uint64_t{hasbit_idx} << 16 |  //
+             uint64_t{coded_tag}) {}
+
+  // Fields used in fast table parsing:
+  //
+  //     Bit:
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+  //     :   .   :   .   :   . 16|=======| [16] coded_tag()
+  //     :   .   :   .   : 24|===|   .   : [ 8] hasbit_idx()
+  //     :   .   :   . 32|===|   :   .   : [ 8] aux_idx()
+  //     :   . 48:---.---:   .   :   .   : [16] (unused)
+  //     |=======|   .   :   .   :   .   : [16] offset()
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+
+  template <typename TagType = uint16_t>
+  TagType coded_tag() const {
+    return static_cast<TagType>(data);
+  }
+  uint8_t hasbit_idx() const { return static_cast<uint8_t>(data >> 16); }
+  uint8_t aux_idx() const { return static_cast<uint8_t>(data >> 24); }
+  uint16_t offset() const { return static_cast<uint16_t>(data >> 48); }
+
+  // Fields used in mini table parsing:
+  //
+  //     Bit:
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+  //     :   .   :   .   |===============| [32] tag() (decoded)
+  //     |===============|   .   :   .   : [32] entry_offset()
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+
+  uint32_t tag() const { return static_cast<uint32_t>(data); }
+  uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
+
+  uint64_t data;
+};
+
+struct TcParseTableBase;
+
+// TailCallParseFunc is the function pointer type used in the tailcall table.
+typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL);
+
+namespace field_layout {
+struct Offset {
+  uint32_t off;
+};
+}  // namespace field_layout
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+#pragma warning(push)
+// TcParseTableBase is intentionally overaligned on 32 bit targets.
+#pragma warning(disable : 4324)
+#endif
+
+// Base class for message-level table with info for the tail-call parser.
+struct alignas(uint64_t) TcParseTableBase {
+  // Common attributes for message layout:
+  uint16_t has_bits_offset;
+  uint16_t extension_offset;
+  uint32_t extension_range_low;
+  uint32_t extension_range_high;
+  uint32_t max_field_number;
+  uint8_t fast_idx_mask;
+  uint16_t lookup_table_offset;
+  uint32_t skipmap32;
+  uint32_t field_entries_offset;
+  uint16_t num_field_entries;
+
+  uint16_t num_aux_entries;
+  uint32_t aux_offset;
+
+  const MessageLite* default_instance;
+
+  // Handler for fields which are not handled by table dispatch.
+  TailCallParseFunc fallback;
+
+  // This constructor exactly follows the field layout, so it's technically
+  // not necessary.  However, it makes it much much easier to add or re-arrange
+  // fields, because it can be overloaded with an additional constructor,
+  // temporarily allowing both old and new protocol buffer headers to be
+  // compiled.
+  constexpr TcParseTableBase(
+      uint16_t has_bits_offset, uint16_t extension_offset,
+      uint32_t extension_range_low, uint32_t extension_range_high,
+      uint32_t max_field_number, uint8_t fast_idx_mask,
+      uint16_t lookup_table_offset, uint32_t skipmap32,
+      uint32_t field_entries_offset, uint16_t num_field_entries,
+      uint16_t num_aux_entries, uint32_t aux_offset,
+      const MessageLite* default_instance, TailCallParseFunc fallback)
+      : has_bits_offset(has_bits_offset),
+        extension_offset(extension_offset),
+        extension_range_low(extension_range_low),
+        extension_range_high(extension_range_high),
+        max_field_number(max_field_number),
+        fast_idx_mask(fast_idx_mask),
+        lookup_table_offset(lookup_table_offset),
+        skipmap32(skipmap32),
+        field_entries_offset(field_entries_offset),
+        num_field_entries(num_field_entries),
+        num_aux_entries(num_aux_entries),
+        aux_offset(aux_offset),
+        default_instance(default_instance),
+        fallback(fallback) {}
+
+  // Table entry for fast-path tailcall dispatch handling.
+  struct FastFieldEntry {
+    // Target function for dispatch:
+    TailCallParseFunc target;
+    // Field data used during parse:
+    TcFieldData bits;
+  };
+  // There is always at least one table entry.
+  const FastFieldEntry* fast_entry(size_t idx) const {
+    return reinterpret_cast<const FastFieldEntry*>(this + 1) + idx;
+  }
+
+  // Returns a begin iterator (pointer) to the start of the field lookup table.
+  const uint16_t* field_lookup_begin() const {
+    return reinterpret_cast<const uint16_t*>(reinterpret_cast<uintptr_t>(this) +
+                                             lookup_table_offset);
+  }
+
+  // Field entry for all fields.
+  struct FieldEntry {
+    uint32_t offset;     // offset in the message object
+    int32_t has_idx;     // has-bit index
+    uint16_t aux_idx;    // index for `field_aux`.
+    uint16_t type_card;  // `FieldType` and `Cardinality` (see _impl.h)
+  };
+
+  // Returns a begin iterator (pointer) to the start of the field entries array.
+  const FieldEntry* field_entries_begin() const {
+    return reinterpret_cast<const FieldEntry*>(
+        reinterpret_cast<uintptr_t>(this) + field_entries_offset);
+  }
+
+  // Auxiliary entries for field types that need extra information.
+  union FieldAux {
+    constexpr FieldAux() : message_default(nullptr) {}
+    constexpr FieldAux(bool (*enum_validator)(int))
+        : enum_validator(enum_validator) {}
+    constexpr FieldAux(field_layout::Offset off) : offset(off.off) {}
+    constexpr FieldAux(int16_t range_start, uint16_t range_length)
+        : enum_range{range_start, range_length} {}
+    constexpr FieldAux(const MessageLite* msg) : message_default(msg) {}
+    bool (*enum_validator)(int);
+    struct {
+      int16_t start;    // minimum enum number (if it fits)
+      uint16_t length;  // length of range (i.e., max = start + length - 1)
+    } enum_range;
+    uint32_t offset;
+    const MessageLite* message_default;
+  };
+  const FieldAux* field_aux(uint32_t idx) const {
+    return reinterpret_cast<const FieldAux*>(reinterpret_cast<uintptr_t>(this) +
+                                             aux_offset) +
+           idx;
+  }
+  const FieldAux* field_aux(const FieldEntry* entry) const {
+    return field_aux(entry->aux_idx);
+  }
+
+  // Field name data
+  const char* name_data() const {
+    return reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(this) +
+                                         aux_offset +
+                                         num_aux_entries * sizeof(FieldAux));
+  }
+};
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+#pragma warning(pop)
+#endif
+
+static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16,
+              "Fast field entry is too big.");
+static_assert(sizeof(TcParseTableBase::FieldEntry) <= 16,
+              "Field entry is too big.");
+
+template <size_t kFastTableSizeLog2, size_t kNumFieldEntries = 0,
+          size_t kNumFieldAux = 0, size_t kNameTableSize = 0,
+          size_t kFieldLookupSize = 2>
+struct TcParseTable {
+  TcParseTableBase header;
+
+  // Entries for each field.
+  //
+  // Fields are indexed by the lowest bits of their field number. The field
+  // number is masked to fit inside the table. Note that the parsing logic
+  // generally calls `TailCallParseTableBase::fast_entry()` instead of accessing
+  // this field directly.
+  std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
+      fast_entries;
+
+  // Just big enough to find all the field entries.
+  std::array<uint16_t, kFieldLookupSize> field_lookup_table;
+  // Entries for all fields:
+  std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
+  std::array<TcParseTableBase::FieldAux, kNumFieldAux> aux_entries;
+  std::array<char, kNameTableSize> field_names;
+};
+
+// Partial specialization: if there are no aux entries, there will be no array.
+// In C++, arrays cannot have length 0, but (C++11) std::array<T, 0> is valid.
+// However, different implementations have different sizeof(std::array<T, 0>).
+// Skipping the member makes offset computations portable.
+template <size_t kFastTableSizeLog2, size_t kNumFieldEntries,
+          size_t kNameTableSize, size_t kFieldLookupSize>
+struct TcParseTable<kFastTableSizeLog2, kNumFieldEntries, 0, kNameTableSize,
+                    kFieldLookupSize> {
+  TcParseTableBase header;
+  std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
+      fast_entries;
+  std::array<uint16_t, kFieldLookupSize> field_lookup_table;
+  std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
+  std::array<char, kNameTableSize> field_names;
+};
+
+// Partial specialization: if there are no fields at all, then we can save space
+// by skipping the field numbers and entries.
+template <size_t kNameTableSize, size_t kFieldLookupSize>
+struct TcParseTable<0, 0, 0, kNameTableSize, kFieldLookupSize> {
+  TcParseTableBase header;
+  // N.B.: the fast entries are sized by log2, so 2**0 fields = 1 entry.
+  // The fast parsing loop will always use this entry, so it must be present.
+  std::array<TcParseTableBase::FastFieldEntry, 1> fast_entries;
+  std::array<uint16_t, kFieldLookupSize> field_lookup_table;
+  std::array<char, kNameTableSize> field_names;
+};
+
+static_assert(std::is_standard_layout<TcParseTable<1>>::value,
+              "TcParseTable must be standard layout.");
+
+static_assert(offsetof(TcParseTable<1>, fast_entries) ==
+                  sizeof(TcParseTableBase),
+              "Table entries must be laid out after TcParseTableBase.");
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_tctable_impl.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_tctable_impl.h
new file mode 100644
index 0000000..a8f8bdc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_tctable_impl.h
@@ -0,0 +1,565 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
+
+#include <cstdint>
+#include <type_traits>
+
+#include <google/protobuf/port.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_decl.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must come last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class UnknownFieldSet;
+
+namespace internal {
+
+// Field layout enums.
+//
+// Structural information about fields is packed into a 16-bit value. The enum
+// types below represent bitwise fields, along with their respective widths,
+// shifts, and masks.
+//
+//     Bit:
+//     +-----------------------+-----------------------+
+//     |15        ..          8|7         ..          0|
+//     +-----------------------+-----------------------+
+//     :  .  :  .  :  .  :  .  :  .  :  .  : 3|========| [3] FieldType
+//     :     :     :     :     :     : 5|=====|  :     : [2] FieldCardinality
+//     :  .  :  .  :  .  :  . 8|========|  :  .  :  .  : [3] FieldRep
+//     :     :     :   10|=====|     :     :     :     : [2] TransformValidation
+//     :  .  :  .12|=====|  .  :  .  :  .  :  .  :  .  : [2] FormatDiscriminator
+//     +-----------------------+-----------------------+
+//     |15        ..          8|7         ..          0|
+//     +-----------------------+-----------------------+
+//
+namespace field_layout {
+// clang-format off
+
+// Field kind (3 bits):
+// These values broadly represent a wire type and an in-memory storage class.
+enum FieldKind : uint16_t {
+  kFkShift = 0,
+  kFkBits = 3,
+  kFkMask = ((1 << kFkBits) - 1) << kFkShift,
+
+  kFkNone = 0,
+  kFkVarint,        // WT=0     rep=8,32,64 bits
+  kFkPackedVarint,  // WT=2     rep=8,32,64 bits
+  kFkFixed,         // WT=1,5   rep=32,64 bits
+  kFkPackedFixed,   // WT=2     rep=32,64 bits
+  kFkString,        // WT=2     rep=various
+  kFkMessage,       // WT=2,3,4 rep=MessageLite*
+  // Maps are a special case of Message, but use different parsing logic.
+  kFkMap,           // WT=2     rep=Map(Lite)<various, various>
+};
+
+static_assert(kFkMap < (1 << kFkBits), "too many types");
+
+// Cardinality (2 bits):
+// These values determine how many values a field can have and its presence.
+// Packed fields are represented in FieldType.
+enum Cardinality : uint16_t {
+  kFcShift    = kFkShift + kFkBits,
+  kFcBits     = 2,
+  kFcMask     = ((1 << kFcBits) - 1) << kFcShift,
+
+  kFcSingular = 0,
+  kFcOptional = 1 << kFcShift,
+  kFcRepeated = 2 << kFcShift,
+  kFcOneof    = 3 << kFcShift,
+};
+
+// Field representation (3 bits):
+// These values are the specific refinements of storage classes in FieldType.
+enum FieldRep : uint16_t {
+  kRepShift    = kFcShift + kFcBits,
+  kRepBits     = 3,
+  kRepMask     = ((1 << kRepBits) - 1) << kRepShift,
+
+  // Numeric types (used for optional and repeated fields):
+  kRep8Bits    = 0,
+  kRep32Bits   = 2 << kRepShift,
+  kRep64Bits   = 3 << kRepShift,
+  // String types:
+  kRepAString  = 0,               // ArenaStringPtr
+  kRepIString  = 1 << kRepShift,  // InlinedString
+  kRepCord     = 2 << kRepShift,  // absl::Cord
+  kRepSPiece   = 3 << kRepShift,  // StringPieceField
+  kRepSString  = 4 << kRepShift,  // std::string*
+  // Message types (WT=2 unless otherwise noted):
+  kRepMessage  = 0,               // MessageLite*
+  kRepGroup    = 1 << kRepShift,  // MessageLite* (WT=3,4)
+  kRepLazy     = 2 << kRepShift,  // LazyField*
+  kRepIWeak    = 3 << kRepShift,  // ImplicitWeak
+};
+
+// Transform/validation (2 bits):
+// These values determine transforms or validation to/from wire format.
+enum TransformValidation : uint16_t {
+  kTvShift     = kRepShift + kRepBits,
+  kTvBits      = 2,
+  kTvMask      = ((1 << kTvBits) - 1) << kTvShift,
+
+  // Varint fields:
+  kTvZigZag    = 1 << kTvShift,
+  kTvEnum      = 2 << kTvShift,  // validate using generated _IsValid()
+  kTvRange     = 3 << kTvShift,  // validate using FieldAux::enum_range
+  // String fields:
+  kTvUtf8Debug = 1 << kTvShift,  // proto2
+  kTvUtf8      = 2 << kTvShift,  // proto3
+};
+
+static_assert((kTvEnum & kTvRange) != 0,
+              "enum validation types must share a bit");
+static_assert((kTvEnum & kTvRange & kTvZigZag) == 0,
+              "zigzag encoding is not enum validation");
+
+// Format discriminators (2 bits):
+enum FormatDiscriminator : uint16_t {
+  kFmtShift      = kTvShift + kTvBits,
+  kFmtBits       = 2,
+  kFmtMask       = ((1 << kFmtBits) - 1) << kFmtShift,
+
+  // Numeric:
+  kFmtUnsigned   = 1 << kFmtShift,  // fixed, varint
+  kFmtSigned     = 2 << kFmtShift,  // fixed, varint
+  kFmtFloating   = 3 << kFmtShift,  // fixed
+  kFmtEnum       = 3 << kFmtShift,  // varint
+  // Strings:
+  kFmtUtf8       = 1 << kFmtShift,  // string (proto3, enforce_utf8=true)
+  kFmtUtf8Escape = 2 << kFmtShift,  // string (proto2, enforce_utf8=false)
+  // Bytes:
+  kFmtArray      = 1 << kFmtShift,  // bytes
+  // Messages:
+  kFmtShow       = 1 << kFmtShift,  // message, map
+};
+
+// Update this assertion (and comments above) when adding or removing bits:
+static_assert(kFmtShift + kFmtBits == 12, "number of bits changed");
+
+// This assertion should not change unless the storage width changes:
+static_assert(kFmtShift + kFmtBits <= 16, "too many bits");
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#if __GNUC__ >= 12 || (__GNUC__ == 11 && __GNUC_MINOR >= 1)
+#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion"
+#endif
+#endif
+// Convenience aliases (16 bits, with format):
+enum FieldType : uint16_t {
+  // Numeric types:
+  kBool            = kFkVarint | kRep8Bits,
+
+  kFixed32         = kFkFixed  | kRep32Bits | kFmtUnsigned,
+  kUInt32          = kFkVarint | kRep32Bits | kFmtUnsigned,
+  kSFixed32        = kFkFixed  | kRep32Bits | kFmtSigned,
+  kInt32           = kFkVarint | kRep32Bits | kFmtSigned,
+  kSInt32          = kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag,
+  kFloat           = kFkFixed  | kRep32Bits | kFmtFloating,
+  kEnum            = kFkVarint | kRep32Bits | kFmtEnum   | kTvEnum,
+  kEnumRange       = kFkVarint | kRep32Bits | kFmtEnum   | kTvRange,
+  kOpenEnum        = kFkVarint | kRep32Bits | kFmtEnum,
+
+  kFixed64         = kFkFixed  | kRep64Bits | kFmtUnsigned,
+  kUInt64          = kFkVarint | kRep64Bits | kFmtUnsigned,
+  kSFixed64        = kFkFixed  | kRep64Bits | kFmtSigned,
+  kInt64           = kFkVarint | kRep64Bits | kFmtSigned,
+  kSInt64          = kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag,
+  kDouble          = kFkFixed  | kRep64Bits | kFmtFloating,
+
+  kPackedBool      = kFkPackedVarint | kRep8Bits,
+
+  kPackedFixed32   = kFkPackedFixed  | kRep32Bits | kFmtUnsigned,
+  kPackedUInt32    = kFkPackedVarint | kRep32Bits | kFmtUnsigned,
+  kPackedSFixed32  = kFkPackedFixed  | kRep32Bits | kFmtSigned,
+  kPackedInt32     = kFkPackedVarint | kRep32Bits | kFmtSigned,
+  kPackedSInt32    = kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag,
+  kPackedFloat     = kFkPackedFixed  | kRep32Bits | kFmtFloating,
+  kPackedEnum      = kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvEnum,
+  kPackedEnumRange = kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvRange,
+  kPackedOpenEnum  = kFkPackedVarint | kRep32Bits | kFmtEnum,
+
+  kPackedFixed64   = kFkPackedFixed  | kRep64Bits | kFmtUnsigned,
+  kPackedUInt64    = kFkPackedVarint | kRep64Bits | kFmtUnsigned,
+  kPackedSFixed64  = kFkPackedFixed  | kRep64Bits | kFmtSigned,
+  kPackedInt64     = kFkPackedVarint | kRep64Bits | kFmtSigned,
+  kPackedSInt64    = kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag,
+  kPackedDouble    = kFkPackedFixed  | kRep64Bits | kFmtFloating,
+
+  // String types:
+  kBytes           = kFkString | kFmtArray,
+  kRawString       = kFkString | kFmtUtf8  | kTvUtf8Debug,
+  kUtf8String      = kFkString | kFmtUtf8  | kTvUtf8,
+
+  // Message types:
+  kMessage         = kFkMessage,
+
+  // Map types:
+  kMap             = kFkMap,
+};
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+// clang-format on
+}  // namespace field_layout
+
+// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
+// defined in port_def.inc.
+//
+// Note that this is performance sensitive: changing the parameters will change
+// the registers used by the ABI calling convention, which subsequently affects
+// register selection logic inside the function.
+
+// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
+#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
+
+#ifndef NDEBUG
+template <size_t align>
+#ifndef _MSC_VER
+[[noreturn]]
+#endif
+void AlignFail(uintptr_t address) {
+  GOOGLE_LOG(FATAL) << "Unaligned (" << align << ") access at " << address;
+#ifdef __GNUC__
+  __builtin_unreachable();
+#endif
+}
+
+extern template void AlignFail<4>(uintptr_t);
+extern template void AlignFail<8>(uintptr_t);
+#endif
+
+// TcParser implements most of the parsing logic for tailcall tables.
+class PROTOBUF_EXPORT TcParser final {
+ public:
+  static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
+  static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
+
+  static const char* ParseLoop(MessageLite* msg, const char* ptr,
+                               ParseContext* ctx,
+                               const TcParseTableBase* table);
+
+  // Functions referenced by generated fast tables (numeric types):
+  //   F: fixed      V: varint     Z: zigzag
+  //   8/32/64: storage type width (bits)
+  //   S: singular   R: repeated   P: packed
+  //   1/2: tag length (bytes)
+
+  // Fixed:
+  static const char* FastF32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64P2(PROTOBUF_TC_PARAM_DECL);
+
+  // Varint:
+  static const char* FastV8S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64P2(PROTOBUF_TC_PARAM_DECL);
+
+  // Varint (with zigzag):
+  static const char* FastZ32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (closed enum):
+  //   E: closed enum (N.B.: open enums use V32, above)
+  //   r: enum range  v: enum validator (_IsValid function)
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastErS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvR2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (string types):
+  //   B: bytes      S: string     U: UTF-8 string
+  //   (empty): ArenaStringPtr     i: InlinedString
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastBS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUR2(PROTOBUF_TC_PARAM_DECL);
+
+  static const char* FastBiS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBiS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSiS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSiS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUiS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUiS2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (message types):
+  //   M: message    G: group
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastMS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastGR2(PROTOBUF_TC_PARAM_DECL);
+
+  template <typename T>
+  static inline T& RefAt(void* x, size_t offset) {
+    T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
+#ifndef NDEBUG
+    if (PROTOBUF_PREDICT_FALSE(
+            reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
+      AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
+    }
+#endif
+    return *target;
+  }
+
+  template <typename T>
+  static inline const T& RefAt(const void* x, size_t offset) {
+    const T* target =
+        reinterpret_cast<const T*>(static_cast<const char*>(x) + offset);
+#ifndef NDEBUG
+    if (PROTOBUF_PREDICT_FALSE(
+            reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
+      AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
+    }
+#endif
+    return *target;
+  }
+
+  template <typename T>
+  static inline T ReadAt(const void* x, size_t offset) {
+    T out;
+    memcpy(&out, static_cast<const char*>(x) + offset, sizeof(T));
+    return out;
+  }
+
+  // Mini parsing:
+  //
+  // This function parses a field from incoming data based on metadata stored in
+  // the message definition. If the field is not defined in the message, it is
+  // stored in either the ExtensionSet (if applicable) or the UnknownFieldSet.
+  //
+  // NOTE: Currently, this function only calls the table-level fallback
+  // function, so it should only be called as the fallback from fast table
+  // parsing.
+  static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
+
+ private:
+  friend class GeneratedTcTableLiteTest;
+
+  template <typename TagType, bool group_coding>
+  static inline const char* SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, bool group_coding>
+  static inline const char* RepeatedParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL);
+
+  static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
+      MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) {
+    const uint32_t has_bits_offset = table->has_bits_offset;
+    if (has_bits_offset) {
+      // Only the first 32 has-bits are updated. Nothing above those is stored,
+      // but e.g. messages without has-bits update the upper bits.
+      RefAt<uint32_t>(msg, has_bits_offset) = static_cast<uint32_t>(hasbits);
+    }
+  }
+
+  static const char* TagDispatch(PROTOBUF_TC_PARAM_DECL);
+  static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL);
+  static const char* ToParseLoop(PROTOBUF_TC_PARAM_DECL);
+  static const char* Error(PROTOBUF_TC_PARAM_DECL);
+
+  static const char* FastUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
+
+  class ScopedArenaSwap;
+
+  template <class MessageBaseT, class UnknownFieldsT>
+  static const char* GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL) {
+#define CHK_(x) \
+  if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr /* NOLINT */
+
+    SyncHasbits(msg, hasbits, table);
+    CHK_(ptr);
+    uint32_t tag = data.tag();
+    if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
+      ctx->SetLastTag(tag);
+      return ptr;
+    }
+    uint32_t num = tag >> 3;
+    if (table->extension_range_low <= num &&
+        num <= table->extension_range_high) {
+      return RefAt<ExtensionSet>(msg, table->extension_offset)
+          .ParseField(tag, ptr,
+                      static_cast<const MessageBaseT*>(table->default_instance),
+                      &msg->_internal_metadata_, ctx);
+    }
+    return UnknownFieldParse(
+        tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
+        ptr, ctx);
+#undef CHK_
+  }
+
+  // Note: `inline` is needed on template function declarations below to avoid
+  // -Wattributes diagnostic in GCC.
+
+  // Implementations for fast fixed field parsing functions:
+  template <typename LayoutType, typename TagType>
+  static inline const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
+  template <typename LayoutType, typename TagType>
+  static inline const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
+  template <typename LayoutType, typename TagType>
+  static inline const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast varint field parsing functions:
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
+
+  // Helper for ints > 127:
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static const char* SingularVarBigint(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast enum field parsing functions:
+  template <typename TagType, uint16_t xform_val>
+  static inline const char* SingularEnum(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, uint16_t xform_val>
+  static inline const char* RepeatedEnum(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast string field parsing functions:
+  enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
+  template <typename TagType, Utf8Type utf8>
+  static inline const char* SingularString(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, Utf8Type utf8>
+  static inline const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
+
+  // Mini field lookup:
+  static const TcParseTableBase::FieldEntry* FindFieldEntry(
+      const TcParseTableBase* table, uint32_t field_num);
+  static StringPiece MessageName(const TcParseTableBase* table);
+  static StringPiece FieldName(const TcParseTableBase* table,
+                                     const TcParseTableBase::FieldEntry*);
+  static bool ChangeOneof(const TcParseTableBase* table,
+                          const TcParseTableBase::FieldEntry& entry,
+                          uint32_t field_num, ParseContext* ctx,
+                          MessageLite* msg);
+
+  // UTF-8 validation:
+  static void ReportFastUtf8Error(uint32_t decoded_tag,
+                                  const TcParseTableBase* table);
+  static bool MpVerifyUtf8(StringPiece wire_bytes,
+                           const TcParseTableBase* table,
+                           const TcParseTableBase::FieldEntry& entry,
+                           uint16_t xform_val);
+
+  // For FindFieldEntry tests:
+  friend class FindFieldEntryTest;
+  static constexpr const uint32_t kMtSmallScanSize = 4;
+
+  // Mini parsing:
+  static const char* MpVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpPackedVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpPackedFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpString(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedString(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpMessage(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpMap(PROTOBUF_TC_PARAM_DECL);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_util.h
new file mode 100644
index 0000000..71d15cd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/generated_message_util.h
@@ -0,0 +1,214 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains miscellaneous helper code used by generated code --
+// including lite types -- but which should not be used directly by users.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+
+#include <assert.h>
+
+#include <atomic>
+#include <climits>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>  // Add direct dep on port for pb.cc
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/has_bits.h>
+#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/casts.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Arena;
+class Message;
+
+namespace io {
+class CodedInputStream;
+}
+
+namespace internal {
+
+template <typename To, typename From>
+inline To DownCast(From* f) {
+  return PROTOBUF_NAMESPACE_ID::internal::down_cast<To>(f);
+}
+template <typename To, typename From>
+inline To DownCast(From& f) {
+  return PROTOBUF_NAMESPACE_ID::internal::down_cast<To>(f);
+}
+
+
+// This fastpath inlines a single branch instead of having to make the
+// InitProtobufDefaults function call.
+// It also generates less inlined code than a function-scope static initializer.
+PROTOBUF_EXPORT extern std::atomic<bool> init_protobuf_defaults_state;
+PROTOBUF_EXPORT void InitProtobufDefaultsSlow();
+PROTOBUF_EXPORT inline void InitProtobufDefaults() {
+  if (PROTOBUF_PREDICT_FALSE(
+          !init_protobuf_defaults_state.load(std::memory_order_acquire))) {
+    InitProtobufDefaultsSlow();
+  }
+}
+
+// This used by proto1
+PROTOBUF_EXPORT inline const std::string& GetEmptyString() {
+  InitProtobufDefaults();
+  return GetEmptyStringAlreadyInited();
+}
+
+
+// True if IsInitialized() is true for all elements of t.  Type is expected
+// to be a RepeatedPtrField<some message type>.  It's useful to have this
+// helper here to keep the protobuf compiler from ever having to emit loops in
+// IsInitialized() methods.  We want the C++ compiler to inline this or not
+// as it sees fit.
+template <typename Msg>
+bool AllAreInitialized(const RepeatedPtrField<Msg>& t) {
+  for (int i = t.size(); --i >= 0;) {
+    if (!t.Get(i).IsInitialized()) return false;
+  }
+  return true;
+}
+
+// "Weak" variant of AllAreInitialized, used to implement implicit weak fields.
+// This version operates on MessageLite to avoid introducing a dependency on the
+// concrete message type.
+template <class T>
+bool AllAreInitializedWeak(const RepeatedPtrField<T>& t) {
+  for (int i = t.size(); --i >= 0;) {
+    if (!reinterpret_cast<const RepeatedPtrFieldBase&>(t)
+             .Get<ImplicitWeakTypeHandler<T> >(i)
+             .IsInitialized()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+inline bool IsPresent(const void* base, uint32_t hasbit) {
+  const uint32_t* has_bits_array = static_cast<const uint32_t*>(base);
+  return (has_bits_array[hasbit / 32] & (1u << (hasbit & 31))) != 0;
+}
+
+inline bool IsOneofPresent(const void* base, uint32_t offset, uint32_t tag) {
+  const uint32_t* oneof = reinterpret_cast<const uint32_t*>(
+      static_cast<const uint8_t*>(base) + offset);
+  return *oneof == tag >> 3;
+}
+
+typedef void (*SpecialSerializer)(const uint8_t* base, uint32_t offset,
+                                  uint32_t tag, uint32_t has_offset,
+                                  io::CodedOutputStream* output);
+
+PROTOBUF_EXPORT void ExtensionSerializer(const MessageLite* extendee,
+                                         const uint8_t* ptr, uint32_t offset,
+                                         uint32_t tag, uint32_t has_offset,
+                                         io::CodedOutputStream* output);
+PROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8_t* base,
+                                                uint32_t offset, uint32_t tag,
+                                                uint32_t has_offset,
+                                                io::CodedOutputStream* output);
+
+PROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message);
+PROTOBUF_EXPORT MessageLite* GetOwnedMessageInternal(Arena* message_arena,
+                                                     MessageLite* submessage,
+                                                     Arena* submessage_arena);
+PROTOBUF_EXPORT void GenericSwap(MessageLite* m1, MessageLite* m2);
+// We specialize GenericSwap for non-lite messages to benefit from reflection.
+PROTOBUF_EXPORT void GenericSwap(Message* m1, Message* m2);
+
+template <typename T>
+T* DuplicateIfNonNull(T* message) {
+  // The casts must be reinterpret_cast<> because T might be a forward-declared
+  // type that the compiler doesn't know is related to MessageLite.
+  return reinterpret_cast<T*>(
+      DuplicateIfNonNullInternal(reinterpret_cast<MessageLite*>(message)));
+}
+
+template <typename T>
+T* GetOwnedMessage(Arena* message_arena, T* submessage,
+                   Arena* submessage_arena) {
+  // The casts must be reinterpret_cast<> because T might be a forward-declared
+  // type that the compiler doesn't know is related to MessageLite.
+  return reinterpret_cast<T*>(GetOwnedMessageInternal(
+      message_arena, reinterpret_cast<MessageLite*>(submessage),
+      submessage_arena));
+}
+
+// Hide atomic from the public header and allow easy change to regular int
+// on platforms where the atomic might have a perf impact.
+class PROTOBUF_EXPORT CachedSize {
+ public:
+  int Get() const { return size_.load(std::memory_order_relaxed); }
+  void Set(int size) { size_.store(size, std::memory_order_relaxed); }
+
+ private:
+  std::atomic<int> size_{0};
+};
+
+PROTOBUF_EXPORT void DestroyMessage(const void* message);
+PROTOBUF_EXPORT void DestroyString(const void* s);
+// Destroy (not delete) the message
+inline void OnShutdownDestroyMessage(const void* ptr) {
+  OnShutdownRun(DestroyMessage, ptr);
+}
+// Destroy the string (call std::string destructor)
+inline void OnShutdownDestroyString(const std::string* ptr) {
+  OnShutdownRun(DestroyString, ptr);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/has_bits.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/has_bits.h
new file mode 100644
index 0000000..f8a4587
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/has_bits.h
@@ -0,0 +1,117 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_HAS_BITS_H__
+#define GOOGLE_PROTOBUF_HAS_BITS_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+template <size_t doublewords>
+class HasBits {
+ public:
+  PROTOBUF_NDEBUG_INLINE constexpr HasBits() : has_bits_{} {}
+
+  PROTOBUF_NDEBUG_INLINE void Clear() {
+    memset(has_bits_, 0, sizeof(has_bits_));
+  }
+
+  PROTOBUF_NDEBUG_INLINE uint32_t& operator[](int index) {
+    return has_bits_[index];
+  }
+
+  PROTOBUF_NDEBUG_INLINE const uint32_t& operator[](int index) const {
+    return has_bits_[index];
+  }
+
+  bool operator==(const HasBits<doublewords>& rhs) const {
+    return memcmp(has_bits_, rhs.has_bits_, sizeof(has_bits_)) == 0;
+  }
+
+  bool operator!=(const HasBits<doublewords>& rhs) const {
+    return !(*this == rhs);
+  }
+
+  void Or(const HasBits<doublewords>& rhs) {
+    for (size_t i = 0; i < doublewords; i++) has_bits_[i] |= rhs[i];
+  }
+
+  bool empty() const;
+
+ private:
+  uint32_t has_bits_[doublewords];
+};
+
+template <>
+inline bool HasBits<1>::empty() const {
+  return !has_bits_[0];
+}
+
+template <>
+inline bool HasBits<2>::empty() const {
+  return !(has_bits_[0] | has_bits_[1]);
+}
+
+template <>
+inline bool HasBits<3>::empty() const {
+  return !(has_bits_[0] | has_bits_[1] | has_bits_[2]);
+}
+
+template <>
+inline bool HasBits<4>::empty() const {
+  return !(has_bits_[0] | has_bits_[1] | has_bits_[2] | has_bits_[3]);
+}
+
+template <size_t doublewords>
+inline bool HasBits<doublewords>::empty() const {
+  for (size_t i = 0; i < doublewords; ++i) {
+    if (has_bits_[i]) return false;
+  }
+  return true;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_HAS_BITS_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/implicit_weak_message.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/implicit_weak_message.h
new file mode 100644
index 0000000..c358c14
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/implicit_weak_message.h
@@ -0,0 +1,213 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
+#define GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
+
+#include <string>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// This file is logically internal-only and should only be used by protobuf
+// generated code.
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// An implementation of MessageLite that treats all data as unknown. This type
+// acts as a placeholder for an implicit weak field in the case where the true
+// message type does not get linked into the binary.
+class PROTOBUF_EXPORT ImplicitWeakMessage : public MessageLite {
+ public:
+  ImplicitWeakMessage() : data_(new std::string) {}
+  explicit constexpr ImplicitWeakMessage(ConstantInitialized)
+      : data_(nullptr) {}
+  explicit ImplicitWeakMessage(Arena* arena)
+      : MessageLite(arena), data_(new std::string) {}
+
+  ~ImplicitWeakMessage() override {
+    // data_ will be null in the default instance, but we can safely call delete
+    // here because the default instance will never be destroyed.
+    delete data_;
+  }
+
+  static const ImplicitWeakMessage* default_instance();
+
+  std::string GetTypeName() const override { return ""; }
+
+  MessageLite* New(Arena* arena) const override {
+    return Arena::CreateMessage<ImplicitWeakMessage>(arena);
+  }
+
+  void Clear() override { data_->clear(); }
+
+  bool IsInitialized() const override { return true; }
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) override {
+    const std::string* other_data =
+        static_cast<const ImplicitWeakMessage&>(other).data_;
+    if (other_data != nullptr) {
+      data_->append(*other_data);
+    }
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) final;
+
+  size_t ByteSizeLong() const override {
+    return data_ == nullptr ? 0 : data_->size();
+  }
+
+  uint8_t* _InternalSerialize(uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const final {
+    if (data_ == nullptr) {
+      return target;
+    }
+    return stream->WriteRaw(data_->data(), data_->size(),
+                            target);
+  }
+
+  int GetCachedSize() const override {
+    return data_ == nullptr ? 0 : static_cast<int>(data_->size());
+  }
+
+  typedef void InternalArenaConstructable_;
+
+ private:
+  // This std::string is allocated on the heap, but we use a raw pointer so that
+  // the default instance can be constant-initialized. In the const methods, we
+  // have to handle the possibility of data_ being null.
+  std::string* data_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImplicitWeakMessage);
+};
+
+struct ImplicitWeakMessageDefaultType;
+extern ImplicitWeakMessageDefaultType implicit_weak_message_default_instance;
+
+// A type handler for use with implicit weak repeated message fields.
+template <typename ImplicitWeakType>
+class ImplicitWeakTypeHandler {
+ public:
+  typedef MessageLite Type;
+  static constexpr bool Moveable = false;
+
+  static inline MessageLite* NewFromPrototype(const MessageLite* prototype,
+                                              Arena* arena = nullptr) {
+    return prototype->New(arena);
+  }
+
+  static inline void Delete(MessageLite* value, Arena* arena) {
+    if (arena == nullptr) {
+      delete value;
+    }
+  }
+  static inline Arena* GetArena(MessageLite* value) {
+    return value->GetArena();
+  }
+  static inline void Clear(MessageLite* value) { value->Clear(); }
+  static void Merge(const MessageLite& from, MessageLite* to) {
+    to->CheckTypeAndMergeFrom(from);
+  }
+};
+
+}  // namespace internal
+
+template <typename T>
+struct WeakRepeatedPtrField {
+  using TypeHandler = internal::ImplicitWeakTypeHandler<T>;
+  constexpr WeakRepeatedPtrField() : weak() {}
+  explicit WeakRepeatedPtrField(Arena* arena) : weak(arena) {}
+  ~WeakRepeatedPtrField() { weak.template Destroy<TypeHandler>(); }
+
+  typedef internal::RepeatedPtrIterator<MessageLite> iterator;
+  typedef internal::RepeatedPtrIterator<const MessageLite> const_iterator;
+  typedef internal::RepeatedPtrOverPtrsIterator<MessageLite*, void*>
+      pointer_iterator;
+  typedef internal::RepeatedPtrOverPtrsIterator<const MessageLite* const,
+                                                const void* const>
+      const_pointer_iterator;
+
+  iterator begin() { return iterator(base().raw_data()); }
+  const_iterator begin() const { return iterator(base().raw_data()); }
+  const_iterator cbegin() const { return begin(); }
+  iterator end() { return begin() + base().size(); }
+  const_iterator end() const { return begin() + base().size(); }
+  const_iterator cend() const { return end(); }
+  pointer_iterator pointer_begin() {
+    return pointer_iterator(base().raw_mutable_data());
+  }
+  const_pointer_iterator pointer_begin() const {
+    return const_pointer_iterator(base().raw_mutable_data());
+  }
+  pointer_iterator pointer_end() {
+    return pointer_iterator(base().raw_mutable_data() + base().size());
+  }
+  const_pointer_iterator pointer_end() const {
+    return const_pointer_iterator(base().raw_mutable_data() + base().size());
+  }
+
+  MessageLite* AddWeak(const MessageLite* prototype) {
+    return base().AddWeak(prototype);
+  }
+  T* Add() { return weak.Add(); }
+  void Clear() { base().template Clear<TypeHandler>(); }
+  void MergeFrom(const WeakRepeatedPtrField& other) {
+    base().template MergeFrom<TypeHandler>(other.base());
+  }
+  void InternalSwap(WeakRepeatedPtrField* other) {
+    base().InternalSwap(&other->base());
+  }
+
+  const internal::RepeatedPtrFieldBase& base() const { return weak; }
+  internal::RepeatedPtrFieldBase& base() { return weak; }
+  // Union disables running the destructor. Which would create a strong link.
+  // Instead we explicitly destroy the underlying base through the virtual
+  // destructor.
+  union {
+    RepeatedPtrField<T> weak;
+  };
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/inlined_string_field.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/inlined_string_field.h
new file mode 100644
index 0000000..79e37d4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/inlined_string_field.h
@@ -0,0 +1,532 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
+#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
+
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Arena;
+
+namespace internal {
+
+// InlinedStringField wraps a std::string instance and exposes an API similar to
+// ArenaStringPtr's wrapping of a std::string* instance.
+//
+// default_value parameters are taken for consistency with ArenaStringPtr, but
+// are not used for most methods. With inlining, these should be removed from
+// the generated binary.
+//
+// InlinedStringField has a donating mechanism that allows string buffer
+// allocated on arena. A string is donated means both the string container and
+// the data buffer are on arena. The donating mechanism here is similar to the
+// one in ArenaStringPtr with some differences:
+//
+// When an InlinedStringField is constructed, the donating state is true. This
+// is because the string container is directly stored in the message on the
+// arena:
+//
+//   Construction: donated=true
+//   Arena:
+//   +-----------------------+
+//   |Message foo:           |
+//   | +-------------------+ |
+//   | |InlinedStringField:| |
+//   | | +-----+           | |
+//   | | | | | |           | |
+//   | | +-----+           | |
+//   | +-------------------+ |
+//   +-----------------------+
+//
+// When lvalue Set is called, the donating state is still true. String data will
+// be allocated on the arena:
+//
+//   Lvalue Set: donated=true
+//   Arena:
+//   +-----------------------+
+//   |Message foo:           |
+//   | +-------------------+ |
+//   | |InlinedStringField:| |
+//   | | +-----+           | |
+//   | | | | | |           | |
+//   | | +|----+           | |
+//   | +--|----------------+ |
+//   |    V                  |
+//   |  +----------------+   |
+//   |  |'f','o','o',... |   |
+//   |  +----------------+   |
+//   +-----------------------+
+//
+// Some operations will undonate a donated string, including: Mutable,
+// SetAllocated, Rvalue Set, and Swap with a non-donated string.
+//
+// For more details of the donating states transitions, go/pd-inlined-string.
+class PROTOBUF_EXPORT InlinedStringField {
+ public:
+  InlinedStringField() { Init(); }
+  inline void Init() { new (get_mutable()) std::string(); }
+  // Add the dummy parameter just to make InlinedStringField(nullptr)
+  // unambiguous.
+  constexpr InlinedStringField(
+      const ExplicitlyConstructed<std::string>* /*default_value*/,
+      bool /*dummy*/)
+      : value_{} {}
+  explicit InlinedStringField(const std::string& default_value);
+  explicit InlinedStringField(Arena* arena);
+  ~InlinedStringField() { Destruct(); }
+
+  // Lvalue Set. To save space, we pack the donating states of multiple
+  // InlinedStringFields into an uint32_t `donating_states`. The `mask`
+  // indicates the position of the bit for this InlinedStringField. `donated` is
+  // whether this field is donated.
+  //
+  // The caller should guarantee that:
+  //
+  //   `donated == ((donating_states & ~mask) != 0)`
+  //
+  // This method never changes the `donating_states`.
+  void Set(ConstStringParam value, Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  // Rvalue Set. If this field is donated, this method will undonate this field
+  // by mutating the `donating_states` according to `mask`.
+  void Set(std::string&& value, Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void Set(const char* str, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void Set(const char* str, size_t size, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  template <typename RefWrappedType>
+  void Set(std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+           uint32_t mask, MessageLite* msg);
+
+  void SetBytes(ConstStringParam value, Arena* arena, bool donated,
+                uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void SetBytes(std::string&& value, Arena* arena, bool donated,
+                uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void SetBytes(const char* str, ::google::protobuf::Arena* arena, bool donated,
+                uint32_t* donating_states, uint32_t mask, MessageLite* msg);
+
+  void SetBytes(const void* p, size_t size, ::google::protobuf::Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg);
+
+  template <typename RefWrappedType>
+  void SetBytes(std::reference_wrapper<RefWrappedType> const_string_ref,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask, MessageLite* msg);
+
+  PROTOBUF_NDEBUG_INLINE void SetNoArena(StringPiece value);
+  PROTOBUF_NDEBUG_INLINE void SetNoArena(std::string&& value);
+
+  // Basic accessors.
+  PROTOBUF_NDEBUG_INLINE const std::string& Get() const { return GetNoArena(); }
+  PROTOBUF_NDEBUG_INLINE const std::string& GetNoArena() const;
+
+  // Mutable returns a std::string* instance that is heap-allocated. If this
+  // field is donated, this method undonates this field by mutating the
+  // `donating_states` according to `mask`, and copies the content of the
+  // original string to the returning string.
+  std::string* Mutable(Arena* arena, bool donated, uint32_t* donating_states,
+                       uint32_t mask, MessageLite* msg);
+  std::string* Mutable(const LazyString& default_value, Arena* arena,
+                       bool donated, uint32_t* donating_states, uint32_t mask,
+                       MessageLite* msg);
+
+  // Mutable(nullptr_t) is an overload to explicitly support Mutable(nullptr)
+  // calls used by the internal parser logic. This provides API equivalence with
+  // ArenaStringPtr, while still protecting against calls with arena pointers.
+  std::string* Mutable(std::nullptr_t);
+  std::string* MutableNoCopy(std::nullptr_t);
+
+  // Takes a std::string that is heap-allocated, and takes ownership. The
+  // std::string's destructor is registered with the arena. Used to implement
+  // set_allocated_<field> in generated classes.
+  //
+  // If this field is donated, this method undonates this field by mutating the
+  // `donating_states` according to `mask`.
+  void SetAllocated(const std::string* default_value, std::string* value,
+                    Arena* arena, bool donated, uint32_t* donating_states,
+                    uint32_t mask, MessageLite* msg);
+
+  void SetAllocatedNoArena(const std::string* default_value,
+                           std::string* value);
+
+  // Release returns a std::string* instance that is heap-allocated and is not
+  // Own()'d by any arena. If the field is not set, this returns nullptr. The
+  // caller retains ownership. Clears this field back to nullptr state. Used to
+  // implement release_<field>() methods on generated classes.
+  PROTOBUF_NODISCARD std::string* Release(Arena* arena, bool donated);
+  PROTOBUF_NODISCARD std::string* Release();
+
+  // --------------------------------------------------------
+  // Below functions will be removed in subsequent code change
+  // --------------------------------------------------------
+#ifdef DEPRECATED_METHODS_TO_BE_DELETED
+  PROTOBUF_NODISCARD std::string* Release(const std::string*, Arena* arena,
+                                          bool donated) {
+    return Release(arena, donated);
+  }
+
+  PROTOBUF_NODISCARD std::string* ReleaseNonDefault(const std::string*,
+                                                    Arena* arena) {
+    return Release();
+  }
+
+  std::string* ReleaseNonDefaultNoArena(const std::string* default_value) {
+    return Release();
+  }
+
+  void Set(const std::string*, ConstStringParam value, Arena* arena,
+           bool donated, uint32_t* donating_states, uint32_t mask,
+           MessageLite* msg) {
+    Set(value, arena, donated, donating_states, mask, msg);
+  }
+
+  void Set(const std::string*, std::string&& value, Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg) {
+    Set(std::move(value), arena, donated, donating_states, mask, msg);
+  }
+
+
+  template <typename FirstParam>
+  void Set(FirstParam, const char* str, ::google::protobuf::Arena* arena, bool donated,
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg) {
+    Set(str, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam>
+  void Set(FirstParam p1, const char* str, size_t size, ::google::protobuf::Arena* arena,
+           bool donated, uint32_t* donating_states, uint32_t mask,
+           MessageLite* msg) {
+    Set(str, size, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam, typename RefWrappedType>
+  void Set(FirstParam p1,
+           std::reference_wrapper<RefWrappedType> const_string_ref,
+           ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+           uint32_t mask, MessageLite* msg) {
+    Set(const_string_ref, arena, donated, donating_states, mask, msg);
+  }
+
+  void SetBytes(const std::string*, ConstStringParam value, Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
+    Set(value, arena, donated, donating_states, mask, msg);
+  }
+
+
+  void SetBytes(const std::string*, std::string&& value, Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
+    Set(std::move(value), arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam>
+  void SetBytes(FirstParam p1, const char* str, ::google::protobuf::Arena* arena,
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
+    SetBytes(str, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam>
+  void SetBytes(FirstParam p1, const void* p, size_t size,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask, MessageLite* msg) {
+    SetBytes(p, size, arena, donated, donating_states, mask, msg);
+  }
+
+  template <typename FirstParam, typename RefWrappedType>
+  void SetBytes(FirstParam p1,
+                std::reference_wrapper<RefWrappedType> const_string_ref,
+                ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+                uint32_t mask, MessageLite* msg) {
+    SetBytes(const_string_ref.get(), arena, donated, donating_states, mask,
+             msg);
+  }
+
+  void SetNoArena(const std::string*, StringPiece value) {
+    SetNoArena(value);
+  }
+  void SetNoArena(const std::string*, std::string&& value) {
+    SetNoArena(std::move(value));
+  }
+
+  std::string* Mutable(ArenaStringPtr::EmptyDefault, Arena* arena, bool donated,
+                       uint32_t* donating_states, uint32_t mask,
+                       MessageLite* msg) {
+    return Mutable(arena, donated, donating_states, mask, msg);
+  }
+
+  PROTOBUF_NDEBUG_INLINE std::string* MutableNoArenaNoDefault(
+      const std::string* /*default_value*/) {
+    return MutableNoCopy(nullptr);
+  }
+
+#endif  // DEPRECATED_METHODS_TO_BE_DELETED
+
+  // Arena-safety semantics: this is guarded by the logic in
+  // Swap()/UnsafeArenaSwap() at the message level, so this method is
+  // 'unsafe' if called directly.
+  inline PROTOBUF_NDEBUG_INLINE static void InternalSwap(
+      InlinedStringField* lhs, Arena* lhs_arena, bool lhs_arena_dtor_registered,
+      MessageLite* lhs_msg,  //
+      InlinedStringField* rhs, Arena* rhs_arena, bool rhs_arena_dtor_registered,
+      MessageLite* rhs_msg);
+
+  // Frees storage (if not on an arena).
+  PROTOBUF_NDEBUG_INLINE void Destroy(const std::string* default_value,
+                                      Arena* arena) {
+    if (arena == nullptr) {
+      DestroyNoArena(default_value);
+    }
+  }
+  PROTOBUF_NDEBUG_INLINE void DestroyNoArena(const std::string* default_value);
+
+  // Clears content, but keeps allocated std::string, to avoid the overhead of
+  // heap operations. After this returns, the content (as seen by the user) will
+  // always be the empty std::string.
+  PROTOBUF_NDEBUG_INLINE void ClearToEmpty() { ClearNonDefaultToEmpty(); }
+  PROTOBUF_NDEBUG_INLINE void ClearNonDefaultToEmpty() {
+    get_mutable()->clear();
+  }
+
+  // Clears content, but keeps allocated std::string if arena != nullptr, to
+  // avoid the overhead of heap operations. After this returns, the content (as
+  // seen by the user) will always be equal to |default_value|.
+  void ClearToDefault(const LazyString& default_value, Arena* arena,
+                      bool donated);
+
+  // Generated code / reflection only! Returns a mutable pointer to the string.
+  PROTOBUF_NDEBUG_INLINE std::string* UnsafeMutablePointer();
+
+  // InlinedStringField doesn't have things like the `default_value` pointer in
+  // ArenaStringPtr.
+  static constexpr bool IsDefault() { return false; }
+  static constexpr bool IsDefault(const std::string*) { return false; }
+
+ private:
+  void Destruct() { get_mutable()->~basic_string(); }
+
+  PROTOBUF_NDEBUG_INLINE std::string* get_mutable();
+  PROTOBUF_NDEBUG_INLINE const std::string* get_const() const;
+
+  alignas(std::string) char value_[sizeof(std::string)];
+
+  std::string* MutableSlow(::google::protobuf::Arena* arena, bool donated,
+                           uint32_t* donating_states, uint32_t mask,
+                           MessageLite* msg);
+
+
+  // When constructed in an Arena, we want our destructor to be skipped.
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+};
+
+inline std::string* InlinedStringField::get_mutable() {
+  return reinterpret_cast<std::string*>(&value_);
+}
+
+inline const std::string* InlinedStringField::get_const() const {
+  return reinterpret_cast<const std::string*>(&value_);
+}
+
+inline InlinedStringField::InlinedStringField(
+    const std::string& default_value) {
+  new (get_mutable()) std::string(default_value);
+}
+
+
+inline InlinedStringField::InlinedStringField(Arena* /*arena*/) { Init(); }
+
+inline const std::string& InlinedStringField::GetNoArena() const {
+  return *get_const();
+}
+
+inline void InlinedStringField::SetAllocatedNoArena(
+    const std::string* /*default_value*/, std::string* value) {
+  if (value == nullptr) {
+    // Currently, inlined string field can't have non empty default.
+    get_mutable()->clear();
+  } else {
+    get_mutable()->assign(std::move(*value));
+    delete value;
+  }
+}
+
+inline void InlinedStringField::DestroyNoArena(const std::string*) {
+  // This is invoked from the generated message's ArenaDtor, which is used to
+  // clean up objects not allocated on the Arena.
+  this->~InlinedStringField();
+}
+
+inline void InlinedStringField::SetNoArena(StringPiece value) {
+  get_mutable()->assign(value.data(), value.length());
+}
+
+inline void InlinedStringField::SetNoArena(std::string&& value) {
+  get_mutable()->assign(std::move(value));
+}
+
+// Caller should make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
+inline PROTOBUF_NDEBUG_INLINE void InlinedStringField::InternalSwap(
+    InlinedStringField* lhs, Arena* lhs_arena, bool lhs_arena_dtor_registered,
+    MessageLite* lhs_msg,  //
+    InlinedStringField* rhs, Arena* rhs_arena, bool rhs_arena_dtor_registered,
+    MessageLite* rhs_msg) {
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  lhs->get_mutable()->swap(*rhs->get_mutable());
+  if (!lhs_arena_dtor_registered && rhs_arena_dtor_registered) {
+    lhs_msg->OnDemandRegisterArenaDtor(lhs_arena);
+  } else if (lhs_arena_dtor_registered && !rhs_arena_dtor_registered) {
+    rhs_msg->OnDemandRegisterArenaDtor(rhs_arena);
+  }
+#else
+  (void)lhs_arena;
+  (void)rhs_arena;
+  (void)lhs_arena_dtor_registered;
+  (void)rhs_arena_dtor_registered;
+  (void)lhs_msg;
+  (void)rhs_msg;
+  lhs->get_mutable()->swap(*rhs->get_mutable());
+#endif
+}
+
+inline void InlinedStringField::Set(ConstStringParam value, Arena* arena,
+                                    bool donated, uint32_t* /*donating_states*/,
+                                    uint32_t /*mask*/, MessageLite* /*msg*/) {
+  (void)arena;
+  (void)donated;
+  SetNoArena(value);
+}
+
+inline void InlinedStringField::Set(const char* str, ::google::protobuf::Arena* arena,
+                                    bool donated, uint32_t* donating_states,
+                                    uint32_t mask, MessageLite* msg) {
+  Set(ConstStringParam(str), arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::Set(const char* str, size_t size,
+                                    ::google::protobuf::Arena* arena, bool donated,
+                                    uint32_t* donating_states, uint32_t mask,
+                                    MessageLite* msg) {
+  Set(ConstStringParam{str, size}, arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(ConstStringParam value, Arena* arena,
+                                         bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(value, arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(std::string&& value, Arena* arena,
+                                         bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(std::move(value), arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(const char* str,
+                                         ::google::protobuf::Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(str, arena, donated, donating_states, mask, msg);
+}
+
+inline void InlinedStringField::SetBytes(const void* p, size_t size,
+                                         ::google::protobuf::Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  Set(static_cast<const char*>(p), size, arena, donated, donating_states, mask,
+      msg);
+}
+
+template <typename RefWrappedType>
+inline void InlinedStringField::Set(
+    std::reference_wrapper<RefWrappedType> const_string_ref,
+    ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+    uint32_t mask, MessageLite* msg) {
+  Set(const_string_ref.get(), arena, donated, donating_states, mask, msg);
+}
+
+template <typename RefWrappedType>
+inline void InlinedStringField::SetBytes(
+    std::reference_wrapper<RefWrappedType> const_string_ref,
+    ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
+    uint32_t mask, MessageLite* msg) {
+  Set(const_string_ref.get(), arena, donated, donating_states, mask, msg);
+}
+
+inline std::string* InlinedStringField::UnsafeMutablePointer() {
+  return get_mutable();
+}
+
+inline std::string* InlinedStringField::Mutable(std::nullptr_t) {
+  return get_mutable();
+}
+
+inline std::string* InlinedStringField::MutableNoCopy(std::nullptr_t) {
+  return get_mutable();
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/coded_stream.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/coded_stream.h
new file mode 100644
index 0000000..6c0dd4a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/coded_stream.h
@@ -0,0 +1,1799 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains the CodedInputStream and CodedOutputStream classes,
+// which wrap a ZeroCopyInputStream or ZeroCopyOutputStream, respectively,
+// and allow you to read or write individual pieces of data in various
+// formats.  In particular, these implement the varint encoding for
+// integers, a simple variable-length encoding in which smaller numbers
+// take fewer bytes.
+//
+// Typically these classes will only be used internally by the protocol
+// buffer library in order to encode and decode protocol buffers.  Clients
+// of the library only need to know about this class if they wish to write
+// custom message parsing or serialization procedures.
+//
+// CodedOutputStream example:
+//   // Write some data to "myfile".  First we write a 4-byte "magic number"
+//   // to identify the file type, then write a length-delimited string.  The
+//   // string is composed of a varint giving the length followed by the raw
+//   // bytes.
+//   int fd = open("myfile", O_CREAT | O_WRONLY);
+//   ZeroCopyOutputStream* raw_output = new FileOutputStream(fd);
+//   CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
+//
+//   int magic_number = 1234;
+//   char text[] = "Hello world!";
+//   coded_output->WriteLittleEndian32(magic_number);
+//   coded_output->WriteVarint32(strlen(text));
+//   coded_output->WriteRaw(text, strlen(text));
+//
+//   delete coded_output;
+//   delete raw_output;
+//   close(fd);
+//
+// CodedInputStream example:
+//   // Read a file created by the above code.
+//   int fd = open("myfile", O_RDONLY);
+//   ZeroCopyInputStream* raw_input = new FileInputStream(fd);
+//   CodedInputStream* coded_input = new CodedInputStream(raw_input);
+//
+//   coded_input->ReadLittleEndian32(&magic_number);
+//   if (magic_number != 1234) {
+//     cerr << "File not in expected format." << endl;
+//     return;
+//   }
+//
+//   uint32_t size;
+//   coded_input->ReadVarint32(&size);
+//
+//   char* text = new char[size + 1];
+//   coded_input->ReadRaw(buffer, size);
+//   text[size] = '\0';
+//
+//   delete coded_input;
+//   delete raw_input;
+//   close(fd);
+//
+//   cout << "Text is: " << text << endl;
+//   delete [] text;
+//
+// For those who are interested, varint encoding is defined as follows:
+//
+// The encoding operates on unsigned integers of up to 64 bits in length.
+// Each byte of the encoded value has the format:
+// * bits 0-6: Seven bits of the number being encoded.
+// * bit 7: Zero if this is the last byte in the encoding (in which
+//   case all remaining bits of the number are zero) or 1 if
+//   more bytes follow.
+// The first byte contains the least-significant 7 bits of the number, the
+// second byte (if present) contains the next-least-significant 7 bits,
+// and so on.  So, the binary number 1011000101011 would be encoded in two
+// bytes as "10101011 00101100".
+//
+// In theory, varint could be used to encode integers of any length.
+// However, for practicality we set a limit at 64 bits.  The maximum encoded
+// length of a number is thus 10 bytes.
+
+#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
+#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
+
+
+#include <assert.h>
+
+#include <atomic>
+#include <climits>
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
+// If MSVC has "/RTCc" set, it will complain about truncating casts at
+// runtime.  This file contains some intentional truncating casts.
+#pragma runtime_checks("c", off)
+#endif
+
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/port.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class DescriptorPool;
+class MessageFactory;
+class ZeroCopyCodedInputStream;
+
+namespace internal {
+void MapTestForceDeterministic();
+class EpsCopyByteStream;
+}  // namespace internal
+
+namespace io {
+
+// Defined in this file.
+class CodedInputStream;
+class CodedOutputStream;
+
+// Defined in other files.
+class ZeroCopyInputStream;   // zero_copy_stream.h
+class ZeroCopyOutputStream;  // zero_copy_stream.h
+
+// Class which reads and decodes binary data which is composed of varint-
+// encoded integers and fixed-width pieces.  Wraps a ZeroCopyInputStream.
+// Most users will not need to deal with CodedInputStream.
+//
+// Most methods of CodedInputStream that return a bool return false if an
+// underlying I/O error occurs or if the data is malformed.  Once such a
+// failure occurs, the CodedInputStream is broken and is no longer useful.
+// After a failure, callers also should assume writes to "out" args may have
+// occurred, though nothing useful can be determined from those writes.
+class PROTOBUF_EXPORT CodedInputStream {
+ public:
+  // Create a CodedInputStream that reads from the given ZeroCopyInputStream.
+  explicit CodedInputStream(ZeroCopyInputStream* input);
+
+  // Create a CodedInputStream that reads from the given flat array.  This is
+  // faster than using an ArrayInputStream.  PushLimit(size) is implied by
+  // this constructor.
+  explicit CodedInputStream(const uint8_t* buffer, int size);
+
+  // Destroy the CodedInputStream and position the underlying
+  // ZeroCopyInputStream at the first unread byte.  If an error occurred while
+  // reading (causing a method to return false), then the exact position of
+  // the input stream may be anywhere between the last value that was read
+  // successfully and the stream's byte limit.
+  ~CodedInputStream();
+
+  // Return true if this CodedInputStream reads from a flat array instead of
+  // a ZeroCopyInputStream.
+  inline bool IsFlat() const;
+
+  // Skips a number of bytes.  Returns false if an underlying read error
+  // occurs.
+  inline bool Skip(int count);
+
+  // Sets *data to point directly at the unread part of the CodedInputStream's
+  // underlying buffer, and *size to the size of that buffer, but does not
+  // advance the stream's current position.  This will always either produce
+  // a non-empty buffer or return false.  If the caller consumes any of
+  // this data, it should then call Skip() to skip over the consumed bytes.
+  // This may be useful for implementing external fast parsing routines for
+  // types of data not covered by the CodedInputStream interface.
+  bool GetDirectBufferPointer(const void** data, int* size);
+
+  // Like GetDirectBufferPointer, but this method is inlined, and does not
+  // attempt to Refresh() if the buffer is currently empty.
+  PROTOBUF_ALWAYS_INLINE
+  void GetDirectBufferPointerInline(const void** data, int* size);
+
+  // Read raw bytes, copying them into the given buffer.
+  bool ReadRaw(void* buffer, int size);
+
+  // Like ReadRaw, but reads into a string.
+  bool ReadString(std::string* buffer, int size);
+
+
+  // Read a 32-bit little-endian integer.
+  bool ReadLittleEndian32(uint32_t* value);
+  // Read a 64-bit little-endian integer.
+  bool ReadLittleEndian64(uint64_t* value);
+
+  // These methods read from an externally provided buffer. The caller is
+  // responsible for ensuring that the buffer has sufficient space.
+  // Read a 32-bit little-endian integer.
+  static const uint8_t* ReadLittleEndian32FromArray(const uint8_t* buffer,
+                                                    uint32_t* value);
+  // Read a 64-bit little-endian integer.
+  static const uint8_t* ReadLittleEndian64FromArray(const uint8_t* buffer,
+                                                    uint64_t* value);
+
+  // Read an unsigned integer with Varint encoding, truncating to 32 bits.
+  // Reading a 32-bit value is equivalent to reading a 64-bit one and casting
+  // it to uint32_t, but may be more efficient.
+  bool ReadVarint32(uint32_t* value);
+  // Read an unsigned integer with Varint encoding.
+  bool ReadVarint64(uint64_t* value);
+
+  // Reads a varint off the wire into an "int". This should be used for reading
+  // sizes off the wire (sizes of strings, submessages, bytes fields, etc).
+  //
+  // The value from the wire is interpreted as unsigned.  If its value exceeds
+  // the representable value of an integer on this platform, instead of
+  // truncating we return false. Truncating (as performed by ReadVarint32()
+  // above) is an acceptable approach for fields representing an integer, but
+  // when we are parsing a size from the wire, truncating the value would result
+  // in us misparsing the payload.
+  bool ReadVarintSizeAsInt(int* value);
+
+  // Read a tag.  This calls ReadVarint32() and returns the result, or returns
+  // zero (which is not a valid tag) if ReadVarint32() fails.  Also, ReadTag
+  // (but not ReadTagNoLastTag) updates the last tag value, which can be checked
+  // with LastTagWas().
+  //
+  // Always inline because this is only called in one place per parse loop
+  // but it is called for every iteration of said loop, so it should be fast.
+  // GCC doesn't want to inline this by default.
+  PROTOBUF_ALWAYS_INLINE uint32_t ReadTag() {
+    return last_tag_ = ReadTagNoLastTag();
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint32_t ReadTagNoLastTag();
+
+  // This usually a faster alternative to ReadTag() when cutoff is a manifest
+  // constant.  It does particularly well for cutoff >= 127.  The first part
+  // of the return value is the tag that was read, though it can also be 0 in
+  // the cases where ReadTag() would return 0.  If the second part is true
+  // then the tag is known to be in [0, cutoff].  If not, the tag either is
+  // above cutoff or is 0.  (There's intentional wiggle room when tag is 0,
+  // because that can arise in several ways, and for best performance we want
+  // to avoid an extra "is tag == 0?" check here.)
+  PROTOBUF_ALWAYS_INLINE
+  std::pair<uint32_t, bool> ReadTagWithCutoff(uint32_t cutoff) {
+    std::pair<uint32_t, bool> result = ReadTagWithCutoffNoLastTag(cutoff);
+    last_tag_ = result.first;
+    return result;
+  }
+
+  PROTOBUF_ALWAYS_INLINE
+  std::pair<uint32_t, bool> ReadTagWithCutoffNoLastTag(uint32_t cutoff);
+
+  // Usually returns true if calling ReadVarint32() now would produce the given
+  // value.  Will always return false if ReadVarint32() would not return the
+  // given value.  If ExpectTag() returns true, it also advances past
+  // the varint.  For best performance, use a compile-time constant as the
+  // parameter.
+  // Always inline because this collapses to a small number of instructions
+  // when given a constant parameter, but GCC doesn't want to inline by default.
+  PROTOBUF_ALWAYS_INLINE bool ExpectTag(uint32_t expected);
+
+  // Like above, except this reads from the specified buffer. The caller is
+  // responsible for ensuring that the buffer is large enough to read a varint
+  // of the expected size. For best performance, use a compile-time constant as
+  // the expected tag parameter.
+  //
+  // Returns a pointer beyond the expected tag if it was found, or NULL if it
+  // was not.
+  PROTOBUF_ALWAYS_INLINE
+  static const uint8_t* ExpectTagFromArray(const uint8_t* buffer,
+                                           uint32_t expected);
+
+  // Usually returns true if no more bytes can be read.  Always returns false
+  // if more bytes can be read.  If ExpectAtEnd() returns true, a subsequent
+  // call to LastTagWas() will act as if ReadTag() had been called and returned
+  // zero, and ConsumedEntireMessage() will return true.
+  bool ExpectAtEnd();
+
+  // If the last call to ReadTag() or ReadTagWithCutoff() returned the given
+  // value, returns true.  Otherwise, returns false.
+  // ReadTagNoLastTag/ReadTagWithCutoffNoLastTag do not preserve the last
+  // returned value.
+  //
+  // This is needed because parsers for some types of embedded messages
+  // (with field type TYPE_GROUP) don't actually know that they've reached the
+  // end of a message until they see an ENDGROUP tag, which was actually part
+  // of the enclosing message.  The enclosing message would like to check that
+  // tag to make sure it had the right number, so it calls LastTagWas() on
+  // return from the embedded parser to check.
+  bool LastTagWas(uint32_t expected);
+  void SetLastTag(uint32_t tag) { last_tag_ = tag; }
+
+  // When parsing message (but NOT a group), this method must be called
+  // immediately after MergeFromCodedStream() returns (if it returns true)
+  // to further verify that the message ended in a legitimate way.  For
+  // example, this verifies that parsing did not end on an end-group tag.
+  // It also checks for some cases where, due to optimizations,
+  // MergeFromCodedStream() can incorrectly return true.
+  bool ConsumedEntireMessage();
+  void SetConsumed() { legitimate_message_end_ = true; }
+
+  // Limits ----------------------------------------------------------
+  // Limits are used when parsing length-delimited embedded messages.
+  // After the message's length is read, PushLimit() is used to prevent
+  // the CodedInputStream from reading beyond that length.  Once the
+  // embedded message has been parsed, PopLimit() is called to undo the
+  // limit.
+
+  // Opaque type used with PushLimit() and PopLimit().  Do not modify
+  // values of this type yourself.  The only reason that this isn't a
+  // struct with private internals is for efficiency.
+  typedef int Limit;
+
+  // Places a limit on the number of bytes that the stream may read,
+  // starting from the current position.  Once the stream hits this limit,
+  // it will act like the end of the input has been reached until PopLimit()
+  // is called.
+  //
+  // As the names imply, the stream conceptually has a stack of limits.  The
+  // shortest limit on the stack is always enforced, even if it is not the
+  // top limit.
+  //
+  // The value returned by PushLimit() is opaque to the caller, and must
+  // be passed unchanged to the corresponding call to PopLimit().
+  Limit PushLimit(int byte_limit);
+
+  // Pops the last limit pushed by PushLimit().  The input must be the value
+  // returned by that call to PushLimit().
+  void PopLimit(Limit limit);
+
+  // Returns the number of bytes left until the nearest limit on the
+  // stack is hit, or -1 if no limits are in place.
+  int BytesUntilLimit() const;
+
+  // Returns current position relative to the beginning of the input stream.
+  int CurrentPosition() const;
+
+  // Total Bytes Limit -----------------------------------------------
+  // To prevent malicious users from sending excessively large messages
+  // and causing memory exhaustion, CodedInputStream imposes a hard limit on
+  // the total number of bytes it will read.
+
+  // Sets the maximum number of bytes that this CodedInputStream will read
+  // before refusing to continue.  To prevent servers from allocating enormous
+  // amounts of memory to hold parsed messages, the maximum message length
+  // should be limited to the shortest length that will not harm usability.
+  // The default limit is INT_MAX (~2GB) and apps should set shorter limits
+  // if possible. An error will always be printed to stderr if the limit is
+  // reached.
+  //
+  // Note: setting a limit less than the current read position is interpreted
+  // as a limit on the current position.
+  //
+  // This is unrelated to PushLimit()/PopLimit().
+  void SetTotalBytesLimit(int total_bytes_limit);
+
+  // The Total Bytes Limit minus the Current Position, or -1 if the total bytes
+  // limit is INT_MAX.
+  int BytesUntilTotalBytesLimit() const;
+
+  // Recursion Limit -------------------------------------------------
+  // To prevent corrupt or malicious messages from causing stack overflows,
+  // we must keep track of the depth of recursion when parsing embedded
+  // messages and groups.  CodedInputStream keeps track of this because it
+  // is the only object that is passed down the stack during parsing.
+
+  // Sets the maximum recursion depth.  The default is 100.
+  void SetRecursionLimit(int limit);
+  int RecursionBudget() { return recursion_budget_; }
+
+  static int GetDefaultRecursionLimit() { return default_recursion_limit_; }
+
+  // Increments the current recursion depth.  Returns true if the depth is
+  // under the limit, false if it has gone over.
+  bool IncrementRecursionDepth();
+
+  // Decrements the recursion depth if possible.
+  void DecrementRecursionDepth();
+
+  // Decrements the recursion depth blindly.  This is faster than
+  // DecrementRecursionDepth().  It should be used only if all previous
+  // increments to recursion depth were successful.
+  void UnsafeDecrementRecursionDepth();
+
+  // Shorthand for make_pair(PushLimit(byte_limit), --recursion_budget_).
+  // Using this can reduce code size and complexity in some cases.  The caller
+  // is expected to check that the second part of the result is non-negative (to
+  // bail out if the depth of recursion is too high) and, if all is well, to
+  // later pass the first part of the result to PopLimit() or similar.
+  std::pair<CodedInputStream::Limit, int> IncrementRecursionDepthAndPushLimit(
+      int byte_limit);
+
+  // Shorthand for PushLimit(ReadVarint32(&length) ? length : 0).
+  Limit ReadLengthAndPushLimit();
+
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  UnsafeDecrementRecursionDepth();
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  // Do not use unless the current recursion depth is greater than zero.
+  bool DecrementRecursionDepthAndPopLimit(Limit limit);
+
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  bool CheckEntireMessageConsumedAndPopLimit(Limit limit);
+
+  // Extension Registry ----------------------------------------------
+  // ADVANCED USAGE:  99.9% of people can ignore this section.
+  //
+  // By default, when parsing extensions, the parser looks for extension
+  // definitions in the pool which owns the outer message's Descriptor.
+  // However, you may call SetExtensionRegistry() to provide an alternative
+  // pool instead.  This makes it possible, for example, to parse a message
+  // using a generated class, but represent some extensions using
+  // DynamicMessage.
+
+  // Set the pool used to look up extensions.  Most users do not need to call
+  // this as the correct pool will be chosen automatically.
+  //
+  // WARNING:  It is very easy to misuse this.  Carefully read the requirements
+  //   below.  Do not use this unless you are sure you need it.  Almost no one
+  //   does.
+  //
+  // Let's say you are parsing a message into message object m, and you want
+  // to take advantage of SetExtensionRegistry().  You must follow these
+  // requirements:
+  //
+  // The given DescriptorPool must contain m->GetDescriptor().  It is not
+  // sufficient for it to simply contain a descriptor that has the same name
+  // and content -- it must be the *exact object*.  In other words:
+  //   assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) ==
+  //          m->GetDescriptor());
+  // There are two ways to satisfy this requirement:
+  // 1) Use m->GetDescriptor()->pool() as the pool.  This is generally useless
+  //    because this is the pool that would be used anyway if you didn't call
+  //    SetExtensionRegistry() at all.
+  // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an
+  //    "underlay".  Read the documentation for DescriptorPool for more
+  //    information about underlays.
+  //
+  // You must also provide a MessageFactory.  This factory will be used to
+  // construct Message objects representing extensions.  The factory's
+  // GetPrototype() MUST return non-NULL for any Descriptor which can be found
+  // through the provided pool.
+  //
+  // If the provided factory might return instances of protocol-compiler-
+  // generated (i.e. compiled-in) types, or if the outer message object m is
+  // a generated type, then the given factory MUST have this property:  If
+  // GetPrototype() is given a Descriptor which resides in
+  // DescriptorPool::generated_pool(), the factory MUST return the same
+  // prototype which MessageFactory::generated_factory() would return.  That
+  // is, given a descriptor for a generated type, the factory must return an
+  // instance of the generated class (NOT DynamicMessage).  However, when
+  // given a descriptor for a type that is NOT in generated_pool, the factory
+  // is free to return any implementation.
+  //
+  // The reason for this requirement is that generated sub-objects may be
+  // accessed via the standard (non-reflection) extension accessor methods,
+  // and these methods will down-cast the object to the generated class type.
+  // If the object is not actually of that type, the results would be undefined.
+  // On the other hand, if an extension is not compiled in, then there is no
+  // way the code could end up accessing it via the standard accessors -- the
+  // only way to access the extension is via reflection.  When using reflection,
+  // DynamicMessage and generated messages are indistinguishable, so it's fine
+  // if these objects are represented using DynamicMessage.
+  //
+  // Using DynamicMessageFactory on which you have called
+  // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the
+  // above requirement.
+  //
+  // If either pool or factory is NULL, both must be NULL.
+  //
+  // Note that this feature is ignored when parsing "lite" messages as they do
+  // not have descriptors.
+  void SetExtensionRegistry(const DescriptorPool* pool,
+                            MessageFactory* factory);
+
+  // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool
+  // has been provided.
+  const DescriptorPool* GetExtensionPool();
+
+  // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no
+  // factory has been provided.
+  MessageFactory* GetExtensionFactory();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream);
+
+  const uint8_t* buffer_;
+  const uint8_t* buffer_end_;  // pointer to the end of the buffer.
+  ZeroCopyInputStream* input_;
+  int total_bytes_read_;  // total bytes read from input_, including
+                          // the current buffer
+
+  // If total_bytes_read_ surpasses INT_MAX, we record the extra bytes here
+  // so that we can BackUp() on destruction.
+  int overflow_bytes_;
+
+  // LastTagWas() stuff.
+  uint32_t last_tag_;  // result of last ReadTag() or ReadTagWithCutoff().
+
+  // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly
+  // at EOF, or by ExpectAtEnd() when it returns true.  This happens when we
+  // reach the end of a message and attempt to read another tag.
+  bool legitimate_message_end_;
+
+  // See EnableAliasing().
+  bool aliasing_enabled_;
+
+  // Limits
+  Limit current_limit_;  // if position = -1, no limit is applied
+
+  // For simplicity, if the current buffer crosses a limit (either a normal
+  // limit created by PushLimit() or the total bytes limit), buffer_size_
+  // only tracks the number of bytes before that limit.  This field
+  // contains the number of bytes after it.  Note that this implies that if
+  // buffer_size_ == 0 and buffer_size_after_limit_ > 0, we know we've
+  // hit a limit.  However, if both are zero, it doesn't necessarily mean
+  // we aren't at a limit -- the buffer may have ended exactly at the limit.
+  int buffer_size_after_limit_;
+
+  // Maximum number of bytes to read, period.  This is unrelated to
+  // current_limit_.  Set using SetTotalBytesLimit().
+  int total_bytes_limit_;
+
+  // Current recursion budget, controlled by IncrementRecursionDepth() and
+  // similar.  Starts at recursion_limit_ and goes down: if this reaches
+  // -1 we are over budget.
+  int recursion_budget_;
+  // Recursion depth limit, set by SetRecursionLimit().
+  int recursion_limit_;
+
+  // See SetExtensionRegistry().
+  const DescriptorPool* extension_pool_;
+  MessageFactory* extension_factory_;
+
+  // Private member functions.
+
+  // Fallback when Skip() goes past the end of the current buffer.
+  bool SkipFallback(int count, int original_buffer_size);
+
+  // Advance the buffer by a given number of bytes.
+  void Advance(int amount);
+
+  // Back up input_ to the current buffer position.
+  void BackUpInputToCurrentPosition();
+
+  // Recomputes the value of buffer_size_after_limit_.  Must be called after
+  // current_limit_ or total_bytes_limit_ changes.
+  void RecomputeBufferLimits();
+
+  // Writes an error message saying that we hit total_bytes_limit_.
+  void PrintTotalBytesLimitError();
+
+  // Called when the buffer runs out to request more data.  Implies an
+  // Advance(BufferSize()).
+  bool Refresh();
+
+  // When parsing varints, we optimize for the common case of small values, and
+  // then optimize for the case when the varint fits within the current buffer
+  // piece. The Fallback method is used when we can't use the one-byte
+  // optimization. The Slow method is yet another fallback when the buffer is
+  // not large enough. Making the slow path out-of-line speeds up the common
+  // case by 10-15%. The slow path is fairly uncommon: it only triggers when a
+  // message crosses multiple buffers.  Note: ReadVarint32Fallback() and
+  // ReadVarint64Fallback() are called frequently and generally not inlined, so
+  // they have been optimized to avoid "out" parameters.  The former returns -1
+  // if it fails and the uint32_t it read otherwise.  The latter has a bool
+  // indicating success or failure as part of its return type.
+  int64_t ReadVarint32Fallback(uint32_t first_byte_or_zero);
+  int ReadVarintSizeAsIntFallback();
+  std::pair<uint64_t, bool> ReadVarint64Fallback();
+  bool ReadVarint32Slow(uint32_t* value);
+  bool ReadVarint64Slow(uint64_t* value);
+  int ReadVarintSizeAsIntSlow();
+  bool ReadLittleEndian32Fallback(uint32_t* value);
+  bool ReadLittleEndian64Fallback(uint64_t* value);
+
+  // Fallback/slow methods for reading tags. These do not update last_tag_,
+  // but will set legitimate_message_end_ if we are at the end of the input
+  // stream.
+  uint32_t ReadTagFallback(uint32_t first_byte_or_zero);
+  uint32_t ReadTagSlow();
+  bool ReadStringFallback(std::string* buffer, int size);
+
+  // Return the size of the buffer.
+  int BufferSize() const;
+
+  static const int kDefaultTotalBytesLimit = INT_MAX;
+
+  static int default_recursion_limit_;  // 100 by default.
+
+  friend class google::protobuf::ZeroCopyCodedInputStream;
+  friend class google::protobuf::internal::EpsCopyByteStream;
+};
+
+// EpsCopyOutputStream wraps a ZeroCopyOutputStream and exposes a new stream,
+// which has the property you can write kSlopBytes (16 bytes) from the current
+// position without bounds checks. The cursor into the stream is managed by
+// the user of the class and is an explicit parameter in the methods. Careful
+// use of this class, ie. keep ptr a local variable, eliminates the need to
+// for the compiler to sync the ptr value between register and memory.
+class PROTOBUF_EXPORT EpsCopyOutputStream {
+ public:
+  enum { kSlopBytes = 16 };
+
+  // Initialize from a stream.
+  EpsCopyOutputStream(ZeroCopyOutputStream* stream, bool deterministic,
+                      uint8_t** pp)
+      : end_(buffer_),
+        stream_(stream),
+        is_serialization_deterministic_(deterministic) {
+    *pp = buffer_;
+  }
+
+  // Only for array serialization. No overflow protection, end_ will be the
+  // pointed to the end of the array. When using this the total size is already
+  // known, so no need to maintain the slop region.
+  EpsCopyOutputStream(void* data, int size, bool deterministic)
+      : end_(static_cast<uint8_t*>(data) + size),
+        buffer_end_(nullptr),
+        stream_(nullptr),
+        is_serialization_deterministic_(deterministic) {}
+
+  // Initialize from stream but with the first buffer already given (eager).
+  EpsCopyOutputStream(void* data, int size, ZeroCopyOutputStream* stream,
+                      bool deterministic, uint8_t** pp)
+      : stream_(stream), is_serialization_deterministic_(deterministic) {
+    *pp = SetInitialBuffer(data, size);
+  }
+
+  // Flush everything that's written into the underlying ZeroCopyOutputStream
+  // and trims the underlying stream to the location of ptr.
+  uint8_t* Trim(uint8_t* ptr);
+
+  // After this it's guaranteed you can safely write kSlopBytes to ptr. This
+  // will never fail! The underlying stream can produce an error. Use HadError
+  // to check for errors.
+  PROTOBUF_NODISCARD uint8_t* EnsureSpace(uint8_t* ptr) {
+    if (PROTOBUF_PREDICT_FALSE(ptr >= end_)) {
+      return EnsureSpaceFallback(ptr);
+    }
+    return ptr;
+  }
+
+  uint8_t* WriteRaw(const void* data, size_t size, uint8_t* ptr) {
+    if (PROTOBUF_PREDICT_FALSE(end_ - ptr < static_cast<int>(size))) {
+      return WriteRawFallback(data, size, ptr);
+    }
+    std::memcpy(ptr, data, size);
+    return ptr + size;
+  }
+  // Writes the buffer specified by data, size to the stream. Possibly by
+  // aliasing the buffer (ie. not copying the data). The caller is responsible
+  // to make sure the buffer is alive for the duration of the
+  // ZeroCopyOutputStream.
+#ifndef NDEBUG
+  PROTOBUF_NOINLINE
+#endif
+  uint8_t* WriteRawMaybeAliased(const void* data, int size, uint8_t* ptr) {
+    if (aliasing_enabled_) {
+      return WriteAliasedRaw(data, size, ptr);
+    } else {
+      return WriteRaw(data, size, ptr);
+    }
+  }
+
+
+#ifndef NDEBUG
+  PROTOBUF_NOINLINE
+#endif
+  uint8_t* WriteStringMaybeAliased(uint32_t num, const std::string& s,
+                                   uint8_t* ptr) {
+    std::ptrdiff_t size = s.size();
+    if (PROTOBUF_PREDICT_FALSE(
+            size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
+      return WriteStringMaybeAliasedOutline(num, s, ptr);
+    }
+    ptr = UnsafeVarint((num << 3) | 2, ptr);
+    *ptr++ = static_cast<uint8_t>(size);
+    std::memcpy(ptr, s.data(), size);
+    return ptr + size;
+  }
+  uint8_t* WriteBytesMaybeAliased(uint32_t num, const std::string& s,
+                                  uint8_t* ptr) {
+    return WriteStringMaybeAliased(num, s, ptr);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteString(uint32_t num, const T& s,
+                                              uint8_t* ptr) {
+    std::ptrdiff_t size = s.size();
+    if (PROTOBUF_PREDICT_FALSE(
+            size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
+      return WriteStringOutline(num, s, ptr);
+    }
+    ptr = UnsafeVarint((num << 3) | 2, ptr);
+    *ptr++ = static_cast<uint8_t>(size);
+    std::memcpy(ptr, s.data(), size);
+    return ptr + size;
+  }
+  template <typename T>
+#ifndef NDEBUG
+  PROTOBUF_NOINLINE
+#endif
+  uint8_t* WriteBytes(uint32_t num, const T& s, uint8_t* ptr) {
+    return WriteString(num, s, ptr);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteInt32Packed(int num, const T& r,
+                                                   int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteUInt32Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode32);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteSInt32Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, ZigZagEncode32);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteInt64Packed(int num, const T& r,
+                                                   int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteUInt64Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteSInt64Packed(int num, const T& r,
+                                                    int size, uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, ZigZagEncode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteEnumPacked(int num, const T& r, int size,
+                                                  uint8_t* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteFixedPacked(int num, const T& r,
+                                                   uint8_t* ptr) {
+    ptr = EnsureSpace(ptr);
+    constexpr auto element_size = sizeof(typename T::value_type);
+    auto size = r.size() * element_size;
+    ptr = WriteLengthDelim(num, size, ptr);
+    return WriteRawLittleEndian<element_size>(r.data(), static_cast<int>(size),
+                                              ptr);
+  }
+
+  // Returns true if there was an underlying I/O error since this object was
+  // created.
+  bool HadError() const { return had_error_; }
+
+  // Instructs the EpsCopyOutputStream to allow the underlying
+  // ZeroCopyOutputStream to hold pointers to the original structure instead of
+  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
+  // underlying stream does not support aliasing, then enabling it has no
+  // affect.  For now, this only affects the behavior of
+  // WriteRawMaybeAliased().
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  void EnableAliasing(bool enabled);
+
+  // See documentation on CodedOutputStream::SetSerializationDeterministic.
+  void SetSerializationDeterministic(bool value) {
+    is_serialization_deterministic_ = value;
+  }
+
+  // See documentation on CodedOutputStream::IsSerializationDeterministic.
+  bool IsSerializationDeterministic() const {
+    return is_serialization_deterministic_;
+  }
+
+  // The number of bytes written to the stream at position ptr, relative to the
+  // stream's overall position.
+  int64_t ByteCount(uint8_t* ptr) const;
+
+
+ private:
+  uint8_t* end_;
+  uint8_t* buffer_end_ = buffer_;
+  uint8_t buffer_[2 * kSlopBytes];
+  ZeroCopyOutputStream* stream_;
+  bool had_error_ = false;
+  bool aliasing_enabled_ = false;  // See EnableAliasing().
+  bool is_serialization_deterministic_;
+  bool skip_check_consistency = false;
+
+  uint8_t* EnsureSpaceFallback(uint8_t* ptr);
+  inline uint8_t* Next();
+  int Flush(uint8_t* ptr);
+  std::ptrdiff_t GetSize(uint8_t* ptr) const {
+    GOOGLE_DCHECK(ptr <= end_ + kSlopBytes);  // NOLINT
+    return end_ + kSlopBytes - ptr;
+  }
+
+  uint8_t* Error() {
+    had_error_ = true;
+    // We use the patch buffer to always guarantee space to write to.
+    end_ = buffer_ + kSlopBytes;
+    return buffer_;
+  }
+
+  static constexpr int TagSize(uint32_t tag) {
+    return (tag < (1 << 7))    ? 1
+           : (tag < (1 << 14)) ? 2
+           : (tag < (1 << 21)) ? 3
+           : (tag < (1 << 28)) ? 4
+                               : 5;
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteTag(uint32_t num, uint32_t wt,
+                                           uint8_t* ptr) {
+    GOOGLE_DCHECK(ptr < end_);  // NOLINT
+    return UnsafeVarint((num << 3) | wt, ptr);
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteLengthDelim(int num, uint32_t size,
+                                                   uint8_t* ptr) {
+    ptr = WriteTag(num, 2, ptr);
+    return UnsafeWriteSize(size, ptr);
+  }
+
+  uint8_t* WriteRawFallback(const void* data, int size, uint8_t* ptr);
+
+  uint8_t* WriteAliasedRaw(const void* data, int size, uint8_t* ptr);
+
+  uint8_t* WriteStringMaybeAliasedOutline(uint32_t num, const std::string& s,
+                                          uint8_t* ptr);
+  uint8_t* WriteStringOutline(uint32_t num, const std::string& s, uint8_t* ptr);
+
+  template <typename T, typename E>
+  PROTOBUF_ALWAYS_INLINE uint8_t* WriteVarintPacked(int num, const T& r,
+                                                    int size, uint8_t* ptr,
+                                                    const E& encode) {
+    ptr = EnsureSpace(ptr);
+    ptr = WriteLengthDelim(num, size, ptr);
+    auto it = r.data();
+    auto end = it + r.size();
+    do {
+      ptr = EnsureSpace(ptr);
+      ptr = UnsafeVarint(encode(*it++), ptr);
+    } while (it < end);
+    return ptr;
+  }
+
+  static uint32_t Encode32(uint32_t v) { return v; }
+  static uint64_t Encode64(uint64_t v) { return v; }
+  static uint32_t ZigZagEncode32(int32_t v) {
+    return (static_cast<uint32_t>(v) << 1) ^ static_cast<uint32_t>(v >> 31);
+  }
+  static uint64_t ZigZagEncode64(int64_t v) {
+    return (static_cast<uint64_t>(v) << 1) ^ static_cast<uint64_t>(v >> 63);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static uint8_t* UnsafeVarint(T value, uint8_t* ptr) {
+    static_assert(std::is_unsigned<T>::value,
+                  "Varint serialization must be unsigned");
+    ptr[0] = static_cast<uint8_t>(value);
+    if (value < 0x80) {
+      return ptr + 1;
+    }
+    // Turn on continuation bit in the byte we just wrote.
+    ptr[0] |= static_cast<uint8_t>(0x80);
+    value >>= 7;
+    ptr[1] = static_cast<uint8_t>(value);
+    if (value < 0x80) {
+      return ptr + 2;
+    }
+    ptr += 2;
+    do {
+      // Turn on continuation bit in the byte we just wrote.
+      ptr[-1] |= static_cast<uint8_t>(0x80);
+      value >>= 7;
+      *ptr = static_cast<uint8_t>(value);
+      ++ptr;
+    } while (value >= 0x80);
+    return ptr;
+  }
+
+  PROTOBUF_ALWAYS_INLINE static uint8_t* UnsafeWriteSize(uint32_t value,
+                                                         uint8_t* ptr) {
+    while (PROTOBUF_PREDICT_FALSE(value >= 0x80)) {
+      *ptr = static_cast<uint8_t>(value | 0x80);
+      value >>= 7;
+      ++ptr;
+    }
+    *ptr++ = static_cast<uint8_t>(value);
+    return ptr;
+  }
+
+  template <int S>
+  uint8_t* WriteRawLittleEndian(const void* data, int size, uint8_t* ptr);
+#if !defined(PROTOBUF_LITTLE_ENDIAN) || \
+    defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  uint8_t* WriteRawLittleEndian32(const void* data, int size, uint8_t* ptr);
+  uint8_t* WriteRawLittleEndian64(const void* data, int size, uint8_t* ptr);
+#endif
+
+  // These methods are for CodedOutputStream. Ideally they should be private
+  // but to match current behavior of CodedOutputStream as close as possible
+  // we allow it some functionality.
+ public:
+  uint8_t* SetInitialBuffer(void* data, int size) {
+    auto ptr = static_cast<uint8_t*>(data);
+    if (size > kSlopBytes) {
+      end_ = ptr + size - kSlopBytes;
+      buffer_end_ = nullptr;
+      return ptr;
+    } else {
+      end_ = buffer_ + size;
+      buffer_end_ = ptr;
+      return buffer_;
+    }
+  }
+
+ private:
+  // Needed by CodedOutputStream HadError. HadError needs to flush the patch
+  // buffers to ensure there is no error as of yet.
+  uint8_t* FlushAndResetBuffer(uint8_t*);
+
+  // The following functions mimic the old CodedOutputStream behavior as close
+  // as possible. They flush the current state to the stream, behave as
+  // the old CodedOutputStream and then return to normal operation.
+  bool Skip(int count, uint8_t** pp);
+  bool GetDirectBufferPointer(void** data, int* size, uint8_t** pp);
+  uint8_t* GetDirectBufferForNBytesAndAdvance(int size, uint8_t** pp);
+
+  friend class CodedOutputStream;
+};
+
+template <>
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<1>(const void* data,
+                                                             int size,
+                                                             uint8_t* ptr) {
+  return WriteRaw(data, size, ptr);
+}
+template <>
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<4>(const void* data,
+                                                             int size,
+                                                             uint8_t* ptr) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  return WriteRaw(data, size, ptr);
+#else
+  return WriteRawLittleEndian32(data, size, ptr);
+#endif
+}
+template <>
+inline uint8_t* EpsCopyOutputStream::WriteRawLittleEndian<8>(const void* data,
+                                                             int size,
+                                                             uint8_t* ptr) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  return WriteRaw(data, size, ptr);
+#else
+  return WriteRawLittleEndian64(data, size, ptr);
+#endif
+}
+
+// Class which encodes and writes binary data which is composed of varint-
+// encoded integers and fixed-width pieces.  Wraps a ZeroCopyOutputStream.
+// Most users will not need to deal with CodedOutputStream.
+//
+// Most methods of CodedOutputStream which return a bool return false if an
+// underlying I/O error occurs.  Once such a failure occurs, the
+// CodedOutputStream is broken and is no longer useful. The Write* methods do
+// not return the stream status, but will invalidate the stream if an error
+// occurs. The client can probe HadError() to determine the status.
+//
+// Note that every method of CodedOutputStream which writes some data has
+// a corresponding static "ToArray" version. These versions write directly
+// to the provided buffer, returning a pointer past the last written byte.
+// They require that the buffer has sufficient capacity for the encoded data.
+// This allows an optimization where we check if an output stream has enough
+// space for an entire message before we start writing and, if there is, we
+// call only the ToArray methods to avoid doing bound checks for each
+// individual value.
+// i.e., in the example above:
+//
+//   CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
+//   int magic_number = 1234;
+//   char text[] = "Hello world!";
+//
+//   int coded_size = sizeof(magic_number) +
+//                    CodedOutputStream::VarintSize32(strlen(text)) +
+//                    strlen(text);
+//
+//   uint8_t* buffer =
+//       coded_output->GetDirectBufferForNBytesAndAdvance(coded_size);
+//   if (buffer != nullptr) {
+//     // The output stream has enough space in the buffer: write directly to
+//     // the array.
+//     buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number,
+//                                                            buffer);
+//     buffer = CodedOutputStream::WriteVarint32ToArray(strlen(text), buffer);
+//     buffer = CodedOutputStream::WriteRawToArray(text, strlen(text), buffer);
+//   } else {
+//     // Make bound-checked writes, which will ask the underlying stream for
+//     // more space as needed.
+//     coded_output->WriteLittleEndian32(magic_number);
+//     coded_output->WriteVarint32(strlen(text));
+//     coded_output->WriteRaw(text, strlen(text));
+//   }
+//
+//   delete coded_output;
+class PROTOBUF_EXPORT CodedOutputStream {
+ public:
+  // Creates a CodedOutputStream that writes to the given `stream`.
+  // The provided stream must publicly derive from `ZeroCopyOutputStream`.
+  template <class Stream, class = typename std::enable_if<std::is_base_of<
+                              ZeroCopyOutputStream, Stream>::value>::type>
+  explicit CodedOutputStream(Stream* stream);
+
+  // Creates a CodedOutputStream that writes to the given `stream`, and does
+  // an 'eager initialization' of the internal state if `eager_init` is true.
+  // The provided stream must publicly derive from `ZeroCopyOutputStream`.
+  template <class Stream, class = typename std::enable_if<std::is_base_of<
+                              ZeroCopyOutputStream, Stream>::value>::type>
+  CodedOutputStream(Stream* stream, bool eager_init);
+
+  // Destroy the CodedOutputStream and position the underlying
+  // ZeroCopyOutputStream immediately after the last byte written.
+  ~CodedOutputStream();
+
+  // Returns true if there was an underlying I/O error since this object was
+  // created. On should call Trim before this function in order to catch all
+  // errors.
+  bool HadError() {
+    cur_ = impl_.FlushAndResetBuffer(cur_);
+    GOOGLE_DCHECK(cur_);
+    return impl_.HadError();
+  }
+
+  // Trims any unused space in the underlying buffer so that its size matches
+  // the number of bytes written by this stream. The underlying buffer will
+  // automatically be trimmed when this stream is destroyed; this call is only
+  // necessary if the underlying buffer is accessed *before* the stream is
+  // destroyed.
+  void Trim() { cur_ = impl_.Trim(cur_); }
+
+  // Skips a number of bytes, leaving the bytes unmodified in the underlying
+  // buffer.  Returns false if an underlying write error occurs.  This is
+  // mainly useful with GetDirectBufferPointer().
+  // Note of caution, the skipped bytes may contain uninitialized data. The
+  // caller must make sure that the skipped bytes are properly initialized,
+  // otherwise you might leak bytes from your heap.
+  bool Skip(int count) { return impl_.Skip(count, &cur_); }
+
+  // Sets *data to point directly at the unwritten part of the
+  // CodedOutputStream's underlying buffer, and *size to the size of that
+  // buffer, but does not advance the stream's current position.  This will
+  // always either produce a non-empty buffer or return false.  If the caller
+  // writes any data to this buffer, it should then call Skip() to skip over
+  // the consumed bytes.  This may be useful for implementing external fast
+  // serialization routines for types of data not covered by the
+  // CodedOutputStream interface.
+  bool GetDirectBufferPointer(void** data, int* size) {
+    return impl_.GetDirectBufferPointer(data, size, &cur_);
+  }
+
+  // If there are at least "size" bytes available in the current buffer,
+  // returns a pointer directly into the buffer and advances over these bytes.
+  // The caller may then write directly into this buffer (e.g. using the
+  // *ToArray static methods) rather than go through CodedOutputStream.  If
+  // there are not enough bytes available, returns NULL.  The return pointer is
+  // invalidated as soon as any other non-const method of CodedOutputStream
+  // is called.
+  inline uint8_t* GetDirectBufferForNBytesAndAdvance(int size) {
+    return impl_.GetDirectBufferForNBytesAndAdvance(size, &cur_);
+  }
+
+  // Write raw bytes, copying them from the given buffer.
+  void WriteRaw(const void* buffer, int size) {
+    cur_ = impl_.WriteRaw(buffer, size, cur_);
+  }
+  // Like WriteRaw()  but will try to write aliased data if aliasing is
+  // turned on.
+  void WriteRawMaybeAliased(const void* data, int size);
+  // Like WriteRaw()  but writing directly to the target array.
+  // This is _not_ inlined, as the compiler often optimizes memcpy into inline
+  // copy loops. Since this gets called by every field with string or bytes
+  // type, inlining may lead to a significant amount of code bloat, with only a
+  // minor performance gain.
+  static uint8_t* WriteRawToArray(const void* buffer, int size,
+                                  uint8_t* target);
+
+  // Equivalent to WriteRaw(str.data(), str.size()).
+  void WriteString(const std::string& str);
+  // Like WriteString()  but writing directly to the target array.
+  static uint8_t* WriteStringToArray(const std::string& str, uint8_t* target);
+  // Write the varint-encoded size of str followed by str.
+  static uint8_t* WriteStringWithSizeToArray(const std::string& str,
+                                             uint8_t* target);
+
+
+  // Write a 32-bit little-endian integer.
+  void WriteLittleEndian32(uint32_t value) {
+    cur_ = impl_.EnsureSpace(cur_);
+    SetCur(WriteLittleEndian32ToArray(value, Cur()));
+  }
+  // Like WriteLittleEndian32()  but writing directly to the target array.
+  static uint8_t* WriteLittleEndian32ToArray(uint32_t value, uint8_t* target);
+  // Write a 64-bit little-endian integer.
+  void WriteLittleEndian64(uint64_t value) {
+    cur_ = impl_.EnsureSpace(cur_);
+    SetCur(WriteLittleEndian64ToArray(value, Cur()));
+  }
+  // Like WriteLittleEndian64()  but writing directly to the target array.
+  static uint8_t* WriteLittleEndian64ToArray(uint64_t value, uint8_t* target);
+
+  // Write an unsigned integer with Varint encoding.  Writing a 32-bit value
+  // is equivalent to casting it to uint64_t and writing it as a 64-bit value,
+  // but may be more efficient.
+  void WriteVarint32(uint32_t value);
+  // Like WriteVarint32()  but writing directly to the target array.
+  static uint8_t* WriteVarint32ToArray(uint32_t value, uint8_t* target);
+  // Like WriteVarint32()  but writing directly to the target array, and with
+  // the less common-case paths being out of line rather than inlined.
+  static uint8_t* WriteVarint32ToArrayOutOfLine(uint32_t value,
+                                                uint8_t* target);
+  // Write an unsigned integer with Varint encoding.
+  void WriteVarint64(uint64_t value);
+  // Like WriteVarint64()  but writing directly to the target array.
+  static uint8_t* WriteVarint64ToArray(uint64_t value, uint8_t* target);
+
+  // Equivalent to WriteVarint32() except when the value is negative,
+  // in which case it must be sign-extended to a full 10 bytes.
+  void WriteVarint32SignExtended(int32_t value);
+  // Like WriteVarint32SignExtended()  but writing directly to the target array.
+  static uint8_t* WriteVarint32SignExtendedToArray(int32_t value,
+                                                   uint8_t* target);
+
+  // This is identical to WriteVarint32(), but optimized for writing tags.
+  // In particular, if the input is a compile-time constant, this method
+  // compiles down to a couple instructions.
+  // Always inline because otherwise the aforementioned optimization can't work,
+  // but GCC by default doesn't want to inline this.
+  void WriteTag(uint32_t value);
+  // Like WriteTag()  but writing directly to the target array.
+  PROTOBUF_ALWAYS_INLINE
+  static uint8_t* WriteTagToArray(uint32_t value, uint8_t* target);
+
+  // Returns the number of bytes needed to encode the given value as a varint.
+  static size_t VarintSize32(uint32_t value);
+  // Returns the number of bytes needed to encode the given value as a varint.
+  static size_t VarintSize64(uint64_t value);
+
+  // If negative, 10 bytes.  Otherwise, same as VarintSize32().
+  static size_t VarintSize32SignExtended(int32_t value);
+
+  // Same as above, plus one.  The additional one comes at no compute cost.
+  static size_t VarintSize32PlusOne(uint32_t value);
+  static size_t VarintSize64PlusOne(uint64_t value);
+  static size_t VarintSize32SignExtendedPlusOne(int32_t value);
+
+  // Compile-time equivalent of VarintSize32().
+  template <uint32_t Value>
+  struct StaticVarintSize32 {
+    static const size_t value = (Value < (1 << 7))    ? 1
+                                : (Value < (1 << 14)) ? 2
+                                : (Value < (1 << 21)) ? 3
+                                : (Value < (1 << 28)) ? 4
+                                                      : 5;
+  };
+
+  // Returns the total number of bytes written since this object was created.
+  int ByteCount() const {
+    return static_cast<int>(impl_.ByteCount(cur_) - start_count_);
+  }
+
+  // Instructs the CodedOutputStream to allow the underlying
+  // ZeroCopyOutputStream to hold pointers to the original structure instead of
+  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
+  // underlying stream does not support aliasing, then enabling it has no
+  // affect.  For now, this only affects the behavior of
+  // WriteRawMaybeAliased().
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  void EnableAliasing(bool enabled) { impl_.EnableAliasing(enabled); }
+
+  // Indicate to the serializer whether the user wants deterministic
+  // serialization. The default when this is not called comes from the global
+  // default, controlled by SetDefaultSerializationDeterministic.
+  //
+  // What deterministic serialization means is entirely up to the driver of the
+  // serialization process (i.e. the caller of methods like WriteVarint32). In
+  // the case of serializing a proto buffer message using one of the methods of
+  // MessageLite, this means that for a given binary equal messages will always
+  // be serialized to the same bytes. This implies:
+  //
+  //   * Repeated serialization of a message will return the same bytes.
+  //
+  //   * Different processes running the same binary (including on different
+  //     machines) will serialize equal messages to the same bytes.
+  //
+  // Note that this is *not* canonical across languages. It is also unstable
+  // across different builds with intervening message definition changes, due to
+  // unknown fields. Users who need canonical serialization (e.g. persistent
+  // storage in a canonical form, fingerprinting) should define their own
+  // canonicalization specification and implement the serializer using
+  // reflection APIs rather than relying on this API.
+  void SetSerializationDeterministic(bool value) {
+    impl_.SetSerializationDeterministic(value);
+  }
+
+  // Return whether the user wants deterministic serialization. See above.
+  bool IsSerializationDeterministic() const {
+    return impl_.IsSerializationDeterministic();
+  }
+
+  static bool IsDefaultSerializationDeterministic() {
+    return default_serialization_deterministic_.load(
+               std::memory_order_relaxed) != 0;
+  }
+
+  template <typename Func>
+  void Serialize(const Func& func);
+
+  uint8_t* Cur() const { return cur_; }
+  void SetCur(uint8_t* ptr) { cur_ = ptr; }
+  EpsCopyOutputStream* EpsCopy() { return &impl_; }
+
+ private:
+  template <class Stream>
+  void InitEagerly(Stream* stream);
+
+  EpsCopyOutputStream impl_;
+  uint8_t* cur_;
+  int64_t start_count_;
+  static std::atomic<bool> default_serialization_deterministic_;
+
+  // See above.  Other projects may use "friend" to allow them to call this.
+  // After SetDefaultSerializationDeterministic() completes, all protocol
+  // buffer serializations will be deterministic by default.  Thread safe.
+  // However, the meaning of "after" is subtle here: to be safe, each thread
+  // that wants deterministic serialization by default needs to call
+  // SetDefaultSerializationDeterministic() or ensure on its own that another
+  // thread has done so.
+  friend void internal::MapTestForceDeterministic();
+  static void SetDefaultSerializationDeterministic() {
+    default_serialization_deterministic_.store(true, std::memory_order_relaxed);
+  }
+  // REQUIRES: value >= 0x80, and that (value & 7f) has been written to *target.
+  static uint8_t* WriteVarint32ToArrayOutOfLineHelper(uint32_t value,
+                                                      uint8_t* target);
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
+};
+
+// inline methods ====================================================
+// The vast majority of varints are only one byte.  These inline
+// methods optimize for that case.
+
+inline bool CodedInputStream::ReadVarint32(uint32_t* value) {
+  uint32_t v = 0;
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
+  }
+  int64_t result = ReadVarint32Fallback(v);
+  *value = static_cast<uint32_t>(result);
+  return result >= 0;
+}
+
+inline bool CodedInputStream::ReadVarint64(uint64_t* value) {
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) {
+    *value = *buffer_;
+    Advance(1);
+    return true;
+  }
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  *value = p.first;
+  return p.second;
+}
+
+inline bool CodedInputStream::ReadVarintSizeAsInt(int* value) {
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    int v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
+  }
+  *value = ReadVarintSizeAsIntFallback();
+  return *value >= 0;
+}
+
+// static
+inline const uint8_t* CodedInputStream::ReadLittleEndian32FromArray(
+    const uint8_t* buffer, uint32_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(value, buffer, sizeof(*value));
+  return buffer + sizeof(*value);
+#else
+  *value = (static_cast<uint32_t>(buffer[0])) |
+           (static_cast<uint32_t>(buffer[1]) << 8) |
+           (static_cast<uint32_t>(buffer[2]) << 16) |
+           (static_cast<uint32_t>(buffer[3]) << 24);
+  return buffer + sizeof(*value);
+#endif
+}
+// static
+inline const uint8_t* CodedInputStream::ReadLittleEndian64FromArray(
+    const uint8_t* buffer, uint64_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(value, buffer, sizeof(*value));
+  return buffer + sizeof(*value);
+#else
+  uint32_t part0 = (static_cast<uint32_t>(buffer[0])) |
+                   (static_cast<uint32_t>(buffer[1]) << 8) |
+                   (static_cast<uint32_t>(buffer[2]) << 16) |
+                   (static_cast<uint32_t>(buffer[3]) << 24);
+  uint32_t part1 = (static_cast<uint32_t>(buffer[4])) |
+                   (static_cast<uint32_t>(buffer[5]) << 8) |
+                   (static_cast<uint32_t>(buffer[6]) << 16) |
+                   (static_cast<uint32_t>(buffer[7]) << 24);
+  *value = static_cast<uint64_t>(part0) | (static_cast<uint64_t>(part1) << 32);
+  return buffer + sizeof(*value);
+#endif
+}
+
+inline bool CodedInputStream::ReadLittleEndian32(uint32_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  if (PROTOBUF_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
+    buffer_ = ReadLittleEndian32FromArray(buffer_, value);
+    return true;
+  } else {
+    return ReadLittleEndian32Fallback(value);
+  }
+#else
+  return ReadLittleEndian32Fallback(value);
+#endif
+}
+
+inline bool CodedInputStream::ReadLittleEndian64(uint64_t* value) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  if (PROTOBUF_PREDICT_TRUE(BufferSize() >= static_cast<int>(sizeof(*value)))) {
+    buffer_ = ReadLittleEndian64FromArray(buffer_, value);
+    return true;
+  } else {
+    return ReadLittleEndian64Fallback(value);
+  }
+#else
+  return ReadLittleEndian64Fallback(value);
+#endif
+}
+
+inline uint32_t CodedInputStream::ReadTagNoLastTag() {
+  uint32_t v = 0;
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      Advance(1);
+      return v;
+    }
+  }
+  v = ReadTagFallback(v);
+  return v;
+}
+
+inline std::pair<uint32_t, bool> CodedInputStream::ReadTagWithCutoffNoLastTag(
+    uint32_t cutoff) {
+  // In performance-sensitive code we can expect cutoff to be a compile-time
+  // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
+  // compile time.
+  uint32_t first_byte_or_zero = 0;
+  if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    // Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
+    // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
+    // is large enough then is it better to check for the two-byte case first?
+    first_byte_or_zero = buffer_[0];
+    if (static_cast<int8_t>(buffer_[0]) > 0) {
+      const uint32_t kMax1ByteVarint = 0x7f;
+      uint32_t tag = buffer_[0];
+      Advance(1);
+      return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
+    }
+    // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
+    // and tag is two bytes.  The latter is tested by bitwise-and-not of the
+    // first byte and the second byte.
+    if (cutoff >= 0x80 && PROTOBUF_PREDICT_TRUE(buffer_ + 1 < buffer_end_) &&
+        PROTOBUF_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) {
+      const uint32_t kMax2ByteVarint = (0x7f << 7) + 0x7f;
+      uint32_t tag = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
+      Advance(2);
+      // It might make sense to test for tag == 0 now, but it is so rare that
+      // that we don't bother.  A varint-encoded 0 should be one byte unless
+      // the encoder lost its mind.  The second part of the return value of
+      // this function is allowed to be either true or false if the tag is 0,
+      // so we don't have to check for tag == 0.  We may need to check whether
+      // it exceeds cutoff.
+      bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
+      return std::make_pair(tag, at_or_below_cutoff);
+    }
+  }
+  // Slow path
+  const uint32_t tag = ReadTagFallback(first_byte_or_zero);
+  return std::make_pair(tag, static_cast<uint32_t>(tag - 1) < cutoff);
+}
+
+inline bool CodedInputStream::LastTagWas(uint32_t expected) {
+  return last_tag_ == expected;
+}
+
+inline bool CodedInputStream::ConsumedEntireMessage() {
+  return legitimate_message_end_;
+}
+
+inline bool CodedInputStream::ExpectTag(uint32_t expected) {
+  if (expected < (1 << 7)) {
+    if (PROTOBUF_PREDICT_TRUE(buffer_ < buffer_end_) &&
+        buffer_[0] == expected) {
+      Advance(1);
+      return true;
+    } else {
+      return false;
+    }
+  } else if (expected < (1 << 14)) {
+    if (PROTOBUF_PREDICT_TRUE(BufferSize() >= 2) &&
+        buffer_[0] == static_cast<uint8_t>(expected | 0x80) &&
+        buffer_[1] == static_cast<uint8_t>(expected >> 7)) {
+      Advance(2);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    // Don't bother optimizing for larger values.
+    return false;
+  }
+}
+
+inline const uint8_t* CodedInputStream::ExpectTagFromArray(
+    const uint8_t* buffer, uint32_t expected) {
+  if (expected < (1 << 7)) {
+    if (buffer[0] == expected) {
+      return buffer + 1;
+    }
+  } else if (expected < (1 << 14)) {
+    if (buffer[0] == static_cast<uint8_t>(expected | 0x80) &&
+        buffer[1] == static_cast<uint8_t>(expected >> 7)) {
+      return buffer + 2;
+    }
+  }
+  return nullptr;
+}
+
+inline void CodedInputStream::GetDirectBufferPointerInline(const void** data,
+                                                           int* size) {
+  *data = buffer_;
+  *size = static_cast<int>(buffer_end_ - buffer_);
+}
+
+inline bool CodedInputStream::ExpectAtEnd() {
+  // If we are at a limit we know no more bytes can be read.  Otherwise, it's
+  // hard to say without calling Refresh(), and we'd rather not do that.
+
+  if (buffer_ == buffer_end_ && ((buffer_size_after_limit_ != 0) ||
+                                 (total_bytes_read_ == current_limit_))) {
+    last_tag_ = 0;                   // Pretend we called ReadTag()...
+    legitimate_message_end_ = true;  // ... and it hit EOF.
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline int CodedInputStream::CurrentPosition() const {
+  return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
+}
+
+inline void CodedInputStream::Advance(int amount) { buffer_ += amount; }
+
+inline void CodedInputStream::SetRecursionLimit(int limit) {
+  recursion_budget_ += limit - recursion_limit_;
+  recursion_limit_ = limit;
+}
+
+inline bool CodedInputStream::IncrementRecursionDepth() {
+  --recursion_budget_;
+  return recursion_budget_ >= 0;
+}
+
+inline void CodedInputStream::DecrementRecursionDepth() {
+  if (recursion_budget_ < recursion_limit_) ++recursion_budget_;
+}
+
+inline void CodedInputStream::UnsafeDecrementRecursionDepth() {
+  assert(recursion_budget_ < recursion_limit_);
+  ++recursion_budget_;
+}
+
+inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
+                                                   MessageFactory* factory) {
+  extension_pool_ = pool;
+  extension_factory_ = factory;
+}
+
+inline const DescriptorPool* CodedInputStream::GetExtensionPool() {
+  return extension_pool_;
+}
+
+inline MessageFactory* CodedInputStream::GetExtensionFactory() {
+  return extension_factory_;
+}
+
+inline int CodedInputStream::BufferSize() const {
+  return static_cast<int>(buffer_end_ - buffer_);
+}
+
+inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
+    : buffer_(nullptr),
+      buffer_end_(nullptr),
+      input_(input),
+      total_bytes_read_(0),
+      overflow_bytes_(0),
+      last_tag_(0),
+      legitimate_message_end_(false),
+      aliasing_enabled_(false),
+      current_limit_(std::numeric_limits<int32_t>::max()),
+      buffer_size_after_limit_(0),
+      total_bytes_limit_(kDefaultTotalBytesLimit),
+      recursion_budget_(default_recursion_limit_),
+      recursion_limit_(default_recursion_limit_),
+      extension_pool_(nullptr),
+      extension_factory_(nullptr) {
+  // Eagerly Refresh() so buffer space is immediately available.
+  Refresh();
+}
+
+inline CodedInputStream::CodedInputStream(const uint8_t* buffer, int size)
+    : buffer_(buffer),
+      buffer_end_(buffer + size),
+      input_(nullptr),
+      total_bytes_read_(size),
+      overflow_bytes_(0),
+      last_tag_(0),
+      legitimate_message_end_(false),
+      aliasing_enabled_(false),
+      current_limit_(size),
+      buffer_size_after_limit_(0),
+      total_bytes_limit_(kDefaultTotalBytesLimit),
+      recursion_budget_(default_recursion_limit_),
+      recursion_limit_(default_recursion_limit_),
+      extension_pool_(nullptr),
+      extension_factory_(nullptr) {
+  // Note that setting current_limit_ == size is important to prevent some
+  // code paths from trying to access input_ and segfaulting.
+}
+
+inline bool CodedInputStream::IsFlat() const { return input_ == nullptr; }
+
+inline bool CodedInputStream::Skip(int count) {
+  if (count < 0) return false;  // security: count is often user-supplied
+
+  const int original_buffer_size = BufferSize();
+
+  if (count <= original_buffer_size) {
+    // Just skipping within the current buffer.  Easy.
+    Advance(count);
+    return true;
+  }
+
+  return SkipFallback(count, original_buffer_size);
+}
+
+template <class Stream, class>
+inline CodedOutputStream::CodedOutputStream(Stream* stream)
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
+  InitEagerly(stream);
+}
+
+template <class Stream, class>
+inline CodedOutputStream::CodedOutputStream(Stream* stream, bool eager_init)
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
+  if (eager_init) {
+    InitEagerly(stream);
+  }
+}
+
+template <class Stream>
+inline void CodedOutputStream::InitEagerly(Stream* stream) {
+  void* data;
+  int size;
+  if (PROTOBUF_PREDICT_TRUE(stream->Next(&data, &size) && size > 0)) {
+    cur_ = impl_.SetInitialBuffer(data, size);
+  }
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint32ToArray(uint32_t value,
+                                                        uint8_t* target) {
+  return EpsCopyOutputStream::UnsafeVarint(value, target);
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLine(
+    uint32_t value, uint8_t* target) {
+  target[0] = static_cast<uint8_t>(value);
+  if (value < 0x80) {
+    return target + 1;
+  } else {
+    return WriteVarint32ToArrayOutOfLineHelper(value, target);
+  }
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint64ToArray(uint64_t value,
+                                                        uint8_t* target) {
+  return EpsCopyOutputStream::UnsafeVarint(value, target);
+}
+
+inline void CodedOutputStream::WriteVarint32SignExtended(int32_t value) {
+  WriteVarint64(static_cast<uint64_t>(value));
+}
+
+inline uint8_t* CodedOutputStream::WriteVarint32SignExtendedToArray(
+    int32_t value, uint8_t* target) {
+  return WriteVarint64ToArray(static_cast<uint64_t>(value), target);
+}
+
+inline uint8_t* CodedOutputStream::WriteLittleEndian32ToArray(uint32_t value,
+                                                              uint8_t* target) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(target, &value, sizeof(value));
+#else
+  target[0] = static_cast<uint8_t>(value);
+  target[1] = static_cast<uint8_t>(value >> 8);
+  target[2] = static_cast<uint8_t>(value >> 16);
+  target[3] = static_cast<uint8_t>(value >> 24);
+#endif
+  return target + sizeof(value);
+}
+
+inline uint8_t* CodedOutputStream::WriteLittleEndian64ToArray(uint64_t value,
+                                                              uint8_t* target) {
+#if defined(PROTOBUF_LITTLE_ENDIAN) && \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  memcpy(target, &value, sizeof(value));
+#else
+  uint32_t part0 = static_cast<uint32_t>(value);
+  uint32_t part1 = static_cast<uint32_t>(value >> 32);
+
+  target[0] = static_cast<uint8_t>(part0);
+  target[1] = static_cast<uint8_t>(part0 >> 8);
+  target[2] = static_cast<uint8_t>(part0 >> 16);
+  target[3] = static_cast<uint8_t>(part0 >> 24);
+  target[4] = static_cast<uint8_t>(part1);
+  target[5] = static_cast<uint8_t>(part1 >> 8);
+  target[6] = static_cast<uint8_t>(part1 >> 16);
+  target[7] = static_cast<uint8_t>(part1 >> 24);
+#endif
+  return target + sizeof(value);
+}
+
+inline void CodedOutputStream::WriteVarint32(uint32_t value) {
+  cur_ = impl_.EnsureSpace(cur_);
+  SetCur(WriteVarint32ToArray(value, Cur()));
+}
+
+inline void CodedOutputStream::WriteVarint64(uint64_t value) {
+  cur_ = impl_.EnsureSpace(cur_);
+  SetCur(WriteVarint64ToArray(value, Cur()));
+}
+
+inline void CodedOutputStream::WriteTag(uint32_t value) {
+  WriteVarint32(value);
+}
+
+inline uint8_t* CodedOutputStream::WriteTagToArray(uint32_t value,
+                                                   uint8_t* target) {
+  return WriteVarint32ToArray(value, target);
+}
+
+inline size_t CodedOutputStream::VarintSize32(uint32_t value) {
+  // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
+  // Use an explicit multiplication to implement the divide of
+  // a number in the 1..31 range.
+  // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
+  // undefined.
+  uint32_t log2value = Bits::Log2FloorNonZero(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize32PlusOne(uint32_t value) {
+  // Same as above, but one more.
+  uint32_t log2value = Bits::Log2FloorNonZero(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73 + 64) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize64(uint64_t value) {
+  // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
+  // Use an explicit multiplication to implement the divide of
+  // a number in the 1..63 range.
+  // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
+  // undefined.
+  uint32_t log2value = Bits::Log2FloorNonZero64(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize64PlusOne(uint64_t value) {
+  // Same as above, but one more.
+  uint32_t log2value = Bits::Log2FloorNonZero64(value | 0x1);
+  return static_cast<size_t>((log2value * 9 + 73 + 64) / 64);
+}
+
+inline size_t CodedOutputStream::VarintSize32SignExtended(int32_t value) {
+  return VarintSize64(static_cast<uint64_t>(int64_t{value}));
+}
+
+inline size_t CodedOutputStream::VarintSize32SignExtendedPlusOne(
+    int32_t value) {
+  return VarintSize64PlusOne(static_cast<uint64_t>(int64_t{value}));
+}
+
+inline void CodedOutputStream::WriteString(const std::string& str) {
+  WriteRaw(str.data(), static_cast<int>(str.size()));
+}
+
+inline void CodedOutputStream::WriteRawMaybeAliased(const void* data,
+                                                    int size) {
+  cur_ = impl_.WriteRawMaybeAliased(data, size, cur_);
+}
+
+inline uint8_t* CodedOutputStream::WriteRawToArray(const void* data, int size,
+                                                   uint8_t* target) {
+  memcpy(target, data, size);
+  return target + size;
+}
+
+inline uint8_t* CodedOutputStream::WriteStringToArray(const std::string& str,
+                                                      uint8_t* target) {
+  return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
+#pragma runtime_checks("c", restore)
+#endif  // _MSC_VER && !defined(__INTEL_COMPILER)
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/gzip_stream.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/gzip_stream.h
new file mode 100644
index 0000000..4cf71b6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/gzip_stream.h
@@ -0,0 +1,205 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: brianolson@google.com (Brian Olson)
+//
+// This file contains the definition for classes GzipInputStream and
+// GzipOutputStream.
+//
+// GzipInputStream decompresses data from an underlying
+// ZeroCopyInputStream and provides the decompressed data as a
+// ZeroCopyInputStream.
+//
+// GzipOutputStream is an ZeroCopyOutputStream that compresses data to
+// an underlying ZeroCopyOutputStream.
+
+#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
+#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
+
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/port.h>
+#include "zlib.h"
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// A ZeroCopyInputStream that reads compressed data through zlib
+class PROTOBUF_EXPORT GzipInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Format key for constructor
+  enum Format {
+    // zlib will autodetect gzip header or deflate stream
+    AUTO = 0,
+
+    // GZIP streams have some extra header data for file attributes.
+    GZIP = 1,
+
+    // Simpler zlib stream format.
+    ZLIB = 2,
+  };
+
+  // buffer_size and format may be -1 for default of 64kB and GZIP format
+  explicit GzipInputStream(ZeroCopyInputStream* sub_stream,
+                           Format format = AUTO, int buffer_size = -1);
+  virtual ~GzipInputStream();
+
+  // Return last error message or NULL if no error.
+  inline const char* ZlibErrorMessage() const { return zcontext_.msg; }
+  inline int ZlibErrorCode() const { return zerror_; }
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  Format format_;
+
+  ZeroCopyInputStream* sub_stream_;
+
+  z_stream zcontext_;
+  int zerror_;
+
+  void* output_buffer_;
+  void* output_position_;
+  size_t output_buffer_length_;
+  int64_t byte_count_;
+
+  int Inflate(int flush);
+  void DoNextOutput(const void** data, int* size);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
+};
+
+class PROTOBUF_EXPORT GzipOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Format key for constructor
+  enum Format {
+    // GZIP streams have some extra header data for file attributes.
+    GZIP = 1,
+
+    // Simpler zlib stream format.
+    ZLIB = 2,
+  };
+
+  struct PROTOBUF_EXPORT Options {
+    // Defaults to GZIP.
+    Format format;
+
+    // What size buffer to use internally.  Defaults to 64kB.
+    int buffer_size;
+
+    // A number between 0 and 9, where 0 is no compression and 9 is best
+    // compression.  Defaults to Z_DEFAULT_COMPRESSION (see zlib.h).
+    int compression_level;
+
+    // Defaults to Z_DEFAULT_STRATEGY.  Can also be set to Z_FILTERED,
+    // Z_HUFFMAN_ONLY, or Z_RLE.  See the documentation for deflateInit2 in
+    // zlib.h for definitions of these constants.
+    int compression_strategy;
+
+    Options();  // Initializes with default values.
+  };
+
+  // Create a GzipOutputStream with default options.
+  explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream);
+
+  // Create a GzipOutputStream with the given options.
+  GzipOutputStream(ZeroCopyOutputStream* sub_stream, const Options& options);
+
+  virtual ~GzipOutputStream();
+
+  // Return last error message or NULL if no error.
+  inline const char* ZlibErrorMessage() const { return zcontext_.msg; }
+  inline int ZlibErrorCode() const { return zerror_; }
+
+  // Flushes data written so far to zipped data in the underlying stream.
+  // It is the caller's responsibility to flush the underlying stream if
+  // necessary.
+  // Compression may be less efficient stopping and starting around flushes.
+  // Returns true if no error.
+  //
+  // Please ensure that block size is > 6. Here is an excerpt from the zlib
+  // doc that explains why:
+  //
+  // In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out
+  // is greater than six to avoid repeated flush markers due to
+  // avail_out == 0 on return.
+  bool Flush();
+
+  // Writes out all data and closes the gzip stream.
+  // It is the caller's responsibility to close the underlying stream if
+  // necessary.
+  // Returns true if no error.
+  bool Close();
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  ZeroCopyOutputStream* sub_stream_;
+  // Result from calling Next() on sub_stream_
+  void* sub_data_;
+  int sub_data_size_;
+
+  z_stream zcontext_;
+  int zerror_;
+  void* input_buffer_;
+  size_t input_buffer_length_;
+
+  // Shared constructor code.
+  void Init(ZeroCopyOutputStream* sub_stream, const Options& options);
+
+  // Do some compression.
+  // Takes zlib flush mode.
+  // Returns zlib error code.
+  int Deflate(int flush);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream);
+};
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/io_win32.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/io_win32.h
new file mode 100644
index 0000000..a72b4ea
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/io_win32.h
@@ -0,0 +1,141 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: laszlocsomor@google.com (Laszlo Csomor)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+// This file contains the declarations for Windows implementations of
+// commonly used POSIX functions such as open(2) and access(2), as well
+// as macro definitions for flags of these functions.
+//
+// By including this file you'll redefine open/access/etc. to
+// ::google::protobuf::io::win32::{open/access/etc.}.
+// Make sure you don't include a header that attempts to redeclare or
+// redefine these functions, that'll lead to confusing compilation
+// errors. It's best to #include this file as the last one to ensure that.
+//
+// This file is only used on Windows, it's empty on other platforms.
+
+#ifndef GOOGLE_PROTOBUF_IO_IO_WIN32_H__
+#define GOOGLE_PROTOBUF_IO_IO_WIN32_H__
+
+#if defined(_WIN32)
+
+#include <functional>
+#include <string>
+
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// Compilers on Windows other than MSVC (e.g. Cygwin, MinGW32) define the
+// following functions already, except for mkdir.
+namespace google {
+namespace protobuf {
+namespace io {
+namespace win32 {
+
+PROTOBUF_EXPORT FILE* fopen(const char* path, const char* mode);
+PROTOBUF_EXPORT int access(const char* path, int mode);
+PROTOBUF_EXPORT int chdir(const char* path);
+PROTOBUF_EXPORT int close(int fd);
+PROTOBUF_EXPORT int dup(int fd);
+PROTOBUF_EXPORT int dup2(int fd1, int fd2);
+PROTOBUF_EXPORT int mkdir(const char* path, int _mode);
+PROTOBUF_EXPORT int open(const char* path, int flags, int mode = 0);
+PROTOBUF_EXPORT int read(int fd, void* buffer, size_t size);
+PROTOBUF_EXPORT int setmode(int fd, int mode);
+PROTOBUF_EXPORT int stat(const char* path, struct _stat* buffer);
+PROTOBUF_EXPORT int write(int fd, const void* buffer, size_t size);
+PROTOBUF_EXPORT std::wstring testonly_utf8_to_winpath(const char* path);
+
+enum class ExpandWildcardsResult {
+  kSuccess = 0,
+  kErrorNoMatchingFile = 1,
+  kErrorInputPathConversion = 2,
+  kErrorOutputPathConversion = 3,
+};
+
+// Expand wildcards in a path pattern, feed the result to a consumer function.
+//
+// `path` must be a valid, Windows-style path. It may be absolute, or relative
+// to the current working directory, and it may contain wildcards ("*" and "?")
+// in the last path segment. This function passes all matching file names to
+// `consume`. The resulting paths may not be absolute nor normalized.
+//
+// The function returns a value from `ExpandWildcardsResult`.
+PROTOBUF_EXPORT ExpandWildcardsResult ExpandWildcards(
+    const std::string& path, std::function<void(const std::string&)> consume);
+
+namespace strings {
+
+// Convert from UTF-16 to Active-Code-Page-encoded or to UTF-8-encoded text.
+PROTOBUF_EXPORT bool wcs_to_mbs(const wchar_t* s, std::string* out,
+                                bool outUtf8);
+
+// Convert from Active-Code-Page-encoded or UTF-8-encoded text to UTF-16.
+PROTOBUF_EXPORT bool mbs_to_wcs(const char* s, std::wstring* out, bool inUtf8);
+
+// Convert from UTF-8-encoded text to UTF-16.
+PROTOBUF_EXPORT bool utf8_to_wcs(const char* input, std::wstring* out);
+
+// Convert from UTF-16-encoded text to UTF-8.
+PROTOBUF_EXPORT bool wcs_to_utf8(const wchar_t* input, std::string* out);
+
+}  // namespace strings
+
+}  // namespace win32
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#ifndef W_OK
+#define W_OK 02  // not defined by MSVC for whatever reason
+#endif
+
+#ifndef F_OK
+#define F_OK 00  // not defined by MSVC for whatever reason
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // defined(_WIN32)
+
+#endif  // GOOGLE_PROTOBUF_IO_IO_WIN32_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/printer.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/printer.h
new file mode 100644
index 0000000..92a4321
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/printer.h
@@ -0,0 +1,387 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Utility class for writing text to a ZeroCopyOutputStream.
+
+#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
+#define GOOGLE_PROTOBUF_IO_PRINTER_H__
+
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+class ZeroCopyOutputStream;  // zero_copy_stream.h
+
+// Records annotations about a Printer's output.
+class PROTOBUF_EXPORT AnnotationCollector {
+ public:
+  // Annotation is a offset range and a payload pair.
+  typedef std::pair<std::pair<size_t, size_t>, std::string> Annotation;
+
+  // Records that the bytes in file_path beginning with begin_offset and ending
+  // before end_offset are associated with the SourceCodeInfo-style path.
+  virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
+                             const std::string& file_path,
+                             const std::vector<int>& path) = 0;
+
+  // TODO(gerbens) I don't see why we need virtuals here. Just a vector of
+  // range, payload pairs stored in a context should suffice.
+  virtual void AddAnnotationNew(Annotation& /* a */) {}
+
+  virtual ~AnnotationCollector() {}
+};
+
+// Records annotations about a Printer's output to the given protocol buffer,
+// assuming that the buffer has an ::Annotation message exposing path,
+// source_file, begin and end fields.
+template <typename AnnotationProto>
+class AnnotationProtoCollector : public AnnotationCollector {
+ public:
+  // annotation_proto is the protocol buffer to which new Annotations should be
+  // added. It is not owned by the AnnotationProtoCollector.
+  explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
+      : annotation_proto_(annotation_proto) {}
+
+  // Override for AnnotationCollector::AddAnnotation.
+  void AddAnnotation(size_t begin_offset, size_t end_offset,
+                     const std::string& file_path,
+                     const std::vector<int>& path) override {
+    typename AnnotationProto::Annotation* annotation =
+        annotation_proto_->add_annotation();
+    for (int i = 0; i < path.size(); ++i) {
+      annotation->add_path(path[i]);
+    }
+    annotation->set_source_file(file_path);
+    annotation->set_begin(begin_offset);
+    annotation->set_end(end_offset);
+  }
+  // Override for AnnotationCollector::AddAnnotation.
+  void AddAnnotationNew(Annotation& a) override {
+    auto* annotation = annotation_proto_->add_annotation();
+    annotation->ParseFromString(a.second);
+    annotation->set_begin(a.first.first);
+    annotation->set_end(a.first.second);
+  }
+
+ private:
+  // The protocol buffer to which new annotations should be added.
+  AnnotationProto* const annotation_proto_;
+};
+
+// This simple utility class assists in code generation.  It basically
+// allows the caller to define a set of variables and then output some
+// text with variable substitutions.  Example usage:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["name"] = "Bob";
+//   printer.Print(vars, "My name is $name$.");
+//
+// The above writes "My name is Bob." to the output stream.
+//
+// Printer aggressively enforces correct usage, crashing (with assert failures)
+// in the case of undefined variables in debug builds. This helps greatly in
+// debugging code which uses it.
+//
+// If a Printer is constructed with an AnnotationCollector, it will provide it
+// with annotations that connect the Printer's output to paths that can identify
+// various descriptors.  In the above example, if person_ is a descriptor that
+// identifies Bob, we can associate the output string "My name is Bob." with
+// a source path pointing to that descriptor with:
+//
+//   printer.Annotate("name", person_);
+//
+// The AnnotationCollector will be sent an annotation linking the output range
+// covering "Bob" to the logical path provided by person_.  Tools may use
+// this association to (for example) link "Bob" in the output back to the
+// source file that defined the person_ descriptor identifying Bob.
+//
+// Annotate can only examine variables substituted during the last call to
+// Print.  It is invalid to refer to a variable that was used multiple times
+// in a single Print call.
+//
+// In full generality, one may specify a range of output text using a beginning
+// substitution variable and an ending variable.  The resulting annotation will
+// span from the first character of the substituted value for the beginning
+// variable to the last character of the substituted value for the ending
+// variable.  For example, the Annotate call above is equivalent to this one:
+//
+//   printer.Annotate("name", "name", person_);
+//
+// This is useful if multiple variables combine to form a single span of output
+// that should be annotated with the same source path.  For example:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["first"] = "Alice";
+//   vars["last"] = "Smith";
+//   printer.Print(vars, "My name is $first$ $last$.");
+//   printer.Annotate("first", "last", person_);
+//
+// This code would associate the span covering "Alice Smith" in the output with
+// the person_ descriptor.
+//
+// Note that the beginning variable must come before (or overlap with, in the
+// case of zero-sized substitution values) the ending variable.
+//
+// It is also sometimes useful to use variables with zero-sized values as
+// markers.  This avoids issues with multiple references to the same variable
+// and also allows annotation ranges to span literal text from the Print
+// templates:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["foo"] = "bar";
+//   vars["function"] = "call";
+//   vars["mark"] = "";
+//   printer.Print(vars, "$function$($foo$,$foo$)$mark$");
+//   printer.Annotate("function", "mark", call_);
+//
+// This code associates the span covering "call(bar,bar)" in the output with the
+// call_ descriptor.
+
+class PROTOBUF_EXPORT Printer {
+ public:
+  // Create a printer that writes text to the given output stream.  Use the
+  // given character as the delimiter for variables.
+  Printer(ZeroCopyOutputStream* output, char variable_delimiter);
+
+  // Create a printer that writes text to the given output stream.  Use the
+  // given character as the delimiter for variables.  If annotation_collector
+  // is not null, Printer will provide it with annotations about code written
+  // to the stream.  annotation_collector is not owned by Printer.
+  Printer(ZeroCopyOutputStream* output, char variable_delimiter,
+          AnnotationCollector* annotation_collector);
+
+  ~Printer();
+
+  // Link a substitution variable emitted by the last call to Print to the
+  // object described by descriptor.
+  template <typename SomeDescriptor>
+  void Annotate(const char* varname, const SomeDescriptor* descriptor) {
+    Annotate(varname, varname, descriptor);
+  }
+
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the object described by descriptor. The range
+  // begins at begin_varname's value and ends after the last character of the
+  // value substituted for end_varname.
+  template <typename SomeDescriptor>
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const SomeDescriptor* descriptor) {
+    if (annotation_collector_ == NULL) {
+      // Annotations aren't turned on for this Printer, so don't pay the cost
+      // of building the location path.
+      return;
+    }
+    std::vector<int> path;
+    descriptor->GetLocationPath(&path);
+    Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
+  }
+
+  // Link a substitution variable emitted by the last call to Print to the file
+  // with path file_name.
+  void Annotate(const char* varname, const std::string& file_name) {
+    Annotate(varname, varname, file_name);
+  }
+
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the file with path file_name. The range begins
+  // at begin_varname's value and ends after the last character of the value
+  // substituted for end_varname.
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const std::string& file_name) {
+    if (annotation_collector_ == NULL) {
+      // Annotations aren't turned on for this Printer.
+      return;
+    }
+    std::vector<int> empty_path;
+    Annotate(begin_varname, end_varname, file_name, empty_path);
+  }
+
+  // Print some text after applying variable substitutions.  If a particular
+  // variable in the text is not defined, this will crash.  Variables to be
+  // substituted are identified by their names surrounded by delimiter
+  // characters (as given to the constructor).  The variable bindings are
+  // defined by the given map.
+  void Print(const std::map<std::string, std::string>& variables,
+             const char* text);
+
+  // Like the first Print(), except the substitutions are given as parameters.
+  template <typename... Args>
+  void Print(const char* text, const Args&... args) {
+    std::map<std::string, std::string> vars;
+    PrintInternal(&vars, text, args...);
+  }
+
+  // Indent text by two spaces.  After calling Indent(), two spaces will be
+  // inserted at the beginning of each line of text.  Indent() may be called
+  // multiple times to produce deeper indents.
+  void Indent();
+
+  // Reduces the current indent level by two spaces, or crashes if the indent
+  // level is zero.
+  void Outdent();
+
+  // Write a string to the output buffer.
+  // This method does not look for newlines to add indentation.
+  void PrintRaw(const std::string& data);
+
+  // Write a zero-delimited string to output buffer.
+  // This method does not look for newlines to add indentation.
+  void PrintRaw(const char* data);
+
+  // Write some bytes to the output buffer.
+  // This method does not look for newlines to add indentation.
+  void WriteRaw(const char* data, int size);
+
+  // FormatInternal is a helper function not meant to use directly, use
+  // compiler::cpp::Formatter instead. This function is meant to support
+  // formatting text using named variables (eq. "$foo$) from a lookup map (vars)
+  // and variables directly supplied by arguments (eq "$1$" meaning first
+  // argument which is the zero index element of args).
+  void FormatInternal(const std::vector<std::string>& args,
+                      const std::map<std::string, std::string>& vars,
+                      const char* format);
+
+  // True if any write to the underlying stream failed.  (We don't just
+  // crash in this case because this is an I/O failure, not a programming
+  // error.)
+  bool failed() const { return failed_; }
+
+ private:
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the object found at the SourceCodeInfo-style path
+  // in a file with path file_path. The range begins at the start of
+  // begin_varname's value and ends after the last character of the value
+  // substituted for end_varname. Note that begin_varname and end_varname
+  // may refer to the same variable.
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const std::string& file_path, const std::vector<int>& path);
+
+  // Base case
+  void PrintInternal(std::map<std::string, std::string>* vars,
+                     const char* text) {
+    Print(*vars, text);
+  }
+
+  template <typename... Args>
+  void PrintInternal(std::map<std::string, std::string>* vars, const char* text,
+                     const char* key, const std::string& value,
+                     const Args&... args) {
+    (*vars)[key] = value;
+    PrintInternal(vars, text, args...);
+  }
+
+  // Copy size worth of bytes from data to buffer_.
+  void CopyToBuffer(const char* data, int size);
+
+  void push_back(char c) {
+    if (failed_) return;
+    if (buffer_size_ == 0) {
+      if (!Next()) return;
+    }
+    *buffer_++ = c;
+    buffer_size_--;
+    offset_++;
+  }
+
+  bool Next();
+
+  inline void IndentIfAtStart();
+  const char* WriteVariable(
+      const std::vector<std::string>& args,
+      const std::map<std::string, std::string>& vars, const char* format,
+      int* arg_index,
+      std::vector<AnnotationCollector::Annotation>* annotations);
+
+  const char variable_delimiter_;
+
+  ZeroCopyOutputStream* const output_;
+  char* buffer_;
+  int buffer_size_;
+  // The current position, in bytes, in the output stream.  This is equivalent
+  // to the total number of bytes that have been written so far.  This value is
+  // used to calculate annotation ranges in the substitutions_ map below.
+  size_t offset_;
+
+  std::string indent_;
+  bool at_start_of_line_;
+  bool failed_;
+
+  // A map from variable name to [start, end) offsets in the output buffer.
+  // These refer to the offsets used for a variable after the last call to
+  // Print.  If a variable was used more than once, the entry used in
+  // this map is set to a negative-length span.  For singly-used variables, the
+  // start offset is the beginning of the substitution; the end offset is the
+  // last byte of the substitution plus one (such that (end - start) is the
+  // length of the substituted string).
+  std::map<std::string, std::pair<size_t, size_t> > substitutions_;
+
+  // Keeps track of the keys in substitutions_ that need to be updated when
+  // indents are inserted. These are keys that refer to the beginning of the
+  // current line.
+  std::vector<std::string> line_start_variables_;
+
+  // Returns true and sets range to the substitution range in the output for
+  // varname if varname was used once in the last call to Print. If varname
+  // was not used, or if it was used multiple times, returns false (and
+  // fails a debug assertion).
+  bool GetSubstitutionRange(const char* varname,
+                            std::pair<size_t, size_t>* range);
+
+  // If non-null, annotation_collector_ is used to store annotations about
+  // generated code.
+  AnnotationCollector* const annotation_collector_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
+};
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_PRINTER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/strtod.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/strtod.h
new file mode 100644
index 0000000..38f544a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/strtod.h
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A locale-independent version of strtod(), used to parse floating
+// point default values in .proto files, where the decimal separator
+// is always a dot.
+
+#ifndef GOOGLE_PROTOBUF_IO_STRTOD_H__
+#define GOOGLE_PROTOBUF_IO_STRTOD_H__
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// A locale-independent version of the standard strtod(), which always
+// uses a dot as the decimal separator.
+double NoLocaleStrtod(const char* str, char** endptr);
+
+// Casts a double value to a float value. If the value is outside of the
+// representable range of float, it will be converted to positive or negative
+// infinity.
+float SafeDoubleToFloat(double value);
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_IO_STRTOD_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/tokenizer.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/tokenizer.h
new file mode 100644
index 0000000..4abab7e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/tokenizer.h
@@ -0,0 +1,442 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Class for parsing tokenized text from a ZeroCopyInputStream.
+
+#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
+#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
+
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+class ZeroCopyInputStream;  // zero_copy_stream.h
+
+// Defined in this file.
+class ErrorCollector;
+class Tokenizer;
+
+// By "column number", the proto compiler refers to a count of the number
+// of bytes before a given byte, except that a tab character advances to
+// the next multiple of 8 bytes.  Note in particular that column numbers
+// are zero-based, while many user interfaces use one-based column numbers.
+typedef int ColumnNumber;
+
+// Abstract interface for an object which collects the errors that occur
+// during parsing.  A typical implementation might simply print the errors
+// to stdout.
+class PROTOBUF_EXPORT ErrorCollector {
+ public:
+  inline ErrorCollector() {}
+  virtual ~ErrorCollector();
+
+  // Indicates that there was an error in the input at the given line and
+  // column numbers.  The numbers are zero-based, so you may want to add
+  // 1 to each before printing them.
+  virtual void AddError(int line, ColumnNumber column,
+                        const std::string& message) = 0;
+
+  // Indicates that there was a warning in the input at the given line and
+  // column numbers.  The numbers are zero-based, so you may want to add
+  // 1 to each before printing them.
+  virtual void AddWarning(int /* line */, ColumnNumber /* column */,
+                          const std::string& /* message */) {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
+};
+
+// This class converts a stream of raw text into a stream of tokens for
+// the protocol definition parser to parse.  The tokens recognized are
+// similar to those that make up the C language; see the TokenType enum for
+// precise descriptions.  Whitespace and comments are skipped.  By default,
+// C- and C++-style comments are recognized, but other styles can be used by
+// calling set_comment_style().
+class PROTOBUF_EXPORT Tokenizer {
+ public:
+  // Construct a Tokenizer that reads and tokenizes text from the given
+  // input stream and writes errors to the given error_collector.
+  // The caller keeps ownership of input and error_collector.
+  Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector);
+  ~Tokenizer();
+
+  enum TokenType {
+    TYPE_START,  // Next() has not yet been called.
+    TYPE_END,    // End of input reached.  "text" is empty.
+
+    TYPE_IDENTIFIER,  // A sequence of letters, digits, and underscores, not
+                      // starting with a digit.  It is an error for a number
+                      // to be followed by an identifier with no space in
+                      // between.
+    TYPE_INTEGER,     // A sequence of digits representing an integer.  Normally
+                      // the digits are decimal, but a prefix of "0x" indicates
+                      // a hex number and a leading zero indicates octal, just
+                      // like with C numeric literals.  A leading negative sign
+                      // is NOT included in the token; it's up to the parser to
+                      // interpret the unary minus operator on its own.
+    TYPE_FLOAT,       // A floating point literal, with a fractional part and/or
+                      // an exponent.  Always in decimal.  Again, never
+                      // negative.
+    TYPE_STRING,      // A quoted sequence of escaped characters.  Either single
+                      // or double quotes can be used, but they must match.
+                      // A string literal cannot cross a line break.
+    TYPE_SYMBOL,      // Any other printable character, like '!' or '+'.
+                      // Symbols are always a single character, so "!+$%" is
+                      // four tokens.
+    TYPE_WHITESPACE,  // A sequence of whitespace.  This token type is only
+                      // produced if report_whitespace() is true.  It is not
+                      // reported for whitespace within comments or strings.
+    TYPE_NEWLINE,     // A newline (\n).  This token type is only
+                      // produced if report_whitespace() is true and
+                      // report_newlines() is true.  It is not reported for
+                      // newlines in comments or strings.
+  };
+
+  // Structure representing a token read from the token stream.
+  struct Token {
+    TokenType type;
+    std::string text;  // The exact text of the token as it appeared in
+                       // the input.  e.g. tokens of TYPE_STRING will still
+                       // be escaped and in quotes.
+
+    // "line" and "column" specify the position of the first character of
+    // the token within the input stream.  They are zero-based.
+    int line;
+    ColumnNumber column;
+    ColumnNumber end_column;
+  };
+
+  // Get the current token.  This is updated when Next() is called.  Before
+  // the first call to Next(), current() has type TYPE_START and no contents.
+  const Token& current();
+
+  // Return the previous token -- i.e. what current() returned before the
+  // previous call to Next().
+  const Token& previous();
+
+  // Advance to the next token.  Returns false if the end of the input is
+  // reached.
+  bool Next();
+
+  // Like Next(), but also collects comments which appear between the previous
+  // and next tokens.
+  //
+  // Comments which appear to be attached to the previous token are stored
+  // in *prev_tailing_comments.  Comments which appear to be attached to the
+  // next token are stored in *next_leading_comments.  Comments appearing in
+  // between which do not appear to be attached to either will be added to
+  // detached_comments.  Any of these parameters can be NULL to simply discard
+  // the comments.
+  //
+  // A series of line comments appearing on consecutive lines, with no other
+  // tokens appearing on those lines, will be treated as a single comment.
+  //
+  // Only the comment content is returned; comment markers (e.g. //) are
+  // stripped out.  For block comments, leading whitespace and an asterisk will
+  // be stripped from the beginning of each line other than the first.  Newlines
+  // are included in the output.
+  //
+  // Examples:
+  //
+  //   optional int32 foo = 1;  // Comment attached to foo.
+  //   // Comment attached to bar.
+  //   optional int32 bar = 2;
+  //
+  //   optional string baz = 3;
+  //   // Comment attached to baz.
+  //   // Another line attached to baz.
+  //
+  //   // Comment attached to qux.
+  //   //
+  //   // Another line attached to qux.
+  //   optional double qux = 4;
+  //
+  //   // Detached comment.  This is not attached to qux or corge
+  //   // because there are blank lines separating it from both.
+  //
+  //   optional string corge = 5;
+  //   /* Block comment attached
+  //    * to corge.  Leading asterisks
+  //    * will be removed. */
+  //   /* Block comment attached to
+  //    * grault. */
+  //   optional int32 grault = 6;
+  bool NextWithComments(std::string* prev_trailing_comments,
+                        std::vector<std::string>* detached_comments,
+                        std::string* next_leading_comments);
+
+  // Parse helpers ---------------------------------------------------
+
+  // Parses a TYPE_FLOAT token.  This never fails, so long as the text actually
+  // comes from a TYPE_FLOAT token parsed by Tokenizer.  If it doesn't, the
+  // result is undefined (possibly an assert failure).
+  static double ParseFloat(const std::string& text);
+
+  // Parses a TYPE_STRING token.  This never fails, so long as the text actually
+  // comes from a TYPE_STRING token parsed by Tokenizer.  If it doesn't, the
+  // result is undefined (possibly an assert failure).
+  static void ParseString(const std::string& text, std::string* output);
+
+  // Identical to ParseString, but appends to output.
+  static void ParseStringAppend(const std::string& text, std::string* output);
+
+  // Parses a TYPE_INTEGER token.  Returns false if the result would be
+  // greater than max_value.  Otherwise, returns true and sets *output to the
+  // result.  If the text is not from a Token of type TYPE_INTEGER originally
+  // parsed by a Tokenizer, the result is undefined (possibly an assert
+  // failure).
+  static bool ParseInteger(const std::string& text, uint64_t max_value,
+                           uint64_t* output);
+
+  // Options ---------------------------------------------------------
+
+  // Set true to allow floats to be suffixed with the letter 'f'.  Tokens
+  // which would otherwise be integers but which have the 'f' suffix will be
+  // forced to be interpreted as floats.  For all other purposes, the 'f' is
+  // ignored.
+  void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
+
+  // Valid values for set_comment_style().
+  enum CommentStyle {
+    // Line comments begin with "//", block comments are delimited by "/*" and
+    // "*/".
+    CPP_COMMENT_STYLE,
+    // Line comments begin with "#".  No way to write block comments.
+    SH_COMMENT_STYLE
+  };
+
+  // Sets the comment style.
+  void set_comment_style(CommentStyle style) { comment_style_ = style; }
+
+  // Whether to require whitespace between a number and a field name.
+  // Default is true. Do not use this; for Google-internal cleanup only.
+  void set_require_space_after_number(bool require) {
+    require_space_after_number_ = require;
+  }
+
+  // Whether to allow string literals to span multiple lines. Default is false.
+  // Do not use this; for Google-internal cleanup only.
+  void set_allow_multiline_strings(bool allow) {
+    allow_multiline_strings_ = allow;
+  }
+
+  // If true, whitespace tokens are reported by Next().
+  // Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
+  bool report_whitespace() const;
+  void set_report_whitespace(bool report);
+
+  // If true, newline tokens are reported by Next().
+  // Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
+  bool report_newlines() const;
+  void set_report_newlines(bool report);
+
+  // External helper: validate an identifier.
+  static bool IsIdentifier(const std::string& text);
+
+  // -----------------------------------------------------------------
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
+
+  Token current_;   // Returned by current().
+  Token previous_;  // Returned by previous().
+
+  ZeroCopyInputStream* input_;
+  ErrorCollector* error_collector_;
+
+  char current_char_;   // == buffer_[buffer_pos_], updated by NextChar().
+  const char* buffer_;  // Current buffer returned from input_.
+  int buffer_size_;     // Size of buffer_.
+  int buffer_pos_;      // Current position within the buffer.
+  bool read_error_;     // Did we previously encounter a read error?
+
+  // Line and column number of current_char_ within the whole input stream.
+  int line_;
+  ColumnNumber column_;
+
+  // String to which text should be appended as we advance through it.
+  // Call RecordTo(&str) to start recording and StopRecording() to stop.
+  // E.g. StartToken() calls RecordTo(&current_.text).  record_start_ is the
+  // position within the current buffer where recording started.
+  std::string* record_target_;
+  int record_start_;
+
+  // Options.
+  bool allow_f_after_float_;
+  CommentStyle comment_style_;
+  bool require_space_after_number_;
+  bool allow_multiline_strings_;
+  bool report_whitespace_ = false;
+  bool report_newlines_ = false;
+
+  // Since we count columns we need to interpret tabs somehow.  We'll take
+  // the standard 8-character definition for lack of any way to do better.
+  // This must match the documentation of ColumnNumber.
+  static const int kTabWidth = 8;
+
+  // -----------------------------------------------------------------
+  // Helper methods.
+
+  // Consume this character and advance to the next one.
+  void NextChar();
+
+  // Read a new buffer from the input.
+  void Refresh();
+
+  inline void RecordTo(std::string* target);
+  inline void StopRecording();
+
+  // Called when the current character is the first character of a new
+  // token (not including whitespace or comments).
+  inline void StartToken();
+  // Called when the current character is the first character after the
+  // end of the last token.  After this returns, current_.text will
+  // contain all text consumed since StartToken() was called.
+  inline void EndToken();
+
+  // Convenience method to add an error at the current line and column.
+  void AddError(const std::string& message) {
+    error_collector_->AddError(line_, column_, message);
+  }
+
+  // -----------------------------------------------------------------
+  // The following four methods are used to consume tokens of specific
+  // types.  They are actually used to consume all characters *after*
+  // the first, since the calling function consumes the first character
+  // in order to decide what kind of token is being read.
+
+  // Read and consume a string, ending when the given delimiter is
+  // consumed.
+  void ConsumeString(char delimiter);
+
+  // Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
+  // depending on what was read.  This needs to know if the first
+  // character was a zero in order to correctly recognize hex and octal
+  // numbers.
+  // It also needs to know if the first character was a . to parse floating
+  // point correctly.
+  TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
+
+  // Consume the rest of a line.
+  void ConsumeLineComment(std::string* content);
+  // Consume until "*/".
+  void ConsumeBlockComment(std::string* content);
+
+  enum NextCommentStatus {
+    // Started a line comment.
+    LINE_COMMENT,
+
+    // Started a block comment.
+    BLOCK_COMMENT,
+
+    // Consumed a slash, then realized it wasn't a comment.  current_ has
+    // been filled in with a slash token.  The caller should return it.
+    SLASH_NOT_COMMENT,
+
+    // We do not appear to be starting a comment here.
+    NO_COMMENT
+  };
+
+  // If we're at the start of a new comment, consume it and return what kind
+  // of comment it is.
+  NextCommentStatus TryConsumeCommentStart();
+
+  // If we're looking at a TYPE_WHITESPACE token and `report_whitespace_` is
+  // true, consume it and return true.
+  bool TryConsumeWhitespace();
+
+  // If we're looking at a TYPE_NEWLINE token and `report_newlines_` is true,
+  // consume it and return true.
+  bool TryConsumeNewline();
+
+  // -----------------------------------------------------------------
+  // These helper methods make the parsing code more readable.  The
+  // "character classes" referred to are defined at the top of the .cc file.
+  // Basically it is a C++ class with one method:
+  //   static bool InClass(char c);
+  // The method returns true if c is a member of this "class", like "Letter"
+  // or "Digit".
+
+  // Returns true if the current character is of the given character
+  // class, but does not consume anything.
+  template <typename CharacterClass>
+  inline bool LookingAt();
+
+  // If the current character is in the given class, consume it and return
+  // true.  Otherwise return false.
+  // e.g. TryConsumeOne<Letter>()
+  template <typename CharacterClass>
+  inline bool TryConsumeOne();
+
+  // Like above, but try to consume the specific character indicated.
+  inline bool TryConsume(char c);
+
+  // Consume zero or more of the given character class.
+  template <typename CharacterClass>
+  inline void ConsumeZeroOrMore();
+
+  // Consume one or more of the given character class or log the given
+  // error message.
+  // e.g. ConsumeOneOrMore<Digit>("Expected digits.");
+  template <typename CharacterClass>
+  inline void ConsumeOneOrMore(const char* error);
+};
+
+// inline methods ====================================================
+inline const Tokenizer::Token& Tokenizer::current() { return current_; }
+
+inline const Tokenizer::Token& Tokenizer::previous() { return previous_; }
+
+inline void Tokenizer::ParseString(const std::string& text,
+                                   std::string* output) {
+  output->clear();
+  ParseStringAppend(text, output);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream.h
new file mode 100644
index 0000000..2041cbf
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream.h
@@ -0,0 +1,260 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains the ZeroCopyInputStream and ZeroCopyOutputStream
+// interfaces, which represent abstract I/O streams to and from which
+// protocol buffers can be read and written.  For a few simple
+// implementations of these interfaces, see zero_copy_stream_impl.h.
+//
+// These interfaces are different from classic I/O streams in that they
+// try to minimize the amount of data copying that needs to be done.
+// To accomplish this, responsibility for allocating buffers is moved to
+// the stream object, rather than being the responsibility of the caller.
+// So, the stream can return a buffer which actually points directly into
+// the final data structure where the bytes are to be stored, and the caller
+// can interact directly with that buffer, eliminating an intermediate copy
+// operation.
+//
+// As an example, consider the common case in which you are reading bytes
+// from an array that is already in memory (or perhaps an mmap()ed file).
+// With classic I/O streams, you would do something like:
+//   char buffer[BUFFER_SIZE];
+//   input->Read(buffer, BUFFER_SIZE);
+//   DoSomething(buffer, BUFFER_SIZE);
+// Then, the stream basically just calls memcpy() to copy the data from
+// the array into your buffer.  With a ZeroCopyInputStream, you would do
+// this instead:
+//   const void* buffer;
+//   int size;
+//   input->Next(&buffer, &size);
+//   DoSomething(buffer, size);
+// Here, no copy is performed.  The input stream returns a pointer directly
+// into the backing array, and the caller ends up reading directly from it.
+//
+// If you want to be able to read the old-fashion way, you can create
+// a CodedInputStream or CodedOutputStream wrapping these objects and use
+// their ReadRaw()/WriteRaw() methods.  These will, of course, add a copy
+// step, but Coded*Stream will handle buffering so at least it will be
+// reasonably efficient.
+//
+// ZeroCopyInputStream example:
+//   // Read in a file and print its contents to stdout.
+//   int fd = open("myfile", O_RDONLY);
+//   ZeroCopyInputStream* input = new FileInputStream(fd);
+//
+//   const void* buffer;
+//   int size;
+//   while (input->Next(&buffer, &size)) {
+//     cout.write(buffer, size);
+//   }
+//
+//   delete input;
+//   close(fd);
+//
+// ZeroCopyOutputStream example:
+//   // Copy the contents of "infile" to "outfile", using plain read() for
+//   // "infile" but a ZeroCopyOutputStream for "outfile".
+//   int infd = open("infile", O_RDONLY);
+//   int outfd = open("outfile", O_WRONLY);
+//   ZeroCopyOutputStream* output = new FileOutputStream(outfd);
+//
+//   void* buffer;
+//   int size;
+//   while (output->Next(&buffer, &size)) {
+//     int bytes = read(infd, buffer, size);
+//     if (bytes < size) {
+//       // Reached EOF.
+//       output->BackUp(size - bytes);
+//       break;
+//     }
+//   }
+//
+//   delete output;
+//   close(infd);
+//   close(outfd);
+
+#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
+
+
+#include <google/protobuf/stubs/common.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// Defined in this file.
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+
+// Abstract interface similar to an input stream but designed to minimize
+// copying.
+class PROTOBUF_EXPORT ZeroCopyInputStream {
+ public:
+  ZeroCopyInputStream() {}
+  virtual ~ZeroCopyInputStream() {}
+
+  // Obtains a chunk of data from the stream.
+  //
+  // Preconditions:
+  // * "size" and "data" are not NULL.
+  //
+  // Postconditions:
+  // * If the returned value is false, there is no more data to return or
+  //   an error occurred.  All errors are permanent.
+  // * Otherwise, "size" points to the actual number of bytes read and "data"
+  //   points to a pointer to a buffer containing these bytes.
+  // * Ownership of this buffer remains with the stream, and the buffer
+  //   remains valid only until some other method of the stream is called
+  //   or the stream is destroyed.
+  // * It is legal for the returned buffer to have zero size, as long
+  //   as repeatedly calling Next() eventually yields a buffer with non-zero
+  //   size.
+  virtual bool Next(const void** data, int* size) = 0;
+
+  // Backs up a number of bytes, so that the next call to Next() returns
+  // data again that was already returned by the last call to Next().  This
+  // is useful when writing procedures that are only supposed to read up
+  // to a certain point in the input, then return.  If Next() returns a
+  // buffer that goes beyond what you wanted to read, you can use BackUp()
+  // to return to the point where you intended to finish.
+  //
+  // This method can be called with `count = 0` to finalize (flush) any
+  // previously returned buffer. For example, a file output stream can
+  // flush buffers returned from a previous call to Next() upon such
+  // BackUp(0) invocations. ZeroCopyOutputStream callers should always
+  // invoke BackUp() after a final Next() call, even if there is no
+  // excess buffer data to be backed up to indicate a flush point.
+  //
+  // Preconditions:
+  // * The last method called must have been Next().
+  // * count must be less than or equal to the size of the last buffer
+  //   returned by Next().
+  //
+  // Postconditions:
+  // * The last "count" bytes of the last buffer returned by Next() will be
+  //   pushed back into the stream.  Subsequent calls to Next() will return
+  //   the same data again before producing new data.
+  virtual void BackUp(int count) = 0;
+
+  // Skips a number of bytes.  Returns false if the end of the stream is
+  // reached or some input error occurred.  In the end-of-stream case, the
+  // stream is advanced to the end of the stream (so ByteCount() will return
+  // the total size of the stream).
+  virtual bool Skip(int count) = 0;
+
+  // Returns the total number of bytes read since this object was created.
+  virtual int64_t ByteCount() const = 0;
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream);
+};
+
+// Abstract interface similar to an output stream but designed to minimize
+// copying.
+class PROTOBUF_EXPORT ZeroCopyOutputStream {
+ public:
+  ZeroCopyOutputStream() {}
+  virtual ~ZeroCopyOutputStream() {}
+
+  // Obtains a buffer into which data can be written.  Any data written
+  // into this buffer will eventually (maybe instantly, maybe later on)
+  // be written to the output.
+  //
+  // Preconditions:
+  // * "size" and "data" are not NULL.
+  //
+  // Postconditions:
+  // * If the returned value is false, an error occurred.  All errors are
+  //   permanent.
+  // * Otherwise, "size" points to the actual number of bytes in the buffer
+  //   and "data" points to the buffer.
+  // * Ownership of this buffer remains with the stream, and the buffer
+  //   remains valid only until some other method of the stream is called
+  //   or the stream is destroyed.
+  // * Any data which the caller stores in this buffer will eventually be
+  //   written to the output (unless BackUp() is called).
+  // * It is legal for the returned buffer to have zero size, as long
+  //   as repeatedly calling Next() eventually yields a buffer with non-zero
+  //   size.
+  virtual bool Next(void** data, int* size) = 0;
+
+  // Backs up a number of bytes, so that the end of the last buffer returned
+  // by Next() is not actually written.  This is needed when you finish
+  // writing all the data you want to write, but the last buffer was bigger
+  // than you needed.  You don't want to write a bunch of garbage after the
+  // end of your data, so you use BackUp() to back up.
+  //
+  // Preconditions:
+  // * The last method called must have been Next().
+  // * count must be less than or equal to the size of the last buffer
+  //   returned by Next().
+  // * The caller must not have written anything to the last "count" bytes
+  //   of that buffer.
+  //
+  // Postconditions:
+  // * The last "count" bytes of the last buffer returned by Next() will be
+  //   ignored.
+  virtual void BackUp(int count) = 0;
+
+  // Returns the total number of bytes written since this object was created.
+  virtual int64_t ByteCount() const = 0;
+
+  // Write a given chunk of data to the output.  Some output streams may
+  // implement this in a way that avoids copying. Check AllowsAliasing() before
+  // calling WriteAliasedRaw(). It will GOOGLE_CHECK fail if WriteAliasedRaw() is
+  // called on a stream that does not allow aliasing.
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  virtual bool WriteAliasedRaw(const void* data, int size);
+  virtual bool AllowsAliasing() const { return false; }
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
+};
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream_impl.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream_impl.h
new file mode 100644
index 0000000..a385992
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream_impl.h
@@ -0,0 +1,336 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains common implementations of the interfaces defined in
+// zero_copy_stream.h which are only included in the full (non-lite)
+// protobuf library.  These implementations include Unix file descriptors
+// and C++ iostreams.  See also:  zero_copy_stream_impl_lite.h
+
+#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
+
+
+#include <iosfwd>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// ===================================================================
+
+// A ZeroCopyInputStream which reads from a file descriptor.
+//
+// FileInputStream is preferred over using an ifstream with IstreamInputStream.
+// The latter will introduce an extra layer of buffering, harming performance.
+// Also, it's conceivable that FileInputStream could someday be enhanced
+// to use zero-copy file descriptors on OSs which support them.
+class PROTOBUF_EXPORT FileInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Creates a stream that reads from the given Unix file descriptor.
+  // If a block_size is given, it specifies the number of bytes that
+  // should be read and returned with each call to Next().  Otherwise,
+  // a reasonable default is used.
+  explicit FileInputStream(int file_descriptor, int block_size = -1);
+
+  // Flushes any buffers and closes the underlying file.  Returns false if
+  // an error occurs during the process; use GetErrno() to examine the error.
+  // Even if an error occurs, the file descriptor is closed when this returns.
+  bool Close();
+
+  // By default, the file descriptor is not closed when the stream is
+  // destroyed.  Call SetCloseOnDelete(true) to change that.  WARNING:
+  // This leaves no way for the caller to detect if close() fails.  If
+  // detecting close() errors is important to you, you should arrange
+  // to close the descriptor yourself.
+  void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); }
+
+  // If an I/O error has occurred on this file descriptor, this is the
+  // errno from that error.  Otherwise, this is zero.  Once an error
+  // occurs, the stream is broken and all subsequent operations will
+  // fail.
+  int GetErrno() const { return copying_input_.GetErrno(); }
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  class PROTOBUF_EXPORT CopyingFileInputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingInputStream {
+   public:
+    CopyingFileInputStream(int file_descriptor);
+    ~CopyingFileInputStream() override;
+
+    bool Close();
+    void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
+    int GetErrno() const { return errno_; }
+
+    // implements CopyingInputStream ---------------------------------
+    int Read(void* buffer, int size) override;
+    int Skip(int count) override;
+
+   private:
+    // The file descriptor.
+    const int file_;
+    bool close_on_delete_;
+    bool is_closed_;
+
+    // The errno of the I/O error, if one has occurred.  Otherwise, zero.
+    int errno_;
+
+    // Did we try to seek once and fail?  If so, we assume this file descriptor
+    // doesn't support seeking and won't try again.
+    bool previous_seek_failed_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream);
+  };
+
+  CopyingFileInputStream copying_input_;
+  CopyingInputStreamAdaptor impl_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream which writes to a file descriptor.
+//
+// FileOutputStream is preferred over using an ofstream with
+// OstreamOutputStream.  The latter will introduce an extra layer of buffering,
+// harming performance.  Also, it's conceivable that FileOutputStream could
+// someday be enhanced to use zero-copy file descriptors on OSs which
+// support them.
+class PROTOBUF_EXPORT FileOutputStream PROTOBUF_FUTURE_FINAL
+    : public CopyingOutputStreamAdaptor {
+ public:
+  // Creates a stream that writes to the given Unix file descriptor.
+  // If a block_size is given, it specifies the size of the buffers
+  // that should be returned by Next().  Otherwise, a reasonable default
+  // is used.
+  explicit FileOutputStream(int file_descriptor, int block_size = -1);
+
+  ~FileOutputStream() override;
+
+  // Flushes any buffers and closes the underlying file.  Returns false if
+  // an error occurs during the process; use GetErrno() to examine the error.
+  // Even if an error occurs, the file descriptor is closed when this returns.
+  bool Close();
+
+  // By default, the file descriptor is not closed when the stream is
+  // destroyed.  Call SetCloseOnDelete(true) to change that.  WARNING:
+  // This leaves no way for the caller to detect if close() fails.  If
+  // detecting close() errors is important to you, you should arrange
+  // to close the descriptor yourself.
+  void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); }
+
+  // If an I/O error has occurred on this file descriptor, this is the
+  // errno from that error.  Otherwise, this is zero.  Once an error
+  // occurs, the stream is broken and all subsequent operations will
+  // fail.
+  int GetErrno() const { return copying_output_.GetErrno(); }
+
+ private:
+  class PROTOBUF_EXPORT CopyingFileOutputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingOutputStream {
+   public:
+    CopyingFileOutputStream(int file_descriptor);
+    ~CopyingFileOutputStream() override;
+
+    bool Close();
+    void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
+    int GetErrno() const { return errno_; }
+
+    // implements CopyingOutputStream --------------------------------
+    bool Write(const void* buffer, int size) override;
+
+   private:
+    // The file descriptor.
+    const int file_;
+    bool close_on_delete_;
+    bool is_closed_;
+
+    // The errno of the I/O error, if one has occurred.  Otherwise, zero.
+    int errno_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream);
+  };
+
+  CopyingFileOutputStream copying_output_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which reads from a C++ istream.
+//
+// Note that for reading files (or anything represented by a file descriptor),
+// FileInputStream is more efficient.
+class PROTOBUF_EXPORT IstreamInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Creates a stream that reads from the given C++ istream.
+  // If a block_size is given, it specifies the number of bytes that
+  // should be read and returned with each call to Next().  Otherwise,
+  // a reasonable default is used.
+  explicit IstreamInputStream(std::istream* stream, int block_size = -1);
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  class PROTOBUF_EXPORT CopyingIstreamInputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingInputStream {
+   public:
+    CopyingIstreamInputStream(std::istream* input);
+    ~CopyingIstreamInputStream() override;
+
+    // implements CopyingInputStream ---------------------------------
+    int Read(void* buffer, int size) override;
+    // (We use the default implementation of Skip().)
+
+   private:
+    // The stream.
+    std::istream* input_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream);
+  };
+
+  CopyingIstreamInputStream copying_input_;
+  CopyingInputStreamAdaptor impl_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream which writes to a C++ ostream.
+//
+// Note that for writing files (or anything represented by a file descriptor),
+// FileOutputStream is more efficient.
+class PROTOBUF_EXPORT OstreamOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Creates a stream that writes to the given C++ ostream.
+  // If a block_size is given, it specifies the size of the buffers
+  // that should be returned by Next().  Otherwise, a reasonable default
+  // is used.
+  explicit OstreamOutputStream(std::ostream* stream, int block_size = -1);
+  ~OstreamOutputStream() override;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  class PROTOBUF_EXPORT CopyingOstreamOutputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingOutputStream {
+   public:
+    CopyingOstreamOutputStream(std::ostream* output);
+    ~CopyingOstreamOutputStream() override;
+
+    // implements CopyingOutputStream --------------------------------
+    bool Write(const void* buffer, int size) override;
+
+   private:
+    // The stream.
+    std::ostream* output_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream);
+  };
+
+  CopyingOstreamOutputStream copying_output_;
+  CopyingOutputStreamAdaptor impl_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which reads from several other streams in sequence.
+// ConcatenatingInputStream is unable to distinguish between end-of-stream
+// and read errors in the underlying streams, so it assumes any errors mean
+// end-of-stream.  So, if the underlying streams fail for any other reason,
+// ConcatenatingInputStream may do odd things.  It is suggested that you do
+// not use ConcatenatingInputStream on streams that might produce read errors
+// other than end-of-stream.
+class PROTOBUF_EXPORT ConcatenatingInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // All streams passed in as well as the array itself must remain valid
+  // until the ConcatenatingInputStream is destroyed.
+  ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count);
+  ~ConcatenatingInputStream() override = default;
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+
+ private:
+  // As streams are retired, streams_ is incremented and count_ is
+  // decremented.
+  ZeroCopyInputStream* const* streams_;
+  int stream_count_;
+  int64_t bytes_retired_;  // Bytes read from previous streams.
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
+};
+
+// ===================================================================
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream_impl_lite.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream_impl_lite.h
new file mode 100644
index 0000000..cbda328
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -0,0 +1,413 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains common implementations of the interfaces defined in
+// zero_copy_stream.h which are included in the "lite" protobuf library.
+// These implementations cover I/O on raw arrays and strings, as well as
+// adaptors which make it easy to implement streams based on traditional
+// streams.  Of course, many users will probably want to write their own
+// implementations of these interfaces specific to the particular I/O
+// abstractions they prefer to use, but these should cover the most common
+// cases.
+
+#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
+#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
+
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// ===================================================================
+
+// A ZeroCopyInputStream backed by an in-memory array of bytes.
+class PROTOBUF_EXPORT ArrayInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  // Create an InputStream that returns the bytes pointed to by "data".
+  // "data" remains the property of the caller but must remain valid until
+  // the stream is destroyed.  If a block_size is given, calls to Next()
+  // will return data blocks no larger than the given size.  Otherwise, the
+  // first call to Next() returns the entire array.  block_size is mainly
+  // useful for testing; in production you would probably never want to set
+  // it.
+  ArrayInputStream(const void* data, int size, int block_size = -1);
+  ~ArrayInputStream() override = default;
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+
+ private:
+  const uint8_t* const data_;  // The byte array.
+  const int size_;           // Total size of the array.
+  const int block_size_;     // How many bytes to return at a time.
+
+  int position_;
+  int last_returned_size_;  // How many bytes we returned last time Next()
+                            // was called (used for error checking only).
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream backed by an in-memory array of bytes.
+class PROTOBUF_EXPORT ArrayOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Create an OutputStream that writes to the bytes pointed to by "data".
+  // "data" remains the property of the caller but must remain valid until
+  // the stream is destroyed.  If a block_size is given, calls to Next()
+  // will return data blocks no larger than the given size.  Otherwise, the
+  // first call to Next() returns the entire array.  block_size is mainly
+  // useful for testing; in production you would probably never want to set
+  // it.
+  ArrayOutputStream(void* data, int size, int block_size = -1);
+  ~ArrayOutputStream() override = default;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  uint8_t* const data_;     // The byte array.
+  const int size_;        // Total size of the array.
+  const int block_size_;  // How many bytes to return at a time.
+
+  int position_;
+  int last_returned_size_;  // How many bytes we returned last time Next()
+                            // was called (used for error checking only).
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream);
+};
+
+// ===================================================================
+
+// A ZeroCopyOutputStream which appends bytes to a string.
+class PROTOBUF_EXPORT StringOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
+ public:
+  // Create a StringOutputStream which appends bytes to the given string.
+  // The string remains property of the caller, but it is mutated in arbitrary
+  // ways and MUST NOT be accessed in any way until you're done with the
+  // stream. Either be sure there's no further usage, or (safest) destroy the
+  // stream before using the contents.
+  //
+  // Hint:  If you call target->reserve(n) before creating the stream,
+  //   the first call to Next() will return at least n bytes of buffer
+  //   space.
+  explicit StringOutputStream(std::string* target);
+  ~StringOutputStream() override = default;
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  static constexpr size_t kMinimumSize = 16;
+
+  std::string* target_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
+};
+
+// Note:  There is no StringInputStream.  Instead, just create an
+// ArrayInputStream as follows:
+//   ArrayInputStream input(str.data(), str.size());
+
+// ===================================================================
+
+// A generic traditional input stream interface.
+//
+// Lots of traditional input streams (e.g. file descriptors, C stdio
+// streams, and C++ iostreams) expose an interface where every read
+// involves copying bytes into a buffer.  If you want to take such an
+// interface and make a ZeroCopyInputStream based on it, simply implement
+// CopyingInputStream and then use CopyingInputStreamAdaptor.
+//
+// CopyingInputStream implementations should avoid buffering if possible.
+// CopyingInputStreamAdaptor does its own buffering and will read data
+// in large blocks.
+class PROTOBUF_EXPORT CopyingInputStream {
+ public:
+  virtual ~CopyingInputStream() {}
+
+  // Reads up to "size" bytes into the given buffer.  Returns the number of
+  // bytes read.  Read() waits until at least one byte is available, or
+  // returns zero if no bytes will ever become available (EOF), or -1 if a
+  // permanent read error occurred.
+  virtual int Read(void* buffer, int size) = 0;
+
+  // Skips the next "count" bytes of input.  Returns the number of bytes
+  // actually skipped.  This will always be exactly equal to "count" unless
+  // EOF was reached or a permanent read error occurred.
+  //
+  // The default implementation just repeatedly calls Read() into a scratch
+  // buffer.
+  virtual int Skip(int count);
+};
+
+// A ZeroCopyInputStream which reads from a CopyingInputStream.  This is
+// useful for implementing ZeroCopyInputStreams that read from traditional
+// streams.  Note that this class is not really zero-copy.
+//
+// If you want to read from file descriptors or C++ istreams, this is
+// already implemented for you:  use FileInputStream or IstreamInputStream
+// respectively.
+class PROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
+ public:
+  // Creates a stream that reads from the given CopyingInputStream.
+  // If a block_size is given, it specifies the number of bytes that
+  // should be read and returned with each call to Next().  Otherwise,
+  // a reasonable default is used.  The caller retains ownership of
+  // copying_stream unless SetOwnsCopyingStream(true) is called.
+  explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream,
+                                     int block_size = -1);
+  ~CopyingInputStreamAdaptor() override;
+
+  // Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to
+  // delete the underlying CopyingInputStream when it is destroyed.
+  void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+ private:
+  // Insures that buffer_ is not NULL.
+  void AllocateBufferIfNeeded();
+  // Frees the buffer and resets buffer_used_.
+  void FreeBuffer();
+
+  // The underlying copying stream.
+  CopyingInputStream* copying_stream_;
+  bool owns_copying_stream_;
+
+  // True if we have seen a permanent error from the underlying stream.
+  bool failed_;
+
+  // The current position of copying_stream_, relative to the point where
+  // we started reading.
+  int64_t position_;
+
+  // Data is read into this buffer.  It may be NULL if no buffer is currently
+  // in use.  Otherwise, it points to an array of size buffer_size_.
+  std::unique_ptr<uint8_t[]> buffer_;
+  const int buffer_size_;
+
+  // Number of valid bytes currently in the buffer (i.e. the size last
+  // returned by Next()).  0 <= buffer_used_ <= buffer_size_.
+  int buffer_used_;
+
+  // Number of bytes in the buffer which were backed up over by a call to
+  // BackUp().  These need to be returned again.
+  // 0 <= backup_bytes_ <= buffer_used_
+  int backup_bytes_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor);
+};
+
+// ===================================================================
+
+// A generic traditional output stream interface.
+//
+// Lots of traditional output streams (e.g. file descriptors, C stdio
+// streams, and C++ iostreams) expose an interface where every write
+// involves copying bytes from a buffer.  If you want to take such an
+// interface and make a ZeroCopyOutputStream based on it, simply implement
+// CopyingOutputStream and then use CopyingOutputStreamAdaptor.
+//
+// CopyingOutputStream implementations should avoid buffering if possible.
+// CopyingOutputStreamAdaptor does its own buffering and will write data
+// in large blocks.
+class PROTOBUF_EXPORT CopyingOutputStream {
+ public:
+  virtual ~CopyingOutputStream() {}
+
+  // Writes "size" bytes from the given buffer to the output.  Returns true
+  // if successful, false on a write error.
+  virtual bool Write(const void* buffer, int size) = 0;
+};
+
+// A ZeroCopyOutputStream which writes to a CopyingOutputStream.  This is
+// useful for implementing ZeroCopyOutputStreams that write to traditional
+// streams.  Note that this class is not really zero-copy.
+//
+// If you want to write to file descriptors or C++ ostreams, this is
+// already implemented for you:  use FileOutputStream or OstreamOutputStream
+// respectively.
+class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
+ public:
+  // Creates a stream that writes to the given Unix file descriptor.
+  // If a block_size is given, it specifies the size of the buffers
+  // that should be returned by Next().  Otherwise, a reasonable default
+  // is used.
+  explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream,
+                                      int block_size = -1);
+  ~CopyingOutputStreamAdaptor() override;
+
+  // Writes all pending data to the underlying stream.  Returns false if a
+  // write error occurred on the underlying stream.  (The underlying
+  // stream itself is not necessarily flushed.)
+  bool Flush();
+
+  // Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to
+  // delete the underlying CopyingOutputStream when it is destroyed.
+  void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
+
+  // implements ZeroCopyOutputStream ---------------------------------
+  bool Next(void** data, int* size) override;
+  void BackUp(int count) override;
+  int64_t ByteCount() const override;
+  bool WriteAliasedRaw(const void* data, int size) override;
+  bool AllowsAliasing() const override { return true; }
+
+ private:
+  // Write the current buffer, if it is present.
+  bool WriteBuffer();
+  // Insures that buffer_ is not NULL.
+  void AllocateBufferIfNeeded();
+  // Frees the buffer.
+  void FreeBuffer();
+
+  // The underlying copying stream.
+  CopyingOutputStream* copying_stream_;
+  bool owns_copying_stream_;
+
+  // True if we have seen a permanent error from the underlying stream.
+  bool failed_;
+
+  // The current position of copying_stream_, relative to the point where
+  // we started writing.
+  int64_t position_;
+
+  // Data is written from this buffer.  It may be NULL if no buffer is
+  // currently in use.  Otherwise, it points to an array of size buffer_size_.
+  std::unique_ptr<uint8_t[]> buffer_;
+  const int buffer_size_;
+
+  // Number of valid bytes currently in the buffer (i.e. the size last
+  // returned by Next()).  When BackUp() is called, we just reduce this.
+  // 0 <= buffer_used_ <= buffer_size_.
+  int buffer_used_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor);
+};
+
+// ===================================================================
+
+// A ZeroCopyInputStream which wraps some other stream and limits it to
+// a particular byte count.
+class PROTOBUF_EXPORT LimitingInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
+ public:
+  LimitingInputStream(ZeroCopyInputStream* input, int64_t limit);
+  ~LimitingInputStream() override;
+
+  // implements ZeroCopyInputStream ----------------------------------
+  bool Next(const void** data, int* size) override;
+  void BackUp(int count) override;
+  bool Skip(int count) override;
+  int64_t ByteCount() const override;
+
+
+ private:
+  ZeroCopyInputStream* input_;
+  int64_t limit_;  // Decreases as we go, becomes negative if we overshoot.
+  int64_t prior_bytes_read_;  // Bytes read on underlying stream at construction
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
+};
+
+
+// ===================================================================
+
+// mutable_string_data() and as_string_data() are workarounds to improve
+// the performance of writing new data to an existing string.  Unfortunately
+// the methods provided by the string class are suboptimal, and using memcpy()
+// is mildly annoying because it requires its pointer args to be non-NULL even
+// if we ask it to copy 0 bytes.  Furthermore, string_as_array() has the
+// property that it always returns NULL if its arg is the empty string, exactly
+// what we want to avoid if we're using it in conjunction with memcpy()!
+// With C++11, the desired memcpy() boils down to memcpy(..., &(*s)[0], size),
+// where s is a string*.  Without C++11, &(*s)[0] is not guaranteed to be safe,
+// so we use string_as_array(), and live with the extra logic that tests whether
+// *s is empty.
+
+// Return a pointer to mutable characters underlying the given string.  The
+// return value is valid until the next time the string is resized.  We
+// trust the caller to treat the return value as an array of length s->size().
+inline char* mutable_string_data(std::string* s) {
+  // This should be simpler & faster than string_as_array() because the latter
+  // is guaranteed to return NULL when *s is empty, so it has to check for that.
+  return &(*s)[0];
+}
+
+// as_string_data(s) is equivalent to
+//  ({ char* p = mutable_string_data(s); make_pair(p, p != NULL); })
+// Sometimes it's faster: in some scenarios p cannot be NULL, and then the
+// code can avoid that check.
+inline std::pair<char*, bool> as_string_data(std::string* s) {
+  char* p = mutable_string_data(s);
+  return std::make_pair(p, true);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map.h
new file mode 100644
index 0000000..008c192
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map.h
@@ -0,0 +1,1448 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines the map container and its helpers to support protobuf maps.
+//
+// The Map and MapIterator types are provided by this header file.
+// Please avoid using other types defined here, unless they are public
+// types within Map or MapIterator, such as Map::value_type.
+
+#ifndef GOOGLE_PROTOBUF_MAP_H__
+#define GOOGLE_PROTOBUF_MAP_H__
+
+
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <limits>  // To support Visual Studio 2008
+#include <map>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#if defined(__cpp_lib_string_view)
+#include <string_view>
+#endif  // defined(__cpp_lib_string_view)
+
+#if !defined(GOOGLE_PROTOBUF_NO_RDTSC) && defined(__APPLE__)
+#include <mach/mach_time.h>
+#endif
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_enum_util.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/hash.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+template <typename Key, typename T>
+class Map;
+
+class MapIterator;
+
+template <typename Enum>
+struct is_proto_enum;
+
+namespace internal {
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+class MapFieldLite;
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+class MapField;
+
+template <typename Key, typename T>
+class TypeDefinedMapFieldBase;
+
+class DynamicMapField;
+
+class GeneratedMessageReflection;
+
+// re-implement std::allocator to use arena allocator for memory allocation.
+// Used for Map implementation. Users should not use this class
+// directly.
+template <typename U>
+class MapAllocator {
+ public:
+  using value_type = U;
+  using pointer = value_type*;
+  using const_pointer = const value_type*;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  constexpr MapAllocator() : arena_(nullptr) {}
+  explicit constexpr MapAllocator(Arena* arena) : arena_(arena) {}
+  template <typename X>
+  MapAllocator(const MapAllocator<X>& allocator)  // NOLINT(runtime/explicit)
+      : arena_(allocator.arena()) {}
+
+  // MapAllocator does not support alignments beyond 8. Technically we should
+  // support up to std::max_align_t, but this fails with ubsan and tcmalloc
+  // debug allocation logic which assume 8 as default alignment.
+  static_assert(alignof(value_type) <= 8, "");
+
+  pointer allocate(size_type n, const void* /* hint */ = nullptr) {
+    // If arena is not given, malloc needs to be called which doesn't
+    // construct element object.
+    if (arena_ == nullptr) {
+      return static_cast<pointer>(::operator new(n * sizeof(value_type)));
+    } else {
+      return reinterpret_cast<pointer>(
+          Arena::CreateArray<uint8_t>(arena_, n * sizeof(value_type)));
+    }
+  }
+
+  void deallocate(pointer p, size_type n) {
+    if (arena_ == nullptr) {
+      internal::SizedDelete(p, n * sizeof(value_type));
+    }
+  }
+
+#if !defined(GOOGLE_PROTOBUF_OS_APPLE) && !defined(GOOGLE_PROTOBUF_OS_NACL) && \
+    !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN)
+  template <class NodeType, class... Args>
+  void construct(NodeType* p, Args&&... args) {
+    // Clang 3.6 doesn't compile static casting to void* directly. (Issue
+    // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall
+    // not cast away constness". So first the maybe const pointer is casted to
+    // const void* and after the const void* is const casted.
+    new (const_cast<void*>(static_cast<const void*>(p)))
+        NodeType(std::forward<Args>(args)...);
+  }
+
+  template <class NodeType>
+  void destroy(NodeType* p) {
+    p->~NodeType();
+  }
+#else
+  void construct(pointer p, const_reference t) { new (p) value_type(t); }
+
+  void destroy(pointer p) { p->~value_type(); }
+#endif
+
+  template <typename X>
+  struct rebind {
+    using other = MapAllocator<X>;
+  };
+
+  template <typename X>
+  bool operator==(const MapAllocator<X>& other) const {
+    return arena_ == other.arena_;
+  }
+
+  template <typename X>
+  bool operator!=(const MapAllocator<X>& other) const {
+    return arena_ != other.arena_;
+  }
+
+  // To support Visual Studio 2008
+  size_type max_size() const {
+    // parentheses around (std::...:max) prevents macro warning of max()
+    return (std::numeric_limits<size_type>::max)();
+  }
+
+  // To support gcc-4.4, which does not properly
+  // support templated friend classes
+  Arena* arena() const { return arena_; }
+
+ private:
+  using DestructorSkippable_ = void;
+  Arena* arena_;
+};
+
+template <typename T>
+using KeyForTree =
+    typename std::conditional<std::is_scalar<T>::value, T,
+                              std::reference_wrapper<const T>>::type;
+
+// Default case: Not transparent.
+// We use std::hash<key_type>/std::less<key_type> and all the lookup functions
+// only accept `key_type`.
+template <typename key_type>
+struct TransparentSupport {
+  using hash = std::hash<key_type>;
+  using less = std::less<key_type>;
+
+  static bool Equals(const key_type& a, const key_type& b) { return a == b; }
+
+  template <typename K>
+  using key_arg = key_type;
+};
+
+#if defined(__cpp_lib_string_view)
+// If std::string_view is available, we add transparent support for std::string
+// keys. We use std::hash<std::string_view> as it supports the input types we
+// care about. The lookup functions accept arbitrary `K`. This will include any
+// key type that is convertible to std::string_view.
+template <>
+struct TransparentSupport<std::string> {
+  static std::string_view ImplicitConvert(std::string_view str) { return str; }
+  // If the element is not convertible to std::string_view, try to convert to
+  // std::string first.
+  // The template makes this overload lose resolution when both have the same
+  // rank otherwise.
+  template <typename = void>
+  static std::string_view ImplicitConvert(const std::string& str) {
+    return str;
+  }
+
+  struct hash : private std::hash<std::string_view> {
+    using is_transparent = void;
+
+    template <typename T>
+    size_t operator()(const T& str) const {
+      return base()(ImplicitConvert(str));
+    }
+
+   private:
+    const std::hash<std::string_view>& base() const { return *this; }
+  };
+  struct less {
+    using is_transparent = void;
+
+    template <typename T, typename U>
+    bool operator()(const T& t, const U& u) const {
+      return ImplicitConvert(t) < ImplicitConvert(u);
+    }
+  };
+
+  template <typename T, typename U>
+  static bool Equals(const T& t, const U& u) {
+    return ImplicitConvert(t) == ImplicitConvert(u);
+  }
+
+  template <typename K>
+  using key_arg = K;
+};
+#endif  // defined(__cpp_lib_string_view)
+
+template <typename Key>
+using TreeForMap =
+    std::map<KeyForTree<Key>, void*, typename TransparentSupport<Key>::less,
+             MapAllocator<std::pair<const KeyForTree<Key>, void*>>>;
+
+inline bool TableEntryIsEmpty(void* const* table, size_t b) {
+  return table[b] == nullptr;
+}
+inline bool TableEntryIsNonEmptyList(void* const* table, size_t b) {
+  return table[b] != nullptr && table[b] != table[b ^ 1];
+}
+inline bool TableEntryIsTree(void* const* table, size_t b) {
+  return !TableEntryIsEmpty(table, b) && !TableEntryIsNonEmptyList(table, b);
+}
+inline bool TableEntryIsList(void* const* table, size_t b) {
+  return !TableEntryIsTree(table, b);
+}
+
+// This captures all numeric types.
+inline size_t MapValueSpaceUsedExcludingSelfLong(bool) { return 0; }
+inline size_t MapValueSpaceUsedExcludingSelfLong(const std::string& str) {
+  return StringSpaceUsedExcludingSelfLong(str);
+}
+template <typename T,
+          typename = decltype(std::declval<const T&>().SpaceUsedLong())>
+size_t MapValueSpaceUsedExcludingSelfLong(const T& message) {
+  return message.SpaceUsedLong() - sizeof(T);
+}
+
+constexpr size_t kGlobalEmptyTableSize = 1;
+PROTOBUF_EXPORT extern void* const kGlobalEmptyTable[kGlobalEmptyTableSize];
+
+// Space used for the table, trees, and nodes.
+// Does not include the indirect space used. Eg the data of a std::string.
+template <typename Key>
+PROTOBUF_NOINLINE size_t SpaceUsedInTable(void** table, size_t num_buckets,
+                                          size_t num_elements,
+                                          size_t sizeof_node) {
+  size_t size = 0;
+  // The size of the table.
+  size += sizeof(void*) * num_buckets;
+  // All the nodes.
+  size += sizeof_node * num_elements;
+  // For each tree, count the overhead of the those nodes.
+  // Two buckets at a time because we only care about trees.
+  for (size_t b = 0; b < num_buckets; b += 2) {
+    if (internal::TableEntryIsTree(table, b)) {
+      using Tree = TreeForMap<Key>;
+      Tree* tree = static_cast<Tree*>(table[b]);
+      // Estimated cost of the red-black tree nodes, 3 pointers plus a
+      // bool (plus alignment, so 4 pointers).
+      size += tree->size() *
+              (sizeof(typename Tree::value_type) + sizeof(void*) * 4);
+    }
+  }
+  return size;
+}
+
+template <typename Map,
+          typename = typename std::enable_if<
+              !std::is_scalar<typename Map::key_type>::value ||
+              !std::is_scalar<typename Map::mapped_type>::value>::type>
+size_t SpaceUsedInValues(const Map* map) {
+  size_t size = 0;
+  for (const auto& v : *map) {
+    size += internal::MapValueSpaceUsedExcludingSelfLong(v.first) +
+            internal::MapValueSpaceUsedExcludingSelfLong(v.second);
+  }
+  return size;
+}
+
+inline size_t SpaceUsedInValues(const void*) { return 0; }
+
+}  // namespace internal
+
+// This is the class for Map's internal value_type. Instead of using
+// std::pair as value_type, we use this class which provides us more control of
+// its process of construction and destruction.
+template <typename Key, typename T>
+struct PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG MapPair {
+  using first_type = const Key;
+  using second_type = T;
+
+  MapPair(const Key& other_first, const T& other_second)
+      : first(other_first), second(other_second) {}
+  explicit MapPair(const Key& other_first) : first(other_first), second() {}
+  explicit MapPair(Key&& other_first)
+      : first(std::move(other_first)), second() {}
+  MapPair(const MapPair& other) : first(other.first), second(other.second) {}
+
+  ~MapPair() {}
+
+  // Implicitly convertible to std::pair of compatible types.
+  template <typename T1, typename T2>
+  operator std::pair<T1, T2>() const {  // NOLINT(runtime/explicit)
+    return std::pair<T1, T2>(first, second);
+  }
+
+  const Key first;
+  T second;
+
+ private:
+  friend class Arena;
+  friend class Map<Key, T>;
+};
+
+// Map is an associative container type used to store protobuf map
+// fields.  Each Map instance may or may not use a different hash function, a
+// different iteration order, and so on.  E.g., please don't examine
+// implementation details to decide if the following would work:
+//  Map<int, int> m0, m1;
+//  m0[0] = m1[0] = m0[1] = m1[1] = 0;
+//  assert(m0.begin()->first == m1.begin()->first);  // Bug!
+//
+// Map's interface is similar to std::unordered_map, except that Map is not
+// designed to play well with exceptions.
+template <typename Key, typename T>
+class Map {
+ public:
+  using key_type = Key;
+  using mapped_type = T;
+  using value_type = MapPair<Key, T>;
+
+  using pointer = value_type*;
+  using const_pointer = const value_type*;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+
+  using size_type = size_t;
+  using hasher = typename internal::TransparentSupport<Key>::hash;
+
+  constexpr Map() : elements_(nullptr) {}
+  explicit Map(Arena* arena) : elements_(arena) {}
+
+  Map(const Map& other) : Map() { insert(other.begin(), other.end()); }
+
+  Map(Map&& other) noexcept : Map() {
+    if (other.arena() != nullptr) {
+      *this = other;
+    } else {
+      swap(other);
+    }
+  }
+
+  Map& operator=(Map&& other) noexcept {
+    if (this != &other) {
+      if (arena() != other.arena()) {
+        *this = other;
+      } else {
+        swap(other);
+      }
+    }
+    return *this;
+  }
+
+  template <class InputIt>
+  Map(const InputIt& first, const InputIt& last) : Map() {
+    insert(first, last);
+  }
+
+  ~Map() {}
+
+ private:
+  using Allocator = internal::MapAllocator<void*>;
+
+  // InnerMap is a generic hash-based map.  It doesn't contain any
+  // protocol-buffer-specific logic.  It is a chaining hash map with the
+  // additional feature that some buckets can be converted to use an ordered
+  // container.  This ensures O(lg n) bounds on find, insert, and erase, while
+  // avoiding the overheads of ordered containers most of the time.
+  //
+  // The implementation doesn't need the full generality of unordered_map,
+  // and it doesn't have it.  More bells and whistles can be added as needed.
+  // Some implementation details:
+  // 1. The hash function has type hasher and the equality function
+  //    equal_to<Key>.  We inherit from hasher to save space
+  //    (empty-base-class optimization).
+  // 2. The number of buckets is a power of two.
+  // 3. Buckets are converted to trees in pairs: if we convert bucket b then
+  //    buckets b and b^1 will share a tree.  Invariant: buckets b and b^1 have
+  //    the same non-null value iff they are sharing a tree.  (An alternative
+  //    implementation strategy would be to have a tag bit per bucket.)
+  // 4. As is typical for hash_map and such, the Keys and Values are always
+  //    stored in linked list nodes.  Pointers to elements are never invalidated
+  //    until the element is deleted.
+  // 5. The trees' payload type is pointer to linked-list node.  Tree-converting
+  //    a bucket doesn't copy Key-Value pairs.
+  // 6. Once we've tree-converted a bucket, it is never converted back. However,
+  //    the items a tree contains may wind up assigned to trees or lists upon a
+  //    rehash.
+  // 7. The code requires no C++ features from C++14 or later.
+  // 8. Mutations to a map do not invalidate the map's iterators, pointers to
+  //    elements, or references to elements.
+  // 9. Except for erase(iterator), any non-const method can reorder iterators.
+  // 10. InnerMap uses KeyForTree<Key> when using the Tree representation, which
+  //    is either `Key`, if Key is a scalar, or `reference_wrapper<const Key>`
+  //    otherwise. This avoids unnecessary copies of string keys, for example.
+  class InnerMap : private hasher {
+   public:
+    explicit constexpr InnerMap(Arena* arena)
+        : hasher(),
+          num_elements_(0),
+          num_buckets_(internal::kGlobalEmptyTableSize),
+          seed_(0),
+          index_of_first_non_null_(internal::kGlobalEmptyTableSize),
+          table_(const_cast<void**>(internal::kGlobalEmptyTable)),
+          alloc_(arena) {}
+
+    ~InnerMap() {
+      if (alloc_.arena() == nullptr &&
+          num_buckets_ != internal::kGlobalEmptyTableSize) {
+        clear();
+        Dealloc<void*>(table_, num_buckets_);
+      }
+    }
+
+   private:
+    enum { kMinTableSize = 8 };
+
+    // Linked-list nodes, as one would expect for a chaining hash table.
+    struct Node {
+      value_type kv;
+      Node* next;
+    };
+
+    // Trees. The payload type is a copy of Key, so that we can query the tree
+    // with Keys that are not in any particular data structure.
+    // The value is a void* pointing to Node. We use void* instead of Node* to
+    // avoid code bloat. That way there is only one instantiation of the tree
+    // class per key type.
+    using Tree = internal::TreeForMap<Key>;
+    using TreeIterator = typename Tree::iterator;
+
+    static Node* NodeFromTreeIterator(TreeIterator it) {
+      return static_cast<Node*>(it->second);
+    }
+
+    // iterator and const_iterator are instantiations of iterator_base.
+    template <typename KeyValueType>
+    class iterator_base {
+     public:
+      using reference = KeyValueType&;
+      using pointer = KeyValueType*;
+
+      // Invariants:
+      // node_ is always correct. This is handy because the most common
+      // operations are operator* and operator-> and they only use node_.
+      // When node_ is set to a non-null value, all the other non-const fields
+      // are updated to be correct also, but those fields can become stale
+      // if the underlying map is modified.  When those fields are needed they
+      // are rechecked, and updated if necessary.
+      iterator_base() : node_(nullptr), m_(nullptr), bucket_index_(0) {}
+
+      explicit iterator_base(const InnerMap* m) : m_(m) {
+        SearchFrom(m->index_of_first_non_null_);
+      }
+
+      // Any iterator_base can convert to any other.  This is overkill, and we
+      // rely on the enclosing class to use it wisely.  The standard "iterator
+      // can convert to const_iterator" is OK but the reverse direction is not.
+      template <typename U>
+      explicit iterator_base(const iterator_base<U>& it)
+          : node_(it.node_), m_(it.m_), bucket_index_(it.bucket_index_) {}
+
+      iterator_base(Node* n, const InnerMap* m, size_type index)
+          : node_(n), m_(m), bucket_index_(index) {}
+
+      iterator_base(TreeIterator tree_it, const InnerMap* m, size_type index)
+          : node_(NodeFromTreeIterator(tree_it)), m_(m), bucket_index_(index) {
+        // Invariant: iterators that use buckets with trees have an even
+        // bucket_index_.
+        GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0u);
+      }
+
+      // Advance through buckets, looking for the first that isn't empty.
+      // If nothing non-empty is found then leave node_ == nullptr.
+      void SearchFrom(size_type start_bucket) {
+        GOOGLE_DCHECK(m_->index_of_first_non_null_ == m_->num_buckets_ ||
+               m_->table_[m_->index_of_first_non_null_] != nullptr);
+        node_ = nullptr;
+        for (bucket_index_ = start_bucket; bucket_index_ < m_->num_buckets_;
+             bucket_index_++) {
+          if (m_->TableEntryIsNonEmptyList(bucket_index_)) {
+            node_ = static_cast<Node*>(m_->table_[bucket_index_]);
+            break;
+          } else if (m_->TableEntryIsTree(bucket_index_)) {
+            Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
+            GOOGLE_DCHECK(!tree->empty());
+            node_ = NodeFromTreeIterator(tree->begin());
+            break;
+          }
+        }
+      }
+
+      reference operator*() const { return node_->kv; }
+      pointer operator->() const { return &(operator*()); }
+
+      friend bool operator==(const iterator_base& a, const iterator_base& b) {
+        return a.node_ == b.node_;
+      }
+      friend bool operator!=(const iterator_base& a, const iterator_base& b) {
+        return a.node_ != b.node_;
+      }
+
+      iterator_base& operator++() {
+        if (node_->next == nullptr) {
+          TreeIterator tree_it;
+          const bool is_list = revalidate_if_necessary(&tree_it);
+          if (is_list) {
+            SearchFrom(bucket_index_ + 1);
+          } else {
+            GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0u);
+            Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
+            if (++tree_it == tree->end()) {
+              SearchFrom(bucket_index_ + 2);
+            } else {
+              node_ = NodeFromTreeIterator(tree_it);
+            }
+          }
+        } else {
+          node_ = node_->next;
+        }
+        return *this;
+      }
+
+      iterator_base operator++(int /* unused */) {
+        iterator_base tmp = *this;
+        ++*this;
+        return tmp;
+      }
+
+      // Assumes node_ and m_ are correct and non-null, but other fields may be
+      // stale.  Fix them as needed.  Then return true iff node_ points to a
+      // Node in a list.  If false is returned then *it is modified to be
+      // a valid iterator for node_.
+      bool revalidate_if_necessary(TreeIterator* it) {
+        GOOGLE_DCHECK(node_ != nullptr && m_ != nullptr);
+        // Force bucket_index_ to be in range.
+        bucket_index_ &= (m_->num_buckets_ - 1);
+        // Common case: the bucket we think is relevant points to node_.
+        if (m_->table_[bucket_index_] == static_cast<void*>(node_)) return true;
+        // Less common: the bucket is a linked list with node_ somewhere in it,
+        // but not at the head.
+        if (m_->TableEntryIsNonEmptyList(bucket_index_)) {
+          Node* l = static_cast<Node*>(m_->table_[bucket_index_]);
+          while ((l = l->next) != nullptr) {
+            if (l == node_) {
+              return true;
+            }
+          }
+        }
+        // Well, bucket_index_ still might be correct, but probably
+        // not.  Revalidate just to be sure.  This case is rare enough that we
+        // don't worry about potential optimizations, such as having a custom
+        // find-like method that compares Node* instead of the key.
+        iterator_base i(m_->find(node_->kv.first, it));
+        bucket_index_ = i.bucket_index_;
+        return m_->TableEntryIsList(bucket_index_);
+      }
+
+      Node* node_;
+      const InnerMap* m_;
+      size_type bucket_index_;
+    };
+
+   public:
+    using iterator = iterator_base<value_type>;
+    using const_iterator = iterator_base<const value_type>;
+
+    Arena* arena() const { return alloc_.arena(); }
+
+    void Swap(InnerMap* other) {
+      std::swap(num_elements_, other->num_elements_);
+      std::swap(num_buckets_, other->num_buckets_);
+      std::swap(seed_, other->seed_);
+      std::swap(index_of_first_non_null_, other->index_of_first_non_null_);
+      std::swap(table_, other->table_);
+      std::swap(alloc_, other->alloc_);
+    }
+
+    iterator begin() { return iterator(this); }
+    iterator end() { return iterator(); }
+    const_iterator begin() const { return const_iterator(this); }
+    const_iterator end() const { return const_iterator(); }
+
+    void clear() {
+      for (size_type b = 0; b < num_buckets_; b++) {
+        if (TableEntryIsNonEmptyList(b)) {
+          Node* node = static_cast<Node*>(table_[b]);
+          table_[b] = nullptr;
+          do {
+            Node* next = node->next;
+            DestroyNode(node);
+            node = next;
+          } while (node != nullptr);
+        } else if (TableEntryIsTree(b)) {
+          Tree* tree = static_cast<Tree*>(table_[b]);
+          GOOGLE_DCHECK(table_[b] == table_[b + 1] && (b & 1) == 0);
+          table_[b] = table_[b + 1] = nullptr;
+          typename Tree::iterator tree_it = tree->begin();
+          do {
+            Node* node = NodeFromTreeIterator(tree_it);
+            typename Tree::iterator next = tree_it;
+            ++next;
+            tree->erase(tree_it);
+            DestroyNode(node);
+            tree_it = next;
+          } while (tree_it != tree->end());
+          DestroyTree(tree);
+          b++;
+        }
+      }
+      num_elements_ = 0;
+      index_of_first_non_null_ = num_buckets_;
+    }
+
+    const hasher& hash_function() const { return *this; }
+
+    static size_type max_size() {
+      return static_cast<size_type>(1) << (sizeof(void**) >= 8 ? 60 : 28);
+    }
+    size_type size() const { return num_elements_; }
+    bool empty() const { return size() == 0; }
+
+    template <typename K>
+    iterator find(const K& k) {
+      return iterator(FindHelper(k).first);
+    }
+
+    template <typename K>
+    const_iterator find(const K& k) const {
+      return FindHelper(k).first;
+    }
+
+    // Inserts a new element into the container if there is no element with the
+    // key in the container.
+    // The new element is:
+    //  (1) Constructed in-place with the given args, if mapped_type is not
+    //      arena constructible.
+    //  (2) Constructed in-place with the arena and then assigned with a
+    //      mapped_type temporary constructed with the given args, otherwise.
+    template <typename K, typename... Args>
+    std::pair<iterator, bool> try_emplace(K&& k, Args&&... args) {
+      return ArenaAwareTryEmplace(Arena::is_arena_constructable<mapped_type>(),
+                                  std::forward<K>(k),
+                                  std::forward<Args>(args)...);
+    }
+
+    // Inserts the key into the map, if not present. In that case, the value
+    // will be value initialized.
+    template <typename K>
+    std::pair<iterator, bool> insert(K&& k) {
+      return try_emplace(std::forward<K>(k));
+    }
+
+    template <typename K>
+    value_type& operator[](K&& k) {
+      return *try_emplace(std::forward<K>(k)).first;
+    }
+
+    void erase(iterator it) {
+      GOOGLE_DCHECK_EQ(it.m_, this);
+      typename Tree::iterator tree_it;
+      const bool is_list = it.revalidate_if_necessary(&tree_it);
+      size_type b = it.bucket_index_;
+      Node* const item = it.node_;
+      if (is_list) {
+        GOOGLE_DCHECK(TableEntryIsNonEmptyList(b));
+        Node* head = static_cast<Node*>(table_[b]);
+        head = EraseFromLinkedList(item, head);
+        table_[b] = static_cast<void*>(head);
+      } else {
+        GOOGLE_DCHECK(TableEntryIsTree(b));
+        Tree* tree = static_cast<Tree*>(table_[b]);
+        tree->erase(tree_it);
+        if (tree->empty()) {
+          // Force b to be the minimum of b and b ^ 1.  This is important
+          // only because we want index_of_first_non_null_ to be correct.
+          b &= ~static_cast<size_type>(1);
+          DestroyTree(tree);
+          table_[b] = table_[b + 1] = nullptr;
+        }
+      }
+      DestroyNode(item);
+      --num_elements_;
+      if (PROTOBUF_PREDICT_FALSE(b == index_of_first_non_null_)) {
+        while (index_of_first_non_null_ < num_buckets_ &&
+               table_[index_of_first_non_null_] == nullptr) {
+          ++index_of_first_non_null_;
+        }
+      }
+    }
+
+    size_t SpaceUsedInternal() const {
+      return internal::SpaceUsedInTable<Key>(table_, num_buckets_,
+                                             num_elements_, sizeof(Node));
+    }
+
+   private:
+    template <typename K, typename... Args>
+    std::pair<iterator, bool> TryEmplaceInternal(K&& k, Args&&... args) {
+      std::pair<const_iterator, size_type> p = FindHelper(k);
+      // Case 1: key was already present.
+      if (p.first.node_ != nullptr)
+        return std::make_pair(iterator(p.first), false);
+      // Case 2: insert.
+      if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
+        p = FindHelper(k);
+      }
+      const size_type b = p.second;  // bucket number
+      // If K is not key_type, make the conversion to key_type explicit.
+      using TypeToInit = typename std::conditional<
+          std::is_same<typename std::decay<K>::type, key_type>::value, K&&,
+          key_type>::type;
+      Node* node = Alloc<Node>(1);
+      // Even when arena is nullptr, CreateInArenaStorage is still used to
+      // ensure the arena of submessage will be consistent. Otherwise,
+      // submessage may have its own arena when message-owned arena is enabled.
+      // Note: This only works if `Key` is not arena constructible.
+      Arena::CreateInArenaStorage(const_cast<Key*>(&node->kv.first),
+                                  alloc_.arena(),
+                                  static_cast<TypeToInit>(std::forward<K>(k)));
+      // Note: if `T` is arena constructible, `Args` needs to be empty.
+      Arena::CreateInArenaStorage(&node->kv.second, alloc_.arena(),
+                                  std::forward<Args>(args)...);
+
+      iterator result = InsertUnique(b, node);
+      ++num_elements_;
+      return std::make_pair(result, true);
+    }
+
+    // A helper function to perform an assignment of `mapped_type`.
+    // If the first argument is true, then it is a regular assignment.
+    // Otherwise, we first create a temporary and then perform an assignment.
+    template <typename V>
+    static void AssignMapped(std::true_type, mapped_type& mapped, V&& v) {
+      mapped = std::forward<V>(v);
+    }
+    template <typename... Args>
+    static void AssignMapped(std::false_type, mapped_type& mapped,
+                             Args&&... args) {
+      mapped = mapped_type(std::forward<Args>(args)...);
+    }
+
+    // Case 1: `mapped_type` is arena constructible. A temporary object is
+    // created and then (if `Args` are not empty) assigned to a mapped value
+    // that was created with the arena.
+    template <typename K>
+    std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k) {
+      // case 1.1: "default" constructed (e.g. from arena only).
+      return TryEmplaceInternal(std::forward<K>(k));
+    }
+    template <typename K, typename... Args>
+    std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k,
+                                                   Args&&... args) {
+      // case 1.2: "default" constructed + copy/move assignment
+      auto p = TryEmplaceInternal(std::forward<K>(k));
+      if (p.second) {
+        AssignMapped(std::is_same<void(typename std::decay<Args>::type...),
+                                  void(mapped_type)>(),
+                     p.first->second, std::forward<Args>(args)...);
+      }
+      return p;
+    }
+    // Case 2: `mapped_type` is not arena constructible. Using in-place
+    // construction.
+    template <typename... Args>
+    std::pair<iterator, bool> ArenaAwareTryEmplace(std::false_type,
+                                                   Args&&... args) {
+      return TryEmplaceInternal(std::forward<Args>(args)...);
+    }
+
+    const_iterator find(const Key& k, TreeIterator* it) const {
+      return FindHelper(k, it).first;
+    }
+    template <typename K>
+    std::pair<const_iterator, size_type> FindHelper(const K& k) const {
+      return FindHelper(k, nullptr);
+    }
+    template <typename K>
+    std::pair<const_iterator, size_type> FindHelper(const K& k,
+                                                    TreeIterator* it) const {
+      size_type b = BucketNumber(k);
+      if (TableEntryIsNonEmptyList(b)) {
+        Node* node = static_cast<Node*>(table_[b]);
+        do {
+          if (internal::TransparentSupport<Key>::Equals(node->kv.first, k)) {
+            return std::make_pair(const_iterator(node, this, b), b);
+          } else {
+            node = node->next;
+          }
+        } while (node != nullptr);
+      } else if (TableEntryIsTree(b)) {
+        GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]);
+        b &= ~static_cast<size_t>(1);
+        Tree* tree = static_cast<Tree*>(table_[b]);
+        auto tree_it = tree->find(k);
+        if (tree_it != tree->end()) {
+          if (it != nullptr) *it = tree_it;
+          return std::make_pair(const_iterator(tree_it, this, b), b);
+        }
+      }
+      return std::make_pair(end(), b);
+    }
+
+    // Insert the given Node in bucket b.  If that would make bucket b too big,
+    // and bucket b is not a tree, create a tree for buckets b and b^1 to share.
+    // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct
+    // bucket.  num_elements_ is not modified.
+    iterator InsertUnique(size_type b, Node* node) {
+      GOOGLE_DCHECK(index_of_first_non_null_ == num_buckets_ ||
+             table_[index_of_first_non_null_] != nullptr);
+      // In practice, the code that led to this point may have already
+      // determined whether we are inserting into an empty list, a short list,
+      // or whatever.  But it's probably cheap enough to recompute that here;
+      // it's likely that we're inserting into an empty or short list.
+      iterator result;
+      GOOGLE_DCHECK(find(node->kv.first) == end());
+      if (TableEntryIsEmpty(b)) {
+        result = InsertUniqueInList(b, node);
+      } else if (TableEntryIsNonEmptyList(b)) {
+        if (PROTOBUF_PREDICT_FALSE(TableEntryIsTooLong(b))) {
+          TreeConvert(b);
+          result = InsertUniqueInTree(b, node);
+          GOOGLE_DCHECK_EQ(result.bucket_index_, b & ~static_cast<size_type>(1));
+        } else {
+          // Insert into a pre-existing list.  This case cannot modify
+          // index_of_first_non_null_, so we skip the code to update it.
+          return InsertUniqueInList(b, node);
+        }
+      } else {
+        // Insert into a pre-existing tree.  This case cannot modify
+        // index_of_first_non_null_, so we skip the code to update it.
+        return InsertUniqueInTree(b, node);
+      }
+      // parentheses around (std::min) prevents macro expansion of min(...)
+      index_of_first_non_null_ =
+          (std::min)(index_of_first_non_null_, result.bucket_index_);
+      return result;
+    }
+
+    // Returns whether we should insert after the head of the list. For
+    // non-optimized builds, we randomly decide whether to insert right at the
+    // head of the list or just after the head. This helps add a little bit of
+    // non-determinism to the map ordering.
+    bool ShouldInsertAfterHead(void* node) {
+#ifdef NDEBUG
+      (void)node;
+      return false;
+#else
+      // Doing modulo with a prime mixes the bits more.
+      return (reinterpret_cast<uintptr_t>(node) ^ seed_) % 13 > 6;
+#endif
+    }
+
+    // Helper for InsertUnique.  Handles the case where bucket b is a
+    // not-too-long linked list.
+    iterator InsertUniqueInList(size_type b, Node* node) {
+      if (table_[b] != nullptr && ShouldInsertAfterHead(node)) {
+        Node* first = static_cast<Node*>(table_[b]);
+        node->next = first->next;
+        first->next = node;
+        return iterator(node, this, b);
+      }
+
+      node->next = static_cast<Node*>(table_[b]);
+      table_[b] = static_cast<void*>(node);
+      return iterator(node, this, b);
+    }
+
+    // Helper for InsertUnique.  Handles the case where bucket b points to a
+    // Tree.
+    iterator InsertUniqueInTree(size_type b, Node* node) {
+      GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]);
+      // Maintain the invariant that node->next is null for all Nodes in Trees.
+      node->next = nullptr;
+      return iterator(
+          static_cast<Tree*>(table_[b])->insert({node->kv.first, node}).first,
+          this, b & ~static_cast<size_t>(1));
+    }
+
+    // Returns whether it did resize.  Currently this is only used when
+    // num_elements_ increases, though it could be used in other situations.
+    // It checks for load too low as well as load too high: because any number
+    // of erases can occur between inserts, the load could be as low as 0 here.
+    // Resizing to a lower size is not always helpful, but failing to do so can
+    // destroy the expected big-O bounds for some operations. By having the
+    // policy that sometimes we resize down as well as up, clients can easily
+    // keep O(size()) = O(number of buckets) if they want that.
+    bool ResizeIfLoadIsOutOfRange(size_type new_size) {
+      const size_type kMaxMapLoadTimes16 = 12;  // controls RAM vs CPU tradeoff
+      const size_type hi_cutoff = num_buckets_ * kMaxMapLoadTimes16 / 16;
+      const size_type lo_cutoff = hi_cutoff / 4;
+      // We don't care how many elements are in trees.  If a lot are,
+      // we may resize even though there are many empty buckets.  In
+      // practice, this seems fine.
+      if (PROTOBUF_PREDICT_FALSE(new_size >= hi_cutoff)) {
+        if (num_buckets_ <= max_size() / 2) {
+          Resize(num_buckets_ * 2);
+          return true;
+        }
+      } else if (PROTOBUF_PREDICT_FALSE(new_size <= lo_cutoff &&
+                                        num_buckets_ > kMinTableSize)) {
+        size_type lg2_of_size_reduction_factor = 1;
+        // It's possible we want to shrink a lot here... size() could even be 0.
+        // So, estimate how much to shrink by making sure we don't shrink so
+        // much that we would need to grow the table after a few inserts.
+        const size_type hypothetical_size = new_size * 5 / 4 + 1;
+        while ((hypothetical_size << lg2_of_size_reduction_factor) <
+               hi_cutoff) {
+          ++lg2_of_size_reduction_factor;
+        }
+        size_type new_num_buckets = std::max<size_type>(
+            kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor);
+        if (new_num_buckets != num_buckets_) {
+          Resize(new_num_buckets);
+          return true;
+        }
+      }
+      return false;
+    }
+
+    // Resize to the given number of buckets.
+    void Resize(size_t new_num_buckets) {
+      if (num_buckets_ == internal::kGlobalEmptyTableSize) {
+        // This is the global empty array.
+        // Just overwrite with a new one. No need to transfer or free anything.
+        num_buckets_ = index_of_first_non_null_ = kMinTableSize;
+        table_ = CreateEmptyTable(num_buckets_);
+        seed_ = Seed();
+        return;
+      }
+
+      GOOGLE_DCHECK_GE(new_num_buckets, kMinTableSize);
+      void** const old_table = table_;
+      const size_type old_table_size = num_buckets_;
+      num_buckets_ = new_num_buckets;
+      table_ = CreateEmptyTable(num_buckets_);
+      const size_type start = index_of_first_non_null_;
+      index_of_first_non_null_ = num_buckets_;
+      for (size_type i = start; i < old_table_size; i++) {
+        if (internal::TableEntryIsNonEmptyList(old_table, i)) {
+          TransferList(old_table, i);
+        } else if (internal::TableEntryIsTree(old_table, i)) {
+          TransferTree(old_table, i++);
+        }
+      }
+      Dealloc<void*>(old_table, old_table_size);
+    }
+
+    void TransferList(void* const* table, size_type index) {
+      Node* node = static_cast<Node*>(table[index]);
+      do {
+        Node* next = node->next;
+        InsertUnique(BucketNumber(node->kv.first), node);
+        node = next;
+      } while (node != nullptr);
+    }
+
+    void TransferTree(void* const* table, size_type index) {
+      Tree* tree = static_cast<Tree*>(table[index]);
+      typename Tree::iterator tree_it = tree->begin();
+      do {
+        InsertUnique(BucketNumber(std::cref(tree_it->first).get()),
+                     NodeFromTreeIterator(tree_it));
+      } while (++tree_it != tree->end());
+      DestroyTree(tree);
+    }
+
+    Node* EraseFromLinkedList(Node* item, Node* head) {
+      if (head == item) {
+        return head->next;
+      } else {
+        head->next = EraseFromLinkedList(item, head->next);
+        return head;
+      }
+    }
+
+    bool TableEntryIsEmpty(size_type b) const {
+      return internal::TableEntryIsEmpty(table_, b);
+    }
+    bool TableEntryIsNonEmptyList(size_type b) const {
+      return internal::TableEntryIsNonEmptyList(table_, b);
+    }
+    bool TableEntryIsTree(size_type b) const {
+      return internal::TableEntryIsTree(table_, b);
+    }
+    bool TableEntryIsList(size_type b) const {
+      return internal::TableEntryIsList(table_, b);
+    }
+
+    void TreeConvert(size_type b) {
+      GOOGLE_DCHECK(!TableEntryIsTree(b) && !TableEntryIsTree(b ^ 1));
+      Tree* tree =
+          Arena::Create<Tree>(alloc_.arena(), typename Tree::key_compare(),
+                              typename Tree::allocator_type(alloc_));
+      size_type count = CopyListToTree(b, tree) + CopyListToTree(b ^ 1, tree);
+      GOOGLE_DCHECK_EQ(count, tree->size());
+      table_[b] = table_[b ^ 1] = static_cast<void*>(tree);
+    }
+
+    // Copy a linked list in the given bucket to a tree.
+    // Returns the number of things it copied.
+    size_type CopyListToTree(size_type b, Tree* tree) {
+      size_type count = 0;
+      Node* node = static_cast<Node*>(table_[b]);
+      while (node != nullptr) {
+        tree->insert({node->kv.first, node});
+        ++count;
+        Node* next = node->next;
+        node->next = nullptr;
+        node = next;
+      }
+      return count;
+    }
+
+    // Return whether table_[b] is a linked list that seems awfully long.
+    // Requires table_[b] to point to a non-empty linked list.
+    bool TableEntryIsTooLong(size_type b) {
+      const size_type kMaxLength = 8;
+      size_type count = 0;
+      Node* node = static_cast<Node*>(table_[b]);
+      do {
+        ++count;
+        node = node->next;
+      } while (node != nullptr);
+      // Invariant: no linked list ever is more than kMaxLength in length.
+      GOOGLE_DCHECK_LE(count, kMaxLength);
+      return count >= kMaxLength;
+    }
+
+    template <typename K>
+    size_type BucketNumber(const K& k) const {
+      // We xor the hash value against the random seed so that we effectively
+      // have a random hash function.
+      uint64_t h = hash_function()(k) ^ seed_;
+
+      // We use the multiplication method to determine the bucket number from
+      // the hash value. The constant kPhi (suggested by Knuth) is roughly
+      // (sqrt(5) - 1) / 2 * 2^64.
+      constexpr uint64_t kPhi = uint64_t{0x9e3779b97f4a7c15};
+      return ((kPhi * h) >> 32) & (num_buckets_ - 1);
+    }
+
+    // Return a power of two no less than max(kMinTableSize, n).
+    // Assumes either n < kMinTableSize or n is a power of two.
+    size_type TableSize(size_type n) {
+      return n < static_cast<size_type>(kMinTableSize)
+                 ? static_cast<size_type>(kMinTableSize)
+                 : n;
+    }
+
+    // Use alloc_ to allocate an array of n objects of type U.
+    template <typename U>
+    U* Alloc(size_type n) {
+      using alloc_type = typename Allocator::template rebind<U>::other;
+      return alloc_type(alloc_).allocate(n);
+    }
+
+    // Use alloc_ to deallocate an array of n objects of type U.
+    template <typename U>
+    void Dealloc(U* t, size_type n) {
+      using alloc_type = typename Allocator::template rebind<U>::other;
+      alloc_type(alloc_).deallocate(t, n);
+    }
+
+    void DestroyNode(Node* node) {
+      if (alloc_.arena() == nullptr) {
+        delete node;
+      }
+    }
+
+    void DestroyTree(Tree* tree) {
+      if (alloc_.arena() == nullptr) {
+        delete tree;
+      }
+    }
+
+    void** CreateEmptyTable(size_type n) {
+      GOOGLE_DCHECK(n >= kMinTableSize);
+      GOOGLE_DCHECK_EQ(n & (n - 1), 0u);
+      void** result = Alloc<void*>(n);
+      memset(result, 0, n * sizeof(result[0]));
+      return result;
+    }
+
+    // Return a randomish value.
+    size_type Seed() const {
+      // We get a little bit of randomness from the address of the map. The
+      // lower bits are not very random, due to alignment, so we discard them
+      // and shift the higher bits into their place.
+      size_type s = reinterpret_cast<uintptr_t>(this) >> 4;
+#if !defined(GOOGLE_PROTOBUF_NO_RDTSC)
+#if defined(__APPLE__)
+      // Use a commpage-based fast time function on Apple environments (MacOS,
+      // iOS, tvOS, watchOS, etc).
+      s += mach_absolute_time();
+#elif defined(__x86_64__) && defined(__GNUC__)
+      uint32_t hi, lo;
+      asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+      s += ((static_cast<uint64_t>(hi) << 32) | lo);
+#elif defined(__aarch64__) && defined(__GNUC__)
+      // There is no rdtsc on ARMv8. CNTVCT_EL0 is the virtual counter of the
+      // system timer. It runs at a different frequency than the CPU's, but is
+      // the best source of time-based entropy we get.
+      uint64_t virtual_timer_value;
+      asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
+      s += virtual_timer_value;
+#endif
+#endif  // !defined(GOOGLE_PROTOBUF_NO_RDTSC)
+      return s;
+    }
+
+    friend class Arena;
+    using InternalArenaConstructable_ = void;
+    using DestructorSkippable_ = void;
+
+    size_type num_elements_;
+    size_type num_buckets_;
+    size_type seed_;
+    size_type index_of_first_non_null_;
+    void** table_;  // an array with num_buckets_ entries
+    Allocator alloc_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap);
+  };  // end of class InnerMap
+
+  template <typename LookupKey>
+  using key_arg = typename internal::TransparentSupport<
+      key_type>::template key_arg<LookupKey>;
+
+ public:
+  // Iterators
+  class const_iterator {
+    using InnerIt = typename InnerMap::const_iterator;
+
+   public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = typename Map::value_type;
+    using difference_type = ptrdiff_t;
+    using pointer = const value_type*;
+    using reference = const value_type&;
+
+    const_iterator() {}
+    explicit const_iterator(const InnerIt& it) : it_(it) {}
+
+    const_reference operator*() const { return *it_; }
+    const_pointer operator->() const { return &(operator*()); }
+
+    const_iterator& operator++() {
+      ++it_;
+      return *this;
+    }
+    const_iterator operator++(int) { return const_iterator(it_++); }
+
+    friend bool operator==(const const_iterator& a, const const_iterator& b) {
+      return a.it_ == b.it_;
+    }
+    friend bool operator!=(const const_iterator& a, const const_iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    InnerIt it_;
+  };
+
+  class iterator {
+    using InnerIt = typename InnerMap::iterator;
+
+   public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = typename Map::value_type;
+    using difference_type = ptrdiff_t;
+    using pointer = value_type*;
+    using reference = value_type&;
+
+    iterator() {}
+    explicit iterator(const InnerIt& it) : it_(it) {}
+
+    reference operator*() const { return *it_; }
+    pointer operator->() const { return &(operator*()); }
+
+    iterator& operator++() {
+      ++it_;
+      return *this;
+    }
+    iterator operator++(int) { return iterator(it_++); }
+
+    // Allow implicit conversion to const_iterator.
+    operator const_iterator() const {  // NOLINT(runtime/explicit)
+      return const_iterator(typename InnerMap::const_iterator(it_));
+    }
+
+    friend bool operator==(const iterator& a, const iterator& b) {
+      return a.it_ == b.it_;
+    }
+    friend bool operator!=(const iterator& a, const iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    friend class Map;
+
+    InnerIt it_;
+  };
+
+  iterator begin() { return iterator(elements_.begin()); }
+  iterator end() { return iterator(elements_.end()); }
+  const_iterator begin() const { return const_iterator(elements_.begin()); }
+  const_iterator end() const { return const_iterator(elements_.end()); }
+  const_iterator cbegin() const { return begin(); }
+  const_iterator cend() const { return end(); }
+
+  // Capacity
+  size_type size() const { return elements_.size(); }
+  bool empty() const { return size() == 0; }
+
+  // Element access
+  template <typename K = key_type>
+  T& operator[](const key_arg<K>& key) {
+    return elements_[key].second;
+  }
+  template <
+      typename K = key_type,
+      // Disable for integral types to reduce code bloat.
+      typename = typename std::enable_if<!std::is_integral<K>::value>::type>
+  T& operator[](key_arg<K>&& key) {
+    return elements_[std::forward<K>(key)].second;
+  }
+
+  template <typename K = key_type>
+  const T& at(const key_arg<K>& key) const {
+    const_iterator it = find(key);
+    GOOGLE_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
+    return it->second;
+  }
+
+  template <typename K = key_type>
+  T& at(const key_arg<K>& key) {
+    iterator it = find(key);
+    GOOGLE_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
+    return it->second;
+  }
+
+  // Lookup
+  template <typename K = key_type>
+  size_type count(const key_arg<K>& key) const {
+    return find(key) == end() ? 0 : 1;
+  }
+
+  template <typename K = key_type>
+  const_iterator find(const key_arg<K>& key) const {
+    return const_iterator(elements_.find(key));
+  }
+  template <typename K = key_type>
+  iterator find(const key_arg<K>& key) {
+    return iterator(elements_.find(key));
+  }
+
+  template <typename K = key_type>
+  bool contains(const key_arg<K>& key) const {
+    return find(key) != end();
+  }
+
+  template <typename K = key_type>
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_arg<K>& key) const {
+    const_iterator it = find(key);
+    if (it == end()) {
+      return std::pair<const_iterator, const_iterator>(it, it);
+    } else {
+      const_iterator begin = it++;
+      return std::pair<const_iterator, const_iterator>(begin, it);
+    }
+  }
+
+  template <typename K = key_type>
+  std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
+    iterator it = find(key);
+    if (it == end()) {
+      return std::pair<iterator, iterator>(it, it);
+    } else {
+      iterator begin = it++;
+      return std::pair<iterator, iterator>(begin, it);
+    }
+  }
+
+  // insert
+  template <typename K, typename... Args>
+  std::pair<iterator, bool> try_emplace(K&& k, Args&&... args) {
+    auto p =
+        elements_.try_emplace(std::forward<K>(k), std::forward<Args>(args)...);
+    return std::pair<iterator, bool>(iterator(p.first), p.second);
+  }
+  std::pair<iterator, bool> insert(const value_type& value) {
+    return try_emplace(value.first, value.second);
+  }
+  std::pair<iterator, bool> insert(value_type&& value) {
+    return try_emplace(value.first, std::move(value.second));
+  }
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    return insert(value_type(std::forward<Args>(args)...));
+  }
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (; first != last; ++first) {
+      try_emplace(first->first, first->second);
+    }
+  }
+  void insert(std::initializer_list<value_type> values) {
+    insert(values.begin(), values.end());
+  }
+
+  // Erase and clear
+  template <typename K = key_type>
+  size_type erase(const key_arg<K>& key) {
+    iterator it = find(key);
+    if (it == end()) {
+      return 0;
+    } else {
+      erase(it);
+      return 1;
+    }
+  }
+  iterator erase(iterator pos) {
+    iterator i = pos++;
+    elements_.erase(i.it_);
+    return pos;
+  }
+  void erase(iterator first, iterator last) {
+    while (first != last) {
+      first = erase(first);
+    }
+  }
+  void clear() { elements_.clear(); }
+
+  // Assign
+  Map& operator=(const Map& other) {
+    if (this != &other) {
+      clear();
+      insert(other.begin(), other.end());
+    }
+    return *this;
+  }
+
+  void swap(Map& other) {
+    if (arena() == other.arena()) {
+      InternalSwap(other);
+    } else {
+      // TODO(zuguang): optimize this. The temporary copy can be allocated
+      // in the same arena as the other message, and the "other = copy" can
+      // be replaced with the fast-path swap above.
+      Map copy = *this;
+      *this = other;
+      other = copy;
+    }
+  }
+
+  void InternalSwap(Map& other) { elements_.Swap(&other.elements_); }
+
+  // Access to hasher.  Currently this returns a copy, but it may
+  // be modified to return a const reference in the future.
+  hasher hash_function() const { return elements_.hash_function(); }
+
+  size_t SpaceUsedExcludingSelfLong() const {
+    if (empty()) return 0;
+    return elements_.SpaceUsedInternal() + internal::SpaceUsedInValues(this);
+  }
+
+ private:
+  Arena* arena() const { return elements_.arena(); }
+  InnerMap elements_;
+
+  friend class Arena;
+  using InternalArenaConstructable_ = void;
+  using DestructorSkippable_ = void;
+  template <typename Derived, typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type>
+  friend class internal::MapFieldLite;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_entry.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_entry.h
new file mode 100644
index 0000000..536dec9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_entry.h
@@ -0,0 +1,134 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_H__
+
+#include <google/protobuf/port.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class Arena;
+namespace internal {
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapField;
+}
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// MapEntry is the returned google::protobuf::Message when calling AddMessage of
+// google::protobuf::Reflection. In order to let it work with generated message
+// reflection, its in-memory type is the same as generated message with the same
+// fields. However, in order to decide the in-memory type of key/value, we need
+// to know both their cpp type in generated api and proto type. In
+// implementation, all in-memory types have related wire format functions to
+// support except ArenaStringPtr. Therefore, we need to define another type with
+// supporting wire format functions. Since this type is only used as return type
+// of MapEntry accessors, it's named MapEntry accessor type.
+//
+// cpp type:               the type visible to users in public API.
+// proto type:             WireFormatLite::FieldType of the field.
+// in-memory type:         type of the data member used to stored this field.
+// MapEntry accessor type: type used in MapEntry getters/mutators to access the
+//                         field.
+//
+// cpp type | proto type  | in-memory type | MapEntry accessor type
+// int32_t    TYPE_INT32    int32_t          int32_t
+// int32_t    TYPE_FIXED32  int32_t          int32_t
+// string     TYPE_STRING   ArenaStringPtr   string
+// FooEnum    TYPE_ENUM     int              int
+// FooMessage TYPE_MESSAGE  FooMessage*      FooMessage
+//
+// The in-memory types of primitive types can be inferred from its proto type,
+// while we need to explicitly specify the cpp type if proto type is
+// TYPE_MESSAGE to infer the in-memory type.
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntry : public MapEntryImpl<Derived, Message, Key, Value,
+                                     kKeyFieldType, kValueFieldType> {
+ public:
+  constexpr MapEntry() {}
+  explicit MapEntry(Arena* arena)
+      : MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
+                     kValueFieldType>(arena) {}
+  ~MapEntry() override {
+    Message::_internal_metadata_.template Delete<UnknownFieldSet>();
+  }
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+
+  typedef typename MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
+                                kValueFieldType>::KeyTypeHandler KeyTypeHandler;
+  typedef
+      typename MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
+                            kValueFieldType>::ValueTypeHandler ValueTypeHandler;
+  size_t SpaceUsedLong() const override {
+    size_t size = sizeof(Derived);
+    size += KeyTypeHandler::SpaceUsedInMapEntryLong(this->key_);
+    size += ValueTypeHandler::SpaceUsedInMapEntryLong(this->value_);
+    return size;
+  }
+
+ private:
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+  template <typename C, typename K, typename V,
+            WireFormatLite::FieldType k_wire_type, WireFormatLite::FieldType>
+  friend class internal::MapField;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_ENTRY_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_entry_lite.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_entry_lite.h
new file mode 100644
index 0000000..6b08cd9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_entry_lite.h
@@ -0,0 +1,563 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntry;
+template <typename Derived, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapFieldLite;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// MoveHelper::Move is used to set *dest.  It copies *src, or moves it (in
+// the C++11 sense), or swaps it. *src is left in a sane state for
+// subsequent destruction, but shouldn't be used for anything.
+template <bool is_enum, bool is_message, bool is_stringlike, typename T>
+struct MoveHelper {  // primitives
+  static void Move(T* src, T* dest) { *dest = *src; }
+};
+
+template <bool is_message, bool is_stringlike, typename T>
+struct MoveHelper<true, is_message, is_stringlike, T> {  // enums
+  static void Move(T* src, T* dest) { *dest = *src; }
+  // T is an enum here, so allow conversions to and from int.
+  static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
+  static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
+};
+
+template <bool is_stringlike, typename T>
+struct MoveHelper<false, true, is_stringlike, T> {  // messages
+  static void Move(T* src, T* dest) { dest->Swap(src); }
+};
+
+template <typename T>
+struct MoveHelper<false, false, true, T> {  // strings and similar
+  static void Move(T* src, T* dest) {
+    *dest = std::move(*src);
+  }
+};
+
+// MapEntryImpl is used to implement parsing and serialization of map entries.
+// It uses Curious Recursive Template Pattern (CRTP) to provide the type of
+// the eventual code to the template code.
+template <typename Derived, typename Base, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntryImpl : public Base {
+ public:
+  typedef MapEntryFuncs<Key, Value, kKeyFieldType, kValueFieldType> Funcs;
+
+ protected:
+  // Provide utilities to parse/serialize key/value.  Provide utilities to
+  // manipulate internal stored type.
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+
+  // Define internal memory layout. Strings and messages are stored as
+  // pointers, while other types are stored as values.
+  typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
+  typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
+
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type
+  // which will replace Enum with int.
+  typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
+  typedef
+      typename ValueTypeHandler::MapEntryAccessorType ValueMapEntryAccessorType;
+
+  // Constants for field number.
+  static const int kKeyFieldNumber = 1;
+  static const int kValueFieldNumber = 2;
+
+  // Constants for field tag.
+  static const uint8_t kKeyTag =
+      GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType);
+  static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kValueFieldNumber, ValueTypeHandler::kWireType);
+  static const size_t kTagSize = 1;
+
+ public:
+  // Work-around for a compiler bug (see repeated_field.h).
+  typedef void MapEntryHasMergeTypeTrait;
+  typedef Derived EntryType;
+  typedef Key EntryKeyType;
+  typedef Value EntryValueType;
+  static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
+  static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
+
+  constexpr MapEntryImpl()
+      : key_(KeyTypeHandler::Constinit()),
+        value_(ValueTypeHandler::Constinit()),
+        _has_bits_{} {}
+
+  explicit MapEntryImpl(Arena* arena)
+      : Base(arena),
+        key_(KeyTypeHandler::Constinit()),
+        value_(ValueTypeHandler::Constinit()),
+        _has_bits_{} {}
+
+  ~MapEntryImpl() override {
+    if (Base::GetArenaForAllocation() != nullptr) return;
+    KeyTypeHandler::DeleteNoArena(key_);
+    ValueTypeHandler::DeleteNoArena(value_);
+  }
+
+  // accessors ======================================================
+
+  virtual inline const KeyMapEntryAccessorType& key() const {
+    return KeyTypeHandler::GetExternalReference(key_);
+  }
+  virtual inline const ValueMapEntryAccessorType& value() const {
+    return ValueTypeHandler::DefaultIfNotInitialized(value_);
+  }
+  inline KeyMapEntryAccessorType* mutable_key() {
+    set_has_key();
+    return KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
+  }
+  inline ValueMapEntryAccessorType* mutable_value() {
+    set_has_value();
+    return ValueTypeHandler::EnsureMutable(&value_,
+                                           Base::GetArenaForAllocation());
+  }
+
+  // implements MessageLite =========================================
+
+  // MapEntryImpl is for implementation only and this function isn't called
+  // anywhere. Just provide a fake implementation here for MessageLite.
+  std::string GetTypeName() const override { return ""; }
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) override {
+    MergeFromInternal(*::google::protobuf::internal::DownCast<const Derived*>(&other));
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
+    while (!ctx->Done(&ptr)) {
+      uint32_t tag;
+      ptr = ReadTag(ptr, &tag);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (tag == kKeyTag) {
+        set_has_key();
+        KeyMapEntryAccessorType* key = mutable_key();
+        ptr = KeyTypeHandler::Read(ptr, ctx, key);
+        if (!Derived::ValidateKey(key)) return nullptr;
+      } else if (tag == kValueTag) {
+        set_has_value();
+        ValueMapEntryAccessorType* value = mutable_value();
+        ptr = ValueTypeHandler::Read(ptr, ctx, value);
+        if (!Derived::ValidateValue(value)) return nullptr;
+      } else {
+        if (tag == 0 || WireFormatLite::GetTagWireType(tag) ==
+                            WireFormatLite::WIRETYPE_END_GROUP) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        ptr = UnknownFieldParse(tag, static_cast<std::string*>(nullptr), ptr,
+                                ctx);
+      }
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+    return ptr;
+  }
+
+  size_t ByteSizeLong() const override {
+    size_t size = 0;
+    size += kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key()));
+    size += kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value()));
+    return size;
+  }
+
+  ::uint8_t* _InternalSerialize(
+      ::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
+  }
+
+  // Don't override SerializeWithCachedSizesToArray.  Use MessageLite's.
+
+  int GetCachedSize() const override {
+    int size = 0;
+    size += has_key() ? static_cast<int>(kTagSize) +
+                            KeyTypeHandler::GetCachedSize(key())
+                      : 0;
+    size += has_value() ? static_cast<int>(kTagSize) +
+                              ValueTypeHandler::GetCachedSize(value())
+                        : 0;
+    return size;
+  }
+
+  bool IsInitialized() const override {
+    return ValueTypeHandler::IsInitialized(value_);
+  }
+
+  Base* New(Arena* arena) const override {
+    Derived* entry = Arena::CreateMessage<Derived>(arena);
+    return entry;
+  }
+
+ protected:
+  // We can't declare this function directly here as it would hide the other
+  // overload (const Message&).
+  void MergeFromInternal(const MapEntryImpl& from) {
+    if (from._has_bits_[0]) {
+      if (from.has_key()) {
+        KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
+        KeyTypeHandler::Merge(from.key(), &key_, Base::GetArenaForAllocation());
+        set_has_key();
+      }
+      if (from.has_value()) {
+        ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation());
+        ValueTypeHandler::Merge(from.value(), &value_,
+                                Base::GetArenaForAllocation());
+        set_has_value();
+      }
+    }
+  }
+
+ public:
+  void Clear() override {
+    KeyTypeHandler::Clear(&key_, Base::GetArenaForAllocation());
+    ValueTypeHandler::Clear(&value_, Base::GetArenaForAllocation());
+    clear_has_key();
+    clear_has_value();
+  }
+
+  // Parsing using MergePartialFromCodedStream, above, is not as
+  // efficient as it could be.  This helper class provides a speedier way.
+  template <typename MapField, typename Map>
+  class Parser {
+   public:
+    explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
+    ~Parser() {
+      if (entry_ != nullptr && entry_->GetArenaForAllocation() == nullptr)
+        delete entry_;
+    }
+
+    const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+      if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) {
+        ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_);
+        if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateKey(&key_))) {
+          return nullptr;
+        }
+        if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kValueTag)) {
+          typename Map::size_type map_size = map_->size();
+          value_ptr_ = &(*map_)[key_];
+          if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
+            using T =
+                typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type;
+            ptr = ValueTypeHandler::Read(ptr + 1, ctx,
+                                         reinterpret_cast<T>(value_ptr_));
+            if (PROTOBUF_PREDICT_FALSE(!ptr ||
+                                       !Derived::ValidateValue(value_ptr_))) {
+              map_->erase(key_);  // Failure! Undo insertion.
+              return nullptr;
+            }
+            if (PROTOBUF_PREDICT_TRUE(ctx->Done(&ptr))) return ptr;
+            if (!ptr) return nullptr;
+            NewEntry();
+            ValueMover::Move(value_ptr_, entry_->mutable_value());
+            map_->erase(key_);
+            goto move_key;
+          }
+        } else {
+          if (!ptr) return nullptr;
+        }
+        NewEntry();
+      move_key:
+        KeyMover::Move(&key_, entry_->mutable_key());
+      } else {
+        if (!ptr) return nullptr;
+        NewEntry();
+      }
+      ptr = entry_->_InternalParse(ptr, ctx);
+      if (ptr) UseKeyAndValueFromEntry();
+      return ptr;
+    }
+
+    template <typename UnknownType>
+    const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
+                                        bool (*is_valid)(int),
+                                        uint32_t field_num,
+                                        InternalMetadata* metadata) {
+      auto entry = NewEntry();
+      ptr = entry->_InternalParse(ptr, ctx);
+      if (!ptr) return nullptr;
+      if (is_valid(entry->value())) {
+        UseKeyAndValueFromEntry();
+      } else {
+        WriteLengthDelimited(field_num, entry->SerializeAsString(),
+                             metadata->mutable_unknown_fields<UnknownType>());
+      }
+      return ptr;
+    }
+
+    MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); }
+
+    const Key& key() const { return key_; }
+    const Value& value() const { return *value_ptr_; }
+
+    const Key& entry_key() const { return entry_->key(); }
+    const Value& entry_value() const { return entry_->value(); }
+
+   private:
+    void UseKeyAndValueFromEntry() {
+      // Update key_ in case we need it later (because key() is called).
+      // This is potentially inefficient, especially if the key is
+      // expensive to copy (e.g., a long string), but this is a cold
+      // path, so it's not a big deal.
+      key_ = entry_->key();
+      value_ptr_ = &(*map_)[key_];
+      ValueMover::Move(entry_->mutable_value(), value_ptr_);
+    }
+
+    // After reading a key and value successfully, and inserting that data
+    // into map_, we are not at the end of the input.  This is unusual, but
+    // allowed by the spec.
+    bool ReadBeyondKeyValuePair(io::CodedInputStream* input) PROTOBUF_COLD {
+      NewEntry();
+      ValueMover::Move(value_ptr_, entry_->mutable_value());
+      map_->erase(key_);
+      KeyMover::Move(&key_, entry_->mutable_key());
+      const bool result = entry_->MergePartialFromCodedStream(input);
+      if (result) UseKeyAndValueFromEntry();
+      return result;
+    }
+
+    typedef MoveHelper<KeyTypeHandler::kIsEnum, KeyTypeHandler::kIsMessage,
+                       KeyTypeHandler::kWireType ==
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                       Key>
+        KeyMover;
+    typedef MoveHelper<ValueTypeHandler::kIsEnum, ValueTypeHandler::kIsMessage,
+                       ValueTypeHandler::kWireType ==
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                       Value>
+        ValueMover;
+
+    MapField* const mf_;
+    Map* const map_;
+    Key key_;
+    Value* value_ptr_;
+    MapEntryImpl* entry_ = nullptr;
+  };
+
+ protected:
+  void set_has_key() { _has_bits_[0] |= 0x00000001u; }
+  bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
+  void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
+  void set_has_value() { _has_bits_[0] |= 0x00000002u; }
+  bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
+  void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
+
+ public:
+  inline Arena* GetArena() const { return Base::GetArena(); }
+
+ protected:  // Needed for constructing tables
+  KeyOnMemory key_;
+  ValueOnMemory value_;
+  uint32_t _has_bits_[1];
+
+ private:
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  template <typename C, typename K, typename V, WireFormatLite::FieldType,
+            WireFormatLite::FieldType>
+  friend class internal::MapEntry;
+  template <typename C, typename K, typename V, WireFormatLite::FieldType,
+            WireFormatLite::FieldType>
+  friend class internal::MapFieldLite;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl);
+};
+
+template <typename T, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapEntryLite : public MapEntryImpl<T, MessageLite, Key, Value,
+                                         kKeyFieldType, kValueFieldType> {
+ public:
+  typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
+                       kValueFieldType>
+      SuperType;
+  constexpr MapEntryLite() {}
+  explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
+  ~MapEntryLite() override {
+    MessageLite::_internal_metadata_.template Delete<std::string>();
+  }
+  void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
+};
+
+// Helpers for deterministic serialization =============================
+
+// Iterator base for MapSorterFlat and MapSorterPtr.
+template <typename storage_type>
+struct MapSorterIt {
+  storage_type* ptr;
+  MapSorterIt(storage_type* ptr) : ptr(ptr) {}
+  bool operator==(const MapSorterIt& other) const { return ptr == other.ptr; }
+  bool operator!=(const MapSorterIt& other) const { return !(*this == other); }
+  MapSorterIt& operator++() { ++ptr; return *this; }
+  MapSorterIt operator++(int) { auto other = *this; ++ptr; return other; }
+  MapSorterIt operator+(int v) { return MapSorterIt{ptr + v}; }
+};
+
+// MapSorterFlat stores keys inline with pointers to map entries, so that
+// keys can be compared without indirection. This type is used for maps with
+// keys that are not strings.
+template <typename MapT>
+class MapSorterFlat {
+ public:
+  using value_type = typename MapT::value_type;
+  using storage_type = std::pair<typename MapT::key_type, const value_type*>;
+
+  // This const_iterator dereferenes to the map entry stored in the sorting
+  // array pairs. This is the same interface as the Map::const_iterator type,
+  // and allows generated code to use the same loop body with either form:
+  //   for (const auto& entry : map) { ... }
+  //   for (const auto& entry : MapSorterFlat(map)) { ... }
+  struct const_iterator : public MapSorterIt<storage_type> {
+    using pointer = const typename MapT::value_type*;
+    using reference = const typename MapT::value_type&;
+    using MapSorterIt<storage_type>::MapSorterIt;
+
+    pointer operator->() const { return this->ptr->second; }
+    reference operator*() const { return *this->operator->(); }
+  };
+
+  explicit MapSorterFlat(const MapT& m)
+      : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
+    if (!size_) return;
+    storage_type* it = &items_[0];
+    for (const auto& entry : m) {
+      *it++ = {entry.first, &entry};
+    }
+    std::sort(&items_[0], &items_[size_],
+              [](const storage_type& a, const storage_type& b) {
+                return a.first < b.first;
+              });
+  }
+  size_t size() const { return size_; }
+  const_iterator begin() const { return {items_.get()}; }
+  const_iterator end() const { return {items_.get() + size_}; }
+
+ private:
+  size_t size_;
+  std::unique_ptr<storage_type[]> items_;
+};
+
+// MapSorterPtr stores and sorts pointers to map entries. This type is used for
+// maps with keys that are strings.
+template <typename MapT>
+class MapSorterPtr {
+ public:
+  using value_type = typename MapT::value_type;
+  using storage_type = const typename MapT::value_type*;
+
+  // This const_iterator dereferenes the map entry pointer stored in the sorting
+  // array. This is the same interface as the Map::const_iterator type, and
+  // allows generated code to use the same loop body with either form:
+  //   for (const auto& entry : map) { ... }
+  //   for (const auto& entry : MapSorterPtr(map)) { ... }
+  struct const_iterator : public MapSorterIt<storage_type> {
+    using pointer = const typename MapT::value_type*;
+    using reference = const typename MapT::value_type&;
+    using MapSorterIt<storage_type>::MapSorterIt;
+
+    pointer operator->() const { return *this->ptr; }
+    reference operator*() const { return *this->operator->(); }
+  };
+
+  explicit MapSorterPtr(const MapT& m)
+      : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
+    if (!size_) return;
+    storage_type* it = &items_[0];
+    for (const auto& entry : m) {
+      *it++ = &entry;
+    }
+    std::sort(&items_[0], &items_[size_],
+              [](const storage_type& a, const storage_type& b) {
+                return a->first < b->first;
+              });
+  }
+  size_t size() const { return size_; }
+  const_iterator begin() const { return {items_.get()}; }
+  const_iterator end() const { return {items_.get() + size_}; }
+
+ private:
+  size_t size_;
+  std::unique_ptr<storage_type[]> items_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field.h
new file mode 100644
index 0000000..287d58f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field.h
@@ -0,0 +1,946 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_H__
+
+#include <atomic>
+#include <functional>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_entry.h>
+#include <google/protobuf/map_field_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+class DynamicMessage;
+class MapIterator;
+
+// Microsoft compiler complains about non-virtual destructor,
+// even when the destructor is private.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4265)
+#endif  // _MSC_VER
+
+#define TYPE_CHECK(EXPECTEDTYPE, METHOD)                                   \
+  if (type() != EXPECTEDTYPE) {                                            \
+    GOOGLE_LOG(FATAL) << "Protocol Buffer map usage error:\n"                     \
+               << METHOD << " type does not match\n"                       \
+               << "  Expected : "                                          \
+               << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n"       \
+               << "  Actual   : " << FieldDescriptor::CppTypeName(type()); \
+  }
+
+// MapKey is an union type for representing any possible
+// map key.
+class PROTOBUF_EXPORT MapKey {
+ public:
+  MapKey() : type_() {}
+  MapKey(const MapKey& other) : type_() { CopyFrom(other); }
+
+  MapKey& operator=(const MapKey& other) {
+    CopyFrom(other);
+    return *this;
+  }
+
+  ~MapKey() {
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_.Destruct();
+    }
+  }
+
+  FieldDescriptor::CppType type() const {
+    if (type_ == FieldDescriptor::CppType()) {
+      GOOGLE_LOG(FATAL) << "Protocol Buffer map usage error:\n"
+                 << "MapKey::type MapKey is not initialized. "
+                 << "Call set methods to initialize MapKey.";
+    }
+    return type_;
+  }
+
+  void SetInt64Value(int64_t value) {
+    SetType(FieldDescriptor::CPPTYPE_INT64);
+    val_.int64_value_ = value;
+  }
+  void SetUInt64Value(uint64_t value) {
+    SetType(FieldDescriptor::CPPTYPE_UINT64);
+    val_.uint64_value_ = value;
+  }
+  void SetInt32Value(int32_t value) {
+    SetType(FieldDescriptor::CPPTYPE_INT32);
+    val_.int32_value_ = value;
+  }
+  void SetUInt32Value(uint32_t value) {
+    SetType(FieldDescriptor::CPPTYPE_UINT32);
+    val_.uint32_value_ = value;
+  }
+  void SetBoolValue(bool value) {
+    SetType(FieldDescriptor::CPPTYPE_BOOL);
+    val_.bool_value_ = value;
+  }
+  void SetStringValue(std::string val) {
+    SetType(FieldDescriptor::CPPTYPE_STRING);
+    *val_.string_value_.get_mutable() = std::move(val);
+  }
+
+  int64_t GetInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapKey::GetInt64Value");
+    return val_.int64_value_;
+  }
+  uint64_t GetUInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapKey::GetUInt64Value");
+    return val_.uint64_value_;
+  }
+  int32_t GetInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapKey::GetInt32Value");
+    return val_.int32_value_;
+  }
+  uint32_t GetUInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapKey::GetUInt32Value");
+    return val_.uint32_value_;
+  }
+  bool GetBoolValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapKey::GetBoolValue");
+    return val_.bool_value_;
+  }
+  const std::string& GetStringValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, "MapKey::GetStringValue");
+    return val_.string_value_.get();
+  }
+
+  bool operator<(const MapKey& other) const {
+    if (type_ != other.type_) {
+      // We could define a total order that handles this case, but
+      // there currently no need.  So, for now, fail.
+      GOOGLE_LOG(FATAL) << "Unsupported: type mismatch";
+    }
+    switch (type()) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        return false;
+      case FieldDescriptor::CPPTYPE_STRING:
+        return val_.string_value_.get() < other.val_.string_value_.get();
+      case FieldDescriptor::CPPTYPE_INT64:
+        return val_.int64_value_ < other.val_.int64_value_;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return val_.int32_value_ < other.val_.int32_value_;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return val_.uint64_value_ < other.val_.uint64_value_;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return val_.uint32_value_ < other.val_.uint32_value_;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return val_.bool_value_ < other.val_.bool_value_;
+    }
+    return false;
+  }
+
+  bool operator==(const MapKey& other) const {
+    if (type_ != other.type_) {
+      // To be consistent with operator<, we don't allow this either.
+      GOOGLE_LOG(FATAL) << "Unsupported: type mismatch";
+    }
+    switch (type()) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        return val_.string_value_.get() == other.val_.string_value_.get();
+      case FieldDescriptor::CPPTYPE_INT64:
+        return val_.int64_value_ == other.val_.int64_value_;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return val_.int32_value_ == other.val_.int32_value_;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return val_.uint64_value_ == other.val_.uint64_value_;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return val_.uint32_value_ == other.val_.uint32_value_;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return val_.bool_value_ == other.val_.bool_value_;
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return false;
+  }
+
+  void CopyFrom(const MapKey& other) {
+    SetType(other.type());
+    switch (type_) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        *val_.string_value_.get_mutable() = other.val_.string_value_.get();
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        val_.int64_value_ = other.val_.int64_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        val_.int32_value_ = other.val_.int32_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        val_.uint64_value_ = other.val_.uint64_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        val_.uint32_value_ = other.val_.uint32_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        val_.bool_value_ = other.val_.bool_value_;
+        break;
+    }
+  }
+
+ private:
+  template <typename K, typename V>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class ::PROTOBUF_NAMESPACE_ID::MapIterator;
+  friend class internal::DynamicMapField;
+
+  union KeyValue {
+    KeyValue() {}
+    internal::ExplicitlyConstructed<std::string> string_value_;
+    int64_t int64_value_;
+    int32_t int32_value_;
+    uint64_t uint64_value_;
+    uint32_t uint32_value_;
+    bool bool_value_;
+  } val_;
+
+  void SetType(FieldDescriptor::CppType type) {
+    if (type_ == type) return;
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_.Destruct();
+    }
+    type_ = type;
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_.DefaultConstruct();
+    }
+  }
+
+  // type_ is 0 or a valid FieldDescriptor::CppType.
+  // Use "CppType()" to indicate zero.
+  FieldDescriptor::CppType type_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+namespace std {
+template <>
+struct hash<::PROTOBUF_NAMESPACE_ID::MapKey> {
+  size_t operator()(const ::PROTOBUF_NAMESPACE_ID::MapKey& map_key) const {
+    switch (map_key.type()) {
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_DOUBLE:
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_FLOAT:
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_ENUM:
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_STRING:
+        return hash<std::string>()(map_key.GetStringValue());
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_INT64: {
+        auto value = map_key.GetInt64Value();
+        return hash<decltype(value)>()(value);
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_INT32: {
+        auto value = map_key.GetInt32Value();
+        return hash<decltype(value)>()(map_key.GetInt32Value());
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_UINT64: {
+        auto value = map_key.GetUInt64Value();
+        return hash<decltype(value)>()(map_key.GetUInt64Value());
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_UINT32: {
+        auto value = map_key.GetUInt32Value();
+        return hash<decltype(value)>()(map_key.GetUInt32Value());
+      }
+      case ::PROTOBUF_NAMESPACE_ID::FieldDescriptor::CPPTYPE_BOOL: {
+        return hash<bool>()(map_key.GetBoolValue());
+      }
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
+  }
+  bool operator()(const ::PROTOBUF_NAMESPACE_ID::MapKey& map_key1,
+                  const ::PROTOBUF_NAMESPACE_ID::MapKey& map_key2) const {
+    return map_key1 < map_key2;
+  }
+};
+}  // namespace std
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class ContendedMapCleanTest;
+class GeneratedMessageReflection;
+class MapFieldAccessor;
+
+// This class provides access to map field using reflection, which is the same
+// as those provided for RepeatedPtrField<Message>. It is used for internal
+// reflection implementation only. Users should never use this directly.
+class PROTOBUF_EXPORT MapFieldBase {
+ public:
+  MapFieldBase()
+      : arena_(nullptr), repeated_field_(nullptr), state_(STATE_MODIFIED_MAP) {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // Except in MSVC, where we can't have a constinit mutex.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr MapFieldBase(ConstantInitialized)
+      : arena_(nullptr),
+        repeated_field_(nullptr),
+        mutex_(GOOGLE_PROTOBUF_LINKER_INITIALIZED),
+        state_(STATE_MODIFIED_MAP) {}
+  explicit MapFieldBase(Arena* arena)
+      : arena_(arena), repeated_field_(nullptr), state_(STATE_MODIFIED_MAP) {}
+
+ protected:
+  ~MapFieldBase() {  // "protected" stops users from deleting a `MapFieldBase *`
+    GOOGLE_DCHECK(repeated_field_ == nullptr);
+  }
+  void Destruct();
+
+ public:
+  // Returns reference to internal repeated field. Data written using
+  // Map's api prior to calling this function is guarantted to be
+  // included in repeated field.
+  const RepeatedPtrFieldBase& GetRepeatedField() const;
+
+  // Like above. Returns mutable pointer to the internal repeated field.
+  RepeatedPtrFieldBase* MutableRepeatedField();
+
+  // Pure virtual map APIs for Map Reflection.
+  virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
+  virtual bool InsertOrLookupMapValue(const MapKey& map_key,
+                                      MapValueRef* val) = 0;
+  virtual bool LookupMapValue(const MapKey& map_key,
+                              MapValueConstRef* val) const = 0;
+  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
+
+  // Returns whether changes to the map are reflected in the repeated field.
+  bool IsRepeatedFieldValid() const;
+  // Insures operations after won't get executed before calling this.
+  bool IsMapValid() const;
+  virtual bool DeleteMapValue(const MapKey& map_key) = 0;
+  virtual bool EqualIterator(const MapIterator& a,
+                             const MapIterator& b) const = 0;
+  virtual void MapBegin(MapIterator* map_iter) const = 0;
+  virtual void MapEnd(MapIterator* map_iter) const = 0;
+  virtual void MergeFrom(const MapFieldBase& other) = 0;
+  virtual void Swap(MapFieldBase* other);
+  virtual void UnsafeShallowSwap(MapFieldBase* other);
+  // Sync Map with repeated field and returns the size of map.
+  virtual int size() const = 0;
+  virtual void Clear() = 0;
+
+  // Returns the number of bytes used by the repeated field, excluding
+  // sizeof(*this)
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+ protected:
+  // Gets the size of space used by map field.
+  virtual size_t SpaceUsedExcludingSelfNoLock() const;
+
+  // Synchronizes the content in Map to RepeatedPtrField if there is any change
+  // to Map after last synchronization.
+  void SyncRepeatedFieldWithMap() const;
+  virtual void SyncRepeatedFieldWithMapNoLock() const;
+
+  // Synchronizes the content in RepeatedPtrField to Map if there is any change
+  // to RepeatedPtrField after last synchronization.
+  void SyncMapWithRepeatedField() const;
+  virtual void SyncMapWithRepeatedFieldNoLock() const {}
+
+  // Tells MapFieldBase that there is new change to Map.
+  void SetMapDirty();
+
+  // Tells MapFieldBase that there is new change to RepeatedPtrField.
+  void SetRepeatedDirty();
+
+  // Provides derived class the access to repeated field.
+  void* MutableRepeatedPtrField() const;
+
+  void InternalSwap(MapFieldBase* other);
+
+  // Support thread sanitizer (tsan) by making const / mutable races
+  // more apparent.  If one thread calls MutableAccess() while another
+  // thread calls either ConstAccess() or MutableAccess(), on the same
+  // MapFieldBase-derived object, and there is no synchronization going
+  // on between them, tsan will alert.
+#if defined(__SANITIZE_THREAD__) || defined(THREAD_SANITIZER)
+  void ConstAccess() const { GOOGLE_CHECK_EQ(seq1_, seq2_); }
+  void MutableAccess() {
+    if (seq1_ & 1) {
+      seq2_ = ++seq1_;
+    } else {
+      seq1_ = ++seq2_;
+    }
+  }
+  unsigned int seq1_ = 0, seq2_ = 0;
+#else
+  void ConstAccess() const {}
+  void MutableAccess() {}
+#endif
+  enum State {
+    STATE_MODIFIED_MAP = 0,       // map has newly added data that has not been
+                                  // synchronized to repeated field
+    STATE_MODIFIED_REPEATED = 1,  // repeated field has newly added data that
+                                  // has not been synchronized to map
+    CLEAN = 2,                    // data in map and repeated field are same
+  };
+
+  Arena* arena_;
+  mutable RepeatedPtrField<Message>* repeated_field_;
+
+  mutable internal::WrappedMutex
+      mutex_;  // The thread to synchronize map and repeated field
+               // needs to get lock first;
+  mutable std::atomic<State> state_;
+
+ private:
+  friend class ContendedMapCleanTest;
+  friend class GeneratedMessageReflection;
+  friend class MapFieldAccessor;
+  friend class ::PROTOBUF_NAMESPACE_ID::Reflection;
+  friend class ::PROTOBUF_NAMESPACE_ID::DynamicMessage;
+
+  // Virtual helper methods for MapIterator. MapIterator doesn't have the
+  // type helper for key and value. Call these help methods to deal with
+  // different types. Real helper methods are implemented in
+  // TypeDefinedMapFieldBase.
+  friend class ::PROTOBUF_NAMESPACE_ID::MapIterator;
+  // Allocate map<...>::iterator for MapIterator.
+  virtual void InitializeIterator(MapIterator* map_iter) const = 0;
+
+  // DeleteIterator() is called by the destructor of MapIterator only.
+  // It deletes map<...>::iterator for MapIterator.
+  virtual void DeleteIterator(MapIterator* map_iter) const = 0;
+
+  // Copy the map<...>::iterator from other_iterator to
+  // this_iterator.
+  virtual void CopyIterator(MapIterator* this_iterator,
+                            const MapIterator& other_iterator) const = 0;
+
+  // IncreaseIterator() is called by operator++() of MapIterator only.
+  // It implements the ++ operator of MapIterator.
+  virtual void IncreaseIterator(MapIterator* map_iter) const = 0;
+
+  // Swaps state_ with another MapFieldBase
+  void SwapState(MapFieldBase* other);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldBase);
+};
+
+// This class provides common Map Reflection implementations for generated
+// message and dynamic message.
+template <typename Key, typename T>
+class TypeDefinedMapFieldBase : public MapFieldBase {
+ public:
+  TypeDefinedMapFieldBase() {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr TypeDefinedMapFieldBase(ConstantInitialized tag)
+      : MapFieldBase(tag) {}
+  explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {}
+  TypeDefinedMapFieldBase(ArenaInitialized, Arena* arena)
+      : TypeDefinedMapFieldBase(arena) {}
+
+ protected:
+  ~TypeDefinedMapFieldBase() {}
+  using MapFieldBase::Destruct;
+
+ public:
+  void MapBegin(MapIterator* map_iter) const override;
+  void MapEnd(MapIterator* map_iter) const override;
+  bool EqualIterator(const MapIterator& a, const MapIterator& b) const override;
+
+  virtual const Map<Key, T>& GetMap() const = 0;
+  virtual Map<Key, T>* MutableMap() = 0;
+
+ protected:
+  typename Map<Key, T>::const_iterator& InternalGetIterator(
+      const MapIterator* map_iter) const;
+
+ private:
+  void InitializeIterator(MapIterator* map_iter) const override;
+  void DeleteIterator(MapIterator* map_iter) const override;
+  void CopyIterator(MapIterator* this_iteratorm,
+                    const MapIterator& that_iterator) const override;
+  void IncreaseIterator(MapIterator* map_iter) const override;
+
+  virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeDefinedMapFieldBase);
+};
+
+// This class provides access to map field using generated api. It is used for
+// internal generated message implementation only. Users should never use this
+// directly.
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+class MapField : public TypeDefinedMapFieldBase<Key, T> {
+  // Provide utilities to parse/serialize key/value.  Provide utilities to
+  // manipulate internal stored type.
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, T> ValueTypeHandler;
+
+  // Define message type for internal repeated field.
+  typedef Derived EntryType;
+
+  // Define abbreviation for parent MapFieldLite
+  typedef MapFieldLite<Derived, Key, T, kKeyFieldType, kValueFieldType>
+      MapFieldLiteType;
+
+  // Enum needs to be handled differently from other types because it has
+  // different exposed type in Map's api and repeated field's api. For
+  // details see the comment in the implementation of
+  // SyncMapWithRepeatedFieldNoLock.
+  static constexpr bool kIsValueEnum = ValueTypeHandler::kIsEnum;
+  typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
+
+ public:
+  typedef Map<Key, T> MapType;
+
+  MapField() : impl_() {}
+  virtual ~MapField() {}  // Destruct() must already have been called!
+  void Destruct() {
+    impl_.Destruct();
+    TypeDefinedMapFieldBase<Key, T>::Destruct();
+  }
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr MapField(ConstantInitialized tag)
+      : TypeDefinedMapFieldBase<Key, T>(tag), impl_() {}
+  explicit MapField(Arena* arena)
+      : TypeDefinedMapFieldBase<Key, T>(arena), impl_(arena) {}
+  MapField(ArenaInitialized, Arena* arena) : MapField(arena) {}
+
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const override;
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
+  bool LookupMapValue(const MapKey& map_key,
+                      MapValueConstRef* val) const override;
+  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
+  bool DeleteMapValue(const MapKey& map_key) override;
+
+  const Map<Key, T>& GetMap() const override {
+    MapFieldBase::SyncMapWithRepeatedField();
+    return impl_.GetMap();
+  }
+
+  Map<Key, T>* MutableMap() override {
+    MapFieldBase::SyncMapWithRepeatedField();
+    Map<Key, T>* result = impl_.MutableMap();
+    MapFieldBase::SetMapDirty();
+    return result;
+  }
+
+  int size() const override;
+  void Clear() override;
+  void MergeFrom(const MapFieldBase& other) override;
+  void Swap(MapFieldBase* other) override;
+  void UnsafeShallowSwap(MapFieldBase* other) override;
+  void InternalSwap(MapField* other);
+
+  // Used in the implementation of parsing. Caller should take the ownership iff
+  // arena_ is nullptr.
+  EntryType* NewEntry() const { return impl_.NewEntry(); }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return impl_._InternalParse(ptr, ctx);
+  }
+  template <typename UnknownType>
+  const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
+                                      bool (*is_valid)(int), uint32_t field_num,
+                                      InternalMetadata* metadata) {
+    return impl_.template ParseWithEnumValidation<UnknownType>(
+        ptr, ctx, is_valid, field_num, metadata);
+  }
+
+ private:
+  MapFieldLiteType impl_;
+
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+
+  // Implements MapFieldBase
+  void SyncRepeatedFieldWithMapNoLock() const override;
+  void SyncMapWithRepeatedFieldNoLock() const override;
+  size_t SpaceUsedExcludingSelfNoLock() const override;
+
+  void SetMapIteratorValue(MapIterator* map_iter) const override;
+
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+  friend class MapFieldStateTest;  // For testing, it needs raw access to impl_
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapField);
+};
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+bool AllAreInitialized(
+    const MapField<Derived, Key, T, key_wire_type, value_wire_type>& field) {
+  const auto& t = field.GetMap();
+  for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
+       ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+template <typename T, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryToMapField<
+    MapEntry<T, Key, Value, kKeyFieldType, kValueFieldType>> {
+  typedef MapField<T, Key, Value, kKeyFieldType, kValueFieldType> MapFieldType;
+};
+
+class PROTOBUF_EXPORT DynamicMapField
+    : public TypeDefinedMapFieldBase<MapKey, MapValueRef> {
+ public:
+  explicit DynamicMapField(const Message* default_entry);
+  DynamicMapField(const Message* default_entry, Arena* arena);
+  virtual ~DynamicMapField();
+
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const override;
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
+  bool LookupMapValue(const MapKey& map_key,
+                      MapValueConstRef* val) const override;
+  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
+  bool DeleteMapValue(const MapKey& map_key) override;
+  void MergeFrom(const MapFieldBase& other) override;
+  void Swap(MapFieldBase* other) override;
+  void UnsafeShallowSwap(MapFieldBase* other) override { Swap(other); }
+
+  const Map<MapKey, MapValueRef>& GetMap() const override;
+  Map<MapKey, MapValueRef>* MutableMap() override;
+
+  int size() const override;
+  void Clear() override;
+
+ private:
+  Map<MapKey, MapValueRef> map_;
+  const Message* default_entry_;
+
+  void AllocateMapValue(MapValueRef* map_val);
+
+  // Implements MapFieldBase
+  void SyncRepeatedFieldWithMapNoLock() const override;
+  void SyncMapWithRepeatedFieldNoLock() const override;
+  size_t SpaceUsedExcludingSelfNoLock() const override;
+  void SetMapIteratorValue(MapIterator* map_iter) const override;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMapField);
+};
+
+}  // namespace internal
+
+// MapValueConstRef points to a map value. Users can NOT modify
+// the map value.
+class PROTOBUF_EXPORT MapValueConstRef {
+ public:
+  MapValueConstRef() : data_(nullptr), type_() {}
+
+  int64_t GetInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64,
+               "MapValueConstRef::GetInt64Value");
+    return *reinterpret_cast<int64_t*>(data_);
+  }
+  uint64_t GetUInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64,
+               "MapValueConstRef::GetUInt64Value");
+    return *reinterpret_cast<uint64_t*>(data_);
+  }
+  int32_t GetInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32,
+               "MapValueConstRef::GetInt32Value");
+    return *reinterpret_cast<int32_t*>(data_);
+  }
+  uint32_t GetUInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
+               "MapValueConstRef::GetUInt32Value");
+    return *reinterpret_cast<uint32_t*>(data_);
+  }
+  bool GetBoolValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueConstRef::GetBoolValue");
+    return *reinterpret_cast<bool*>(data_);
+  }
+  int GetEnumValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, "MapValueConstRef::GetEnumValue");
+    return *reinterpret_cast<int*>(data_);
+  }
+  const std::string& GetStringValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING,
+               "MapValueConstRef::GetStringValue");
+    return *reinterpret_cast<std::string*>(data_);
+  }
+  float GetFloatValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT,
+               "MapValueConstRef::GetFloatValue");
+    return *reinterpret_cast<float*>(data_);
+  }
+  double GetDoubleValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE,
+               "MapValueConstRef::GetDoubleValue");
+    return *reinterpret_cast<double*>(data_);
+  }
+
+  const Message& GetMessageValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE,
+               "MapValueConstRef::GetMessageValue");
+    return *reinterpret_cast<Message*>(data_);
+  }
+
+ protected:
+  // data_ point to a map value. MapValueConstRef does not
+  // own this value.
+  void* data_;
+  // type_ is 0 or a valid FieldDescriptor::CppType.
+  // Use "CppType()" to indicate zero.
+  FieldDescriptor::CppType type_;
+
+  FieldDescriptor::CppType type() const {
+    if (type_ == FieldDescriptor::CppType() || data_ == nullptr) {
+      GOOGLE_LOG(FATAL)
+          << "Protocol Buffer map usage error:\n"
+          << "MapValueConstRef::type MapValueConstRef is not initialized.";
+    }
+    return type_;
+  }
+
+ private:
+  template <typename Derived, typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type>
+  friend class internal::MapField;
+  template <typename K, typename V>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class ::PROTOBUF_NAMESPACE_ID::MapIterator;
+  friend class Reflection;
+  friend class internal::DynamicMapField;
+
+  void SetType(FieldDescriptor::CppType type) { type_ = type; }
+  void SetValue(const void* val) { data_ = const_cast<void*>(val); }
+  void CopyFrom(const MapValueConstRef& other) {
+    type_ = other.type_;
+    data_ = other.data_;
+  }
+};
+
+// MapValueRef points to a map value. Users are able to modify
+// the map value.
+class PROTOBUF_EXPORT MapValueRef final : public MapValueConstRef {
+ public:
+  MapValueRef() {}
+
+  void SetInt64Value(int64_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapValueRef::SetInt64Value");
+    *reinterpret_cast<int64_t*>(data_) = value;
+  }
+  void SetUInt64Value(uint64_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapValueRef::SetUInt64Value");
+    *reinterpret_cast<uint64_t*>(data_) = value;
+  }
+  void SetInt32Value(int32_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapValueRef::SetInt32Value");
+    *reinterpret_cast<int32_t*>(data_) = value;
+  }
+  void SetUInt32Value(uint32_t value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapValueRef::SetUInt32Value");
+    *reinterpret_cast<uint32_t*>(data_) = value;
+  }
+  void SetBoolValue(bool value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueRef::SetBoolValue");
+    *reinterpret_cast<bool*>(data_) = value;
+  }
+  // TODO(jieluo) - Checks that enum is member.
+  void SetEnumValue(int value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, "MapValueRef::SetEnumValue");
+    *reinterpret_cast<int*>(data_) = value;
+  }
+  void SetStringValue(const std::string& value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, "MapValueRef::SetStringValue");
+    *reinterpret_cast<std::string*>(data_) = value;
+  }
+  void SetFloatValue(float value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, "MapValueRef::SetFloatValue");
+    *reinterpret_cast<float*>(data_) = value;
+  }
+  void SetDoubleValue(double value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, "MapValueRef::SetDoubleValue");
+    *reinterpret_cast<double*>(data_) = value;
+  }
+
+  Message* MutableMessageValue() {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE,
+               "MapValueRef::MutableMessageValue");
+    return reinterpret_cast<Message*>(data_);
+  }
+
+ private:
+  friend class internal::DynamicMapField;
+
+  // Only used in DynamicMapField
+  void DeleteData() {
+    switch (type_) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
+    delete reinterpret_cast<TYPE*>(data_);   \
+    break;                                   \
+  }
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, std::string);
+      HANDLE_TYPE(ENUM, int32_t);
+      HANDLE_TYPE(MESSAGE, Message);
+#undef HANDLE_TYPE
+    }
+  }
+};
+
+#undef TYPE_CHECK
+
+class PROTOBUF_EXPORT MapIterator {
+ public:
+  MapIterator(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    map_ = reflection->MutableMapData(message, field);
+    key_.SetType(field->message_type()->map_key()->cpp_type());
+    value_.SetType(field->message_type()->map_value()->cpp_type());
+    map_->InitializeIterator(this);
+  }
+  MapIterator(const MapIterator& other) {
+    map_ = other.map_;
+    map_->InitializeIterator(this);
+    map_->CopyIterator(this, other);
+  }
+  ~MapIterator() { map_->DeleteIterator(this); }
+  MapIterator& operator=(const MapIterator& other) {
+    map_ = other.map_;
+    map_->CopyIterator(this, other);
+    return *this;
+  }
+  friend bool operator==(const MapIterator& a, const MapIterator& b) {
+    return a.map_->EqualIterator(a, b);
+  }
+  friend bool operator!=(const MapIterator& a, const MapIterator& b) {
+    return !a.map_->EqualIterator(a, b);
+  }
+  MapIterator& operator++() {
+    map_->IncreaseIterator(this);
+    return *this;
+  }
+  MapIterator operator++(int) {
+    // iter_ is copied from Map<...>::iterator, no need to
+    // copy from its self again. Use the same implementation
+    // with operator++()
+    map_->IncreaseIterator(this);
+    return *this;
+  }
+  const MapKey& GetKey() { return key_; }
+  const MapValueRef& GetValueRef() { return value_; }
+  MapValueRef* MutableValueRef() {
+    map_->SetMapDirty();
+    return &value_;
+  }
+
+ private:
+  template <typename Key, typename T>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class internal::DynamicMapField;
+  template <typename Derived, typename Key, typename T,
+            internal::WireFormatLite::FieldType kKeyFieldType,
+            internal::WireFormatLite::FieldType kValueFieldType>
+  friend class internal::MapField;
+
+  // reinterpret_cast from heap-allocated Map<...>::iterator*. MapIterator owns
+  // the iterator. It is allocated by MapField<...>::InitializeIterator() called
+  // in constructor and deleted by MapField<...>::DeleteIterator() called in
+  // destructor.
+  void* iter_;
+  // Point to a MapField to call helper methods implemented in MapField.
+  // MapIterator does not own this object.
+  internal::MapFieldBase* map_;
+  MapKey key_;
+  MapValueRef value_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#ifdef _MSC_VER
+#pragma warning(pop)  // restore warning C4265
+#endif                // _MSC_VER
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field_inl.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field_inl.h
new file mode 100644
index 0000000..7c4c232
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field_inl.h
@@ -0,0 +1,375 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+
+#include <memory>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_type_handler.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// UnwrapMapKey template
+template <typename T>
+T UnwrapMapKey(const MapKey& map_key);
+template <>
+inline int32_t UnwrapMapKey<int32_t>(const MapKey& map_key) {
+  return map_key.GetInt32Value();
+}
+template <>
+inline uint32_t UnwrapMapKey<uint32_t>(const MapKey& map_key) {
+  return map_key.GetUInt32Value();
+}
+template <>
+inline int64_t UnwrapMapKey<int64_t>(const MapKey& map_key) {
+  return map_key.GetInt64Value();
+}
+template <>
+inline uint64_t UnwrapMapKey<uint64_t>(const MapKey& map_key) {
+  return map_key.GetUInt64Value();
+}
+template <>
+inline bool UnwrapMapKey<bool>(const MapKey& map_key) {
+  return map_key.GetBoolValue();
+}
+template <>
+inline std::string UnwrapMapKey<std::string>(const MapKey& map_key) {
+  return map_key.GetStringValue();
+}
+
+// SetMapKey template
+template <typename T>
+inline void SetMapKey(MapKey* map_key, const T& value);
+template <>
+inline void SetMapKey<int32_t>(MapKey* map_key, const int32_t& value) {
+  map_key->SetInt32Value(value);
+}
+template <>
+inline void SetMapKey<uint32_t>(MapKey* map_key, const uint32_t& value) {
+  map_key->SetUInt32Value(value);
+}
+template <>
+inline void SetMapKey<int64_t>(MapKey* map_key, const int64_t& value) {
+  map_key->SetInt64Value(value);
+}
+template <>
+inline void SetMapKey<uint64_t>(MapKey* map_key, const uint64_t& value) {
+  map_key->SetUInt64Value(value);
+}
+template <>
+inline void SetMapKey<bool>(MapKey* map_key, const bool& value) {
+  map_key->SetBoolValue(value);
+}
+template <>
+inline void SetMapKey<std::string>(MapKey* map_key, const std::string& value) {
+  map_key->SetStringValue(value);
+}
+
+// ------------------------TypeDefinedMapFieldBase---------------
+template <typename Key, typename T>
+typename Map<Key, T>::const_iterator&
+TypeDefinedMapFieldBase<Key, T>::InternalGetIterator(
+    const MapIterator* map_iter) const {
+  return *reinterpret_cast<typename Map<Key, T>::const_iterator*>(
+      map_iter->iter_);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::MapBegin(MapIterator* map_iter) const {
+  InternalGetIterator(map_iter) = GetMap().begin();
+  SetMapIteratorValue(map_iter);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::MapEnd(MapIterator* map_iter) const {
+  InternalGetIterator(map_iter) = GetMap().end();
+}
+
+template <typename Key, typename T>
+bool TypeDefinedMapFieldBase<Key, T>::EqualIterator(
+    const MapIterator& a, const MapIterator& b) const {
+  return InternalGetIterator(&a) == InternalGetIterator(&b);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::IncreaseIterator(
+    MapIterator* map_iter) const {
+  ++InternalGetIterator(map_iter);
+  SetMapIteratorValue(map_iter);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::InitializeIterator(
+    MapIterator* map_iter) const {
+  map_iter->iter_ = new typename Map<Key, T>::const_iterator;
+  GOOGLE_CHECK(map_iter->iter_ != nullptr);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::DeleteIterator(
+    MapIterator* map_iter) const {
+  delete reinterpret_cast<typename Map<Key, T>::const_iterator*>(
+      map_iter->iter_);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::CopyIterator(
+    MapIterator* this_iter, const MapIterator& that_iter) const {
+  InternalGetIterator(this_iter) = InternalGetIterator(&that_iter);
+  this_iter->key_.SetType(that_iter.key_.type());
+  // MapValueRef::type() fails when containing data is null. However, if
+  // this_iter points to MapEnd, data can be null.
+  this_iter->value_.SetType(
+      static_cast<FieldDescriptor::CppType>(that_iter.value_.type_));
+  SetMapIteratorValue(this_iter);
+}
+
+// ----------------------------------------------------------------------
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+int MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::size() const {
+  MapFieldBase::SyncMapWithRepeatedField();
+  return static_cast<int>(impl_.GetMap().size());
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::Clear() {
+  if (this->MapFieldBase::repeated_field_ != nullptr) {
+    RepeatedPtrField<EntryType>* repeated_field =
+        reinterpret_cast<RepeatedPtrField<EntryType>*>(
+            this->MapFieldBase::repeated_field_);
+    repeated_field->Clear();
+  }
+
+  impl_.MutableMap()->clear();
+  // Data in map and repeated field are both empty, but we can't set status
+  // CLEAN. Because clear is a generated API, we cannot invalidate previous
+  // reference to map.
+  MapFieldBase::SetMapDirty();
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::SetMapIteratorValue(MapIterator* map_iter)
+    const {
+  const Map<Key, T>& map = impl_.GetMap();
+  typename Map<Key, T>::const_iterator iter =
+      TypeDefinedMapFieldBase<Key, T>::InternalGetIterator(map_iter);
+  if (iter == map.end()) return;
+  SetMapKey(&map_iter->key_, iter->first);
+  map_iter->value_.SetValue(&iter->second);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::ContainsMapKey(
+    const MapKey& map_key) const {
+  const Map<Key, T>& map = impl_.GetMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::const_iterator iter = map.find(key);
+  return iter != map.end();
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::InsertOrLookupMapValue(const MapKey& map_key,
+                                                       MapValueRef* val) {
+  // Always use mutable map because users may change the map value by
+  // MapValueRef.
+  Map<Key, T>* map = MutableMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::iterator iter = map->find(key);
+  if (map->end() == iter) {
+    val->SetValue(&((*map)[key]));
+    return true;
+  }
+  // Key is already in the map. Make sure (*map)[key] is not called.
+  // [] may reorder the map and iterators.
+  val->SetValue(&(iter->second));
+  return false;
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::LookupMapValue(
+    const MapKey& map_key, MapValueConstRef* val) const {
+  const Map<Key, T>& map = GetMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::const_iterator iter = map.find(key);
+  if (map.end() == iter) {
+    return false;
+  }
+  // Key is already in the map. Make sure (*map)[key] is not called.
+  // [] may reorder the map and iterators.
+  val->SetValue(&(iter->second));
+  return true;
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::DeleteMapValue(
+    const MapKey& map_key) {
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  return MutableMap()->erase(key);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::MergeFrom(
+    const MapFieldBase& other) {
+  MapFieldBase::SyncMapWithRepeatedField();
+  const MapField& other_field = static_cast<const MapField&>(other);
+  other_field.SyncMapWithRepeatedField();
+  impl_.MergeFrom(other_field.impl_);
+  MapFieldBase::SetMapDirty();
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::Swap(
+    MapFieldBase* other) {
+  MapFieldBase::Swap(other);
+  MapField* other_field = down_cast<MapField*>(other);
+  impl_.Swap(&other_field->impl_);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::UnsafeShallowSwap(MapFieldBase* other) {
+  InternalSwap(down_cast<MapField*>(other));
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::InternalSwap(
+    MapField* other) {
+  MapFieldBase::InternalSwap(other);
+  impl_.InternalSwap(&other->impl_);
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::SyncRepeatedFieldWithMapNoLock() const {
+  if (this->MapFieldBase::repeated_field_ == nullptr) {
+    this->MapFieldBase::repeated_field_ =
+        Arena::CreateMessage<RepeatedPtrField<Message> >(
+            this->MapFieldBase::arena_);
+  }
+  const Map<Key, T>& map = impl_.GetMap();
+  RepeatedPtrField<EntryType>* repeated_field =
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          this->MapFieldBase::repeated_field_);
+
+  repeated_field->Clear();
+
+  // The only way we can get at this point is through reflection and the
+  // only way we can get the reflection object is by having called GetReflection
+  // on the encompassing field. So that type must have existed and hence we
+  // know that this MapEntry default_type has also already been constructed.
+  // So it's safe to just call internal_default_instance().
+  const Message* default_entry = Derived::internal_default_instance();
+  for (typename Map<Key, T>::const_iterator it = map.begin(); it != map.end();
+       ++it) {
+    EntryType* new_entry =
+        down_cast<EntryType*>(default_entry->New(this->MapFieldBase::arena_));
+    repeated_field->AddAllocated(new_entry);
+    (*new_entry->mutable_key()) = it->first;
+    (*new_entry->mutable_value()) = it->second;
+  }
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+void MapField<Derived, Key, T, kKeyFieldType,
+              kValueFieldType>::SyncMapWithRepeatedFieldNoLock() const {
+  Map<Key, T>* map = const_cast<MapField*>(this)->impl_.MutableMap();
+  RepeatedPtrField<EntryType>* repeated_field =
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          this->MapFieldBase::repeated_field_);
+  GOOGLE_CHECK(this->MapFieldBase::repeated_field_ != nullptr);
+  map->clear();
+  for (typename RepeatedPtrField<EntryType>::iterator it =
+           repeated_field->begin();
+       it != repeated_field->end(); ++it) {
+    // Cast is needed because Map's api and internal storage is different when
+    // value is enum. For enum, we cannot cast an int to enum. Thus, we have to
+    // copy value. For other types, they have same exposed api type and internal
+    // stored type. We should not introduce value copy for them. We achieve this
+    // by casting to value for enum while casting to reference for other types.
+    (*map)[it->key()] = static_cast<CastValueType>(it->value());
+  }
+}
+
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+size_t MapField<Derived, Key, T, kKeyFieldType,
+                kValueFieldType>::SpaceUsedExcludingSelfNoLock() const {
+  size_t size = 0;
+  if (this->MapFieldBase::repeated_field_ != nullptr) {
+    size += this->MapFieldBase::repeated_field_->SpaceUsedExcludingSelfLong();
+  }
+  size += impl_.GetMap().SpaceUsedExcludingSelfLong();
+
+  return size;
+}
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field_lite.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field_lite.h
new file mode 100644
index 0000000..53bf7a0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_field_lite.h
@@ -0,0 +1,209 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+
+#include <type_traits>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#ifndef NDEBUG
+void MapFieldLiteNotDestructed(void* map_field_lite);
+#endif
+
+// This class provides access to map field using generated api. It is used for
+// internal generated message implementation only. Users should never use this
+// directly.
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+class MapFieldLite {
+  // Define message type for internal repeated field.
+  typedef Derived EntryType;
+
+ public:
+  typedef Map<Key, T> MapType;
+
+  constexpr MapFieldLite() : map_() {}
+  explicit MapFieldLite(Arena* arena) : map_(arena) {}
+  MapFieldLite(ArenaInitialized, Arena* arena) : MapFieldLite(arena) {}
+
+#ifdef NDEBUG
+  void Destruct() { map_.~Map(); }
+  ~MapFieldLite() {}
+#else
+  void Destruct() {
+    // We want to destruct the map in such a way that we can verify
+    // that we've done that, but also be sure that we've deallocated
+    // everything (as opposed to leaving an allocation behind with no
+    // data in it, as would happen if a vector was resize'd to zero.
+    // Map::Swap with an empty map accomplishes that.
+    decltype(map_) swapped_map(map_.arena());
+    map_.InternalSwap(swapped_map);
+  }
+  ~MapFieldLite() {
+    if (map_.arena() == nullptr && !map_.empty()) {
+      MapFieldLiteNotDestructed(this);
+    }
+  }
+#endif
+  // Accessors
+  const Map<Key, T>& GetMap() const { return map_; }
+  Map<Key, T>* MutableMap() { return &map_; }
+
+  // Convenient methods for generated message implementation.
+  int size() const { return static_cast<int>(map_.size()); }
+  void Clear() { return map_.clear(); }
+  void MergeFrom(const MapFieldLite& other) {
+    for (typename Map<Key, T>::const_iterator it = other.map_.begin();
+         it != other.map_.end(); ++it) {
+      map_[it->first] = it->second;
+    }
+  }
+  void Swap(MapFieldLite* other) { map_.swap(other->map_); }
+  void InternalSwap(MapFieldLite* other) { map_.InternalSwap(other->map_); }
+
+  // Used in the implementation of parsing. Caller should take the ownership iff
+  // arena_ is nullptr.
+  EntryType* NewEntry() const {
+    return Arena::CreateMessage<EntryType>(map_.arena());
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
+    return parser._InternalParse(ptr, ctx);
+  }
+
+  template <typename UnknownType>
+  const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
+                                      bool (*is_valid)(int), uint32_t field_num,
+                                      InternalMetadata* metadata) {
+    typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
+    return parser.template ParseWithEnumValidation<UnknownType>(
+        ptr, ctx, is_valid, field_num, metadata);
+  }
+
+ private:
+  typedef void DestructorSkippable_;
+
+  // map_ is inside an anonymous union so we can explicitly control its
+  // destruction
+  union {
+    Map<Key, T> map_;
+  };
+
+  friend class ::PROTOBUF_NAMESPACE_ID::Arena;
+};
+
+template <typename UnknownType, typename T>
+struct EnumParseWrapper {
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return map_field->template ParseWithEnumValidation<UnknownType>(
+        ptr, ctx, is_valid, field_num, metadata);
+  }
+  T* map_field;
+  bool (*is_valid)(int);
+  uint32_t field_num;
+  InternalMetadata* metadata;
+};
+
+// Helper function because the typenames of maps are horrendous to print. This
+// leverages compiler type deduction, to keep all type data out of the
+// generated code
+template <typename UnknownType, typename T>
+EnumParseWrapper<UnknownType, T> InitEnumParseWrapper(
+    T* map_field, bool (*is_valid)(int), uint32_t field_num,
+    InternalMetadata* metadata) {
+  return EnumParseWrapper<UnknownType, T>{map_field, is_valid, field_num,
+                                          metadata};
+}
+
+// True if IsInitialized() is true for value field in all elements of t. T is
+// expected to be message.  It's useful to have this helper here to keep the
+// protobuf compiler from ever having to emit loops in IsInitialized() methods.
+// We want the C++ compiler to inline this or not as it sees fit.
+template <typename Derived, typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type>
+bool AllAreInitialized(const MapFieldLite<Derived, Key, T, key_wire_type,
+                                          value_wire_type>& field) {
+  const auto& t = field.GetMap();
+  for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
+       ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+template <typename MEntry>
+struct MapEntryToMapField : MapEntryToMapField<typename MEntry::SuperType> {};
+
+template <typename T, typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryToMapField<
+    MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType>> {
+  typedef MapFieldLite<
+      MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType>, Key, Value,
+      kKeyFieldType, kValueFieldType>
+      MapFieldType;
+};
+
+#ifndef NDEBUG
+inline PROTOBUF_NOINLINE void MapFieldLiteNotDestructed(void* map_field_lite) {
+  bool proper_destruct = false;
+  GOOGLE_CHECK(proper_destruct) << map_field_lite;
+}
+#endif
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_type_handler.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_type_handler.h
new file mode 100644
index 0000000..c210c63
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/map_type_handler.h
@@ -0,0 +1,736 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
+#define GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Used for compile time type selection. MapIf::type will be TrueType if Flag is
+// true and FalseType otherwise.
+template <bool Flag, typename TrueType, typename FalseType>
+struct MapIf;
+
+template <typename TrueType, typename FalseType>
+struct MapIf<true, TrueType, FalseType> {
+  typedef TrueType type;
+};
+
+template <typename TrueType, typename FalseType>
+struct MapIf<false, TrueType, FalseType> {
+  typedef FalseType type;
+};
+
+template <typename Type, bool is_arena_constructable>
+class MapArenaMessageCreator {
+ public:
+  // Use arena to create message if Type is arena constructable. Otherwise,
+  // create the message on heap.
+  static inline Type* CreateMessage(Arena* arena);
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, true> {
+ public:
+  static inline Type* CreateMessage(Arena* arena) {
+    return Arena::CreateMessage<Type>(arena);
+  }
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, false> {
+ public:
+  static inline Type* CreateMessage(Arena* arena) {
+    return Arena::Create<Type>(arena);
+  }
+};
+
+// Define constants for given wire field type
+template <WireFormatLite::FieldType field_type, typename Type>
+class MapWireFieldTypeTraits {};
+
+#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum)   \
+  template <typename Type>                                                 \
+  class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> {   \
+   public:                                                                 \
+    static const bool kIsMessage = IsMessage;                              \
+    static const bool kIsEnum = IsEnum;                                    \
+    typedef typename MapIf<kIsMessage, Type*, CType>::type TypeOnMemory;   \
+    typedef typename MapIf<kIsEnum, int, Type>::type MapEntryAccessorType; \
+    static const WireFormatLite::WireType kWireType =                      \
+        WireFormatLite::WIRETYPE_##WireFormatType;                         \
+  };
+
+TYPE_TRAITS(MESSAGE, Type, LENGTH_DELIMITED, true, false)
+TYPE_TRAITS(STRING, ArenaStringPtr, LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(BYTES, ArenaStringPtr, LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(INT64, int64_t, VARINT, false, false)
+TYPE_TRAITS(UINT64, uint64_t, VARINT, false, false)
+TYPE_TRAITS(INT32, int32_t, VARINT, false, false)
+TYPE_TRAITS(UINT32, uint32_t, VARINT, false, false)
+TYPE_TRAITS(SINT64, int64_t, VARINT, false, false)
+TYPE_TRAITS(SINT32, int32_t, VARINT, false, false)
+TYPE_TRAITS(ENUM, int, VARINT, false, true)
+TYPE_TRAITS(DOUBLE, double, FIXED64, false, false)
+TYPE_TRAITS(FLOAT, float, FIXED32, false, false)
+TYPE_TRAITS(FIXED64, uint64_t, FIXED64, false, false)
+TYPE_TRAITS(FIXED32, uint32_t, FIXED32, false, false)
+TYPE_TRAITS(SFIXED64, int64_t, FIXED64, false, false)
+TYPE_TRAITS(SFIXED32, int32_t, FIXED32, false, false)
+TYPE_TRAITS(BOOL, bool, VARINT, false, false)
+
+#undef TYPE_TRAITS
+
+template <WireFormatLite::FieldType field_type, typename Type>
+class MapTypeHandler {};
+
+template <typename Type>
+class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
+ public:
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type which will
+  // replace Enum with int.
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+                                          Type>::MapEntryAccessorType
+      MapEntryAccessorType;
+  // Internal stored type in MapEntryLite for given wire field type.
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+                                          Type>::TypeOnMemory TypeOnMemory;
+  // Corresponding wire type for field type.
+  static constexpr WireFormatLite::WireType kWireType =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType;
+  // Whether wire type is for message.
+  static constexpr bool kIsMessage =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage;
+  // Whether wire type is for enum.
+  static constexpr bool kIsEnum =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsEnum;
+
+  // Functions used in parsing and serialization. ===================
+  static inline size_t ByteSize(const MapEntryAccessorType& value);
+  static inline int GetCachedSize(const MapEntryAccessorType& value);
+  static inline bool Read(io::CodedInputStream* input,
+                          MapEntryAccessorType* value);
+  static inline const char* Read(const char* ptr, ParseContext* ctx,
+                                 MapEntryAccessorType* value);
+
+  static inline uint8_t* Write(int field, const MapEntryAccessorType& value,
+                               uint8_t* ptr, io::EpsCopyOutputStream* stream);
+
+  // Functions to manipulate data on memory. ========================
+  static inline const Type& GetExternalReference(const Type* value);
+  static inline void DeleteNoArena(const Type* x);
+  static inline void Merge(const Type& from, Type** to, Arena* arena);
+  static inline void Clear(Type** value, Arena* arena);
+  static constexpr TypeOnMemory Constinit();
+
+  static inline Type* EnsureMutable(Type** value, Arena* arena);
+  // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
+  // those already calculate in sizeof(MapField).
+  static inline size_t SpaceUsedInMapEntryLong(const Type* value);
+  // Return default instance if value is not initialized when calling const
+  // reference accessor.
+  static inline const Type& DefaultIfNotInitialized(const Type* value);
+  // Check if all required fields have values set.
+  static inline bool IsInitialized(Type* value);
+};
+
+#define MAP_HANDLER(FieldType)                                                 \
+  template <typename Type>                                                     \
+  class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> {               \
+   public:                                                                     \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,  \
+                                            Type>::MapEntryAccessorType        \
+        MapEntryAccessorType;                                                  \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,  \
+                                            Type>::TypeOnMemory TypeOnMemory;  \
+    static const WireFormatLite::WireType kWireType =                          \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kWireType;                               \
+    static const bool kIsMessage =                                             \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kIsMessage;                              \
+    static const bool kIsEnum =                                                \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,               \
+                               Type>::kIsEnum;                                 \
+    static inline int ByteSize(const MapEntryAccessorType& value);             \
+    static inline int GetCachedSize(const MapEntryAccessorType& value);        \
+    static inline bool Read(io::CodedInputStream* input,                       \
+                            MapEntryAccessorType* value);                      \
+    static inline const char* Read(const char* begin, ParseContext* ctx,       \
+                                   MapEntryAccessorType* value);               \
+    static inline uint8_t* Write(int field, const MapEntryAccessorType& value, \
+                                 uint8_t* ptr,                                 \
+                                 io::EpsCopyOutputStream* stream);             \
+    static inline const MapEntryAccessorType& GetExternalReference(            \
+        const TypeOnMemory& value);                                            \
+    static inline void DeleteNoArena(const TypeOnMemory& x);                   \
+    static inline void Merge(const MapEntryAccessorType& from,                 \
+                             TypeOnMemory* to, Arena* arena);                  \
+    static inline void Clear(TypeOnMemory* value, Arena* arena);               \
+    static inline size_t SpaceUsedInMapEntryLong(const TypeOnMemory& value);   \
+    static inline const MapEntryAccessorType& DefaultIfNotInitialized(         \
+        const TypeOnMemory& value);                                            \
+    static inline bool IsInitialized(const TypeOnMemory& value);               \
+    static void DeleteNoArena(TypeOnMemory& value);                            \
+    static constexpr TypeOnMemory Constinit();                                 \
+    static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value,     \
+                                                      Arena* arena);           \
+  };
+MAP_HANDLER(STRING)
+MAP_HANDLER(BYTES)
+MAP_HANDLER(INT64)
+MAP_HANDLER(UINT64)
+MAP_HANDLER(INT32)
+MAP_HANDLER(UINT32)
+MAP_HANDLER(SINT64)
+MAP_HANDLER(SINT32)
+MAP_HANDLER(ENUM)
+MAP_HANDLER(DOUBLE)
+MAP_HANDLER(FLOAT)
+MAP_HANDLER(FIXED64)
+MAP_HANDLER(FIXED32)
+MAP_HANDLER(SFIXED64)
+MAP_HANDLER(SFIXED32)
+MAP_HANDLER(BOOL)
+#undef MAP_HANDLER
+
+template <typename Type>
+inline size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::ByteSize(
+    const MapEntryAccessorType& value) {
+  return WireFormatLite::MessageSizeNoVirtual(value);
+}
+
+#define GOOGLE_PROTOBUF_BYTE_SIZE(FieldType, DeclaredType)                     \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
+      const MapEntryAccessorType& value) {                                     \
+    return static_cast<int>(WireFormatLite::DeclaredType##Size(value));        \
+  }
+
+GOOGLE_PROTOBUF_BYTE_SIZE(STRING, String)
+GOOGLE_PROTOBUF_BYTE_SIZE(BYTES, Bytes)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT64, Int64)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT64, UInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT32, Int32)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT32, UInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT64, SInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT32, SInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(ENUM, Enum)
+
+#undef GOOGLE_PROTOBUF_BYTE_SIZE
+
+#define FIXED_BYTE_SIZE(FieldType, DeclaredType)                               \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
+      const MapEntryAccessorType& /* value */) {                               \
+    return WireFormatLite::k##DeclaredType##Size;                              \
+  }
+
+FIXED_BYTE_SIZE(DOUBLE, Double)
+FIXED_BYTE_SIZE(FLOAT, Float)
+FIXED_BYTE_SIZE(FIXED64, Fixed64)
+FIXED_BYTE_SIZE(FIXED32, Fixed32)
+FIXED_BYTE_SIZE(SFIXED64, SFixed64)
+FIXED_BYTE_SIZE(SFIXED32, SFixed32)
+FIXED_BYTE_SIZE(BOOL, Bool)
+
+#undef FIXED_BYTE_SIZE
+
+template <typename Type>
+inline int MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetCachedSize(
+    const MapEntryAccessorType& value) {
+  return static_cast<int>(WireFormatLite::LengthDelimitedSize(
+      static_cast<size_t>(value.GetCachedSize())));
+}
+
+#define GET_CACHED_SIZE(FieldType, DeclaredType)                         \
+  template <typename Type>                                               \
+  inline int                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
+      const MapEntryAccessorType& value) {                               \
+    return static_cast<int>(WireFormatLite::DeclaredType##Size(value));  \
+  }
+
+GET_CACHED_SIZE(STRING, String)
+GET_CACHED_SIZE(BYTES, Bytes)
+GET_CACHED_SIZE(INT64, Int64)
+GET_CACHED_SIZE(UINT64, UInt64)
+GET_CACHED_SIZE(INT32, Int32)
+GET_CACHED_SIZE(UINT32, UInt32)
+GET_CACHED_SIZE(SINT64, SInt64)
+GET_CACHED_SIZE(SINT32, SInt32)
+GET_CACHED_SIZE(ENUM, Enum)
+
+#undef GET_CACHED_SIZE
+
+#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType)                   \
+  template <typename Type>                                               \
+  inline int                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
+      const MapEntryAccessorType& /* value */) {                         \
+    return WireFormatLite::k##DeclaredType##Size;                        \
+  }
+
+GET_FIXED_CACHED_SIZE(DOUBLE, Double)
+GET_FIXED_CACHED_SIZE(FLOAT, Float)
+GET_FIXED_CACHED_SIZE(FIXED64, Fixed64)
+GET_FIXED_CACHED_SIZE(FIXED32, Fixed32)
+GET_FIXED_CACHED_SIZE(SFIXED64, SFixed64)
+GET_FIXED_CACHED_SIZE(SFIXED32, SFixed32)
+GET_FIXED_CACHED_SIZE(BOOL, Bool)
+
+#undef GET_FIXED_CACHED_SIZE
+
+template <typename Type>
+inline uint8_t* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
+    int field, const MapEntryAccessorType& value, uint8_t* ptr,
+    io::EpsCopyOutputStream* stream) {
+  ptr = stream->EnsureSpace(ptr);
+  return WireFormatLite::InternalWriteMessage(
+      field, value, value.GetCachedSize(), ptr, stream);
+}
+
+#define WRITE_METHOD(FieldType, DeclaredType)                     \
+  template <typename Type>                                        \
+  inline uint8_t*                                                 \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(  \
+      int field, const MapEntryAccessorType& value, uint8_t* ptr, \
+      io::EpsCopyOutputStream* stream) {                          \
+    ptr = stream->EnsureSpace(ptr);                               \
+    return stream->Write##DeclaredType(field, value, ptr);        \
+  }
+
+WRITE_METHOD(STRING, String)
+WRITE_METHOD(BYTES, Bytes)
+
+#undef WRITE_METHOD
+#define WRITE_METHOD(FieldType, DeclaredType)                               \
+  template <typename Type>                                                  \
+  inline uint8_t*                                                           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(            \
+      int field, const MapEntryAccessorType& value, uint8_t* ptr,           \
+      io::EpsCopyOutputStream* stream) {                                    \
+    ptr = stream->EnsureSpace(ptr);                                         \
+    return WireFormatLite::Write##DeclaredType##ToArray(field, value, ptr); \
+  }
+
+WRITE_METHOD(INT64, Int64)
+WRITE_METHOD(UINT64, UInt64)
+WRITE_METHOD(INT32, Int32)
+WRITE_METHOD(UINT32, UInt32)
+WRITE_METHOD(SINT64, SInt64)
+WRITE_METHOD(SINT32, SInt32)
+WRITE_METHOD(ENUM, Enum)
+WRITE_METHOD(DOUBLE, Double)
+WRITE_METHOD(FLOAT, Float)
+WRITE_METHOD(FIXED64, Fixed64)
+WRITE_METHOD(FIXED32, Fixed32)
+WRITE_METHOD(SFIXED64, SFixed64)
+WRITE_METHOD(SFIXED32, SFixed32)
+WRITE_METHOD(BOOL, Bool)
+
+#undef WRITE_METHOD
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadMessageNoVirtual(input, value);
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadString(input, value);
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadBytes(input, value);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  return ctx->ParseMessage(value, ptr);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ctx->ReadString(ptr, size, value);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ctx->ReadString(ptr, size, value);
+}
+
+inline const char* ReadINT64(const char* ptr, int64_t* value) {
+  return VarintParse(ptr, reinterpret_cast<uint64_t*>(value));
+}
+inline const char* ReadUINT64(const char* ptr, uint64_t* value) {
+  return VarintParse(ptr, value);
+}
+inline const char* ReadINT32(const char* ptr, int32_t* value) {
+  return VarintParse(ptr, reinterpret_cast<uint32_t*>(value));
+}
+inline const char* ReadUINT32(const char* ptr, uint32_t* value) {
+  return VarintParse(ptr, value);
+}
+inline const char* ReadSINT64(const char* ptr, int64_t* value) {
+  *value = ReadVarintZigZag64(&ptr);
+  return ptr;
+}
+inline const char* ReadSINT32(const char* ptr, int32_t* value) {
+  *value = ReadVarintZigZag32(&ptr);
+  return ptr;
+}
+template <typename E>
+inline const char* ReadENUM(const char* ptr, E* value) {
+  *value = static_cast<E>(ReadVarint32(&ptr));
+  return ptr;
+}
+inline const char* ReadBOOL(const char* ptr, bool* value) {
+  *value = static_cast<bool>(ReadVarint32(&ptr));
+  return ptr;
+}
+
+template <typename F>
+inline const char* ReadUnaligned(const char* ptr, F* value) {
+  *value = UnalignedLoad<F>(ptr);
+  return ptr + sizeof(F);
+}
+inline const char* ReadFLOAT(const char* ptr, float* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadDOUBLE(const char* ptr, double* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadFIXED64(const char* ptr, uint64_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadFIXED32(const char* ptr, uint32_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadSFIXED64(const char* ptr, int64_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadSFIXED32(const char* ptr, int32_t* value) {
+  return ReadUnaligned(ptr, value);
+}
+
+#define READ_METHOD(FieldType)                                              \
+  template <typename Type>                                                  \
+  inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
+      io::CodedInputStream* input, MapEntryAccessorType* value) {           \
+    return WireFormatLite::ReadPrimitive<TypeOnMemory,                      \
+                                         WireFormatLite::TYPE_##FieldType>( \
+        input, value);                                                      \
+  }                                                                         \
+  template <typename Type>                                                  \
+  const char* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
+      const char* begin, ParseContext* ctx, MapEntryAccessorType* value) {  \
+    (void)ctx;                                                              \
+    return Read##FieldType(begin, value);                                   \
+  }
+
+READ_METHOD(INT64)
+READ_METHOD(UINT64)
+READ_METHOD(INT32)
+READ_METHOD(UINT32)
+READ_METHOD(SINT64)
+READ_METHOD(SINT32)
+READ_METHOD(ENUM)
+READ_METHOD(DOUBLE)
+READ_METHOD(FLOAT)
+READ_METHOD(FIXED64)
+READ_METHOD(FIXED32)
+READ_METHOD(SFIXED64)
+READ_METHOD(SFIXED32)
+READ_METHOD(BOOL)
+
+#undef READ_METHOD
+
+// Definition for message handler
+
+template <typename Type>
+inline const Type&
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetExternalReference(
+    const Type* value) {
+  return *value;
+}
+
+template <typename Type>
+inline size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                             Type>::SpaceUsedInMapEntryLong(const Type* value) {
+  return value->SpaceUsedLong();
+}
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Clear(
+    Type** value, Arena* /* arena */) {
+  if (*value != nullptr) (*value)->Clear();
+}
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Merge(
+    const Type& from, Type** to, Arena* /* arena */) {
+  (*to)->MergeFrom(from);
+}
+
+template <typename Type>
+void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DeleteNoArena(
+    const Type* ptr) {
+  delete ptr;
+}
+
+template <typename Type>
+constexpr auto MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Constinit()
+    -> TypeOnMemory {
+  return nullptr;
+}
+
+template <typename Type>
+inline Type* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::EnsureMutable(
+    Type** value, Arena* arena) {
+  if (*value == nullptr) {
+    *value = MapArenaMessageCreator<
+        Type,
+        Arena::is_arena_constructable<Type>::type::value>::CreateMessage(arena);
+  }
+  return *value;
+}
+
+template <typename Type>
+inline const Type&
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DefaultIfNotInitialized(
+    const Type* value) {
+  return value != nullptr ? *value : *Type::internal_default_instance();
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::IsInitialized(
+    Type* value) {
+  return value ? value->IsInitialized() : false;
+}
+
+// Definition for string/bytes handler
+
+#define STRING_OR_BYTES_HANDLER_FUNCTIONS(FieldType)                          \
+  template <typename Type>                                                    \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,      \
+                                       Type>::MapEntryAccessorType&           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                            \
+                 Type>::GetExternalReference(const TypeOnMemory& value) {     \
+    return value.Get();                                                       \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline size_t                                                               \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                            \
+                 Type>::SpaceUsedInMapEntryLong(const TypeOnMemory& value) {  \
+    return sizeof(value);                                                     \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear(  \
+      TypeOnMemory* value, Arena* /* arena */) {                              \
+    value->ClearToEmpty();                                                    \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge(  \
+      const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) {     \
+    to->Set(from, arena);                                                     \
+  }                                                                           \
+  template <typename Type>                                                    \
+  void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena( \
+      TypeOnMemory& value) {                                                  \
+    value.Destroy();                                                          \
+  }                                                                           \
+  template <typename Type>                                                    \
+  constexpr auto                                                              \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Constinit()         \
+      ->TypeOnMemory {                                                        \
+    return TypeOnMemory(&internal::fixed_address_empty_string,                \
+                        ConstantInitialized{});                               \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,            \
+                                 Type>::MapEntryAccessorType*                 \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable(      \
+      TypeOnMemory* value, Arena* arena) {                                    \
+    return value->Mutable(arena);                                             \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,      \
+                                       Type>::MapEntryAccessorType&           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                            \
+                 Type>::DefaultIfNotInitialized(const TypeOnMemory& value) {  \
+    return value.Get();                                                       \
+  }                                                                           \
+  template <typename Type>                                                    \
+  inline bool                                                                 \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::IsInitialized(      \
+      const TypeOnMemory& /* value */) {                                      \
+    return true;                                                              \
+  }
+STRING_OR_BYTES_HANDLER_FUNCTIONS(STRING)
+STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES)
+#undef STRING_OR_BYTES_HANDLER_FUNCTIONS
+
+#define PRIMITIVE_HANDLER_FUNCTIONS(FieldType)                               \
+  template <typename Type>                                                   \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,     \
+                                       Type>::MapEntryAccessorType&          \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                           \
+                 Type>::GetExternalReference(const TypeOnMemory& value) {    \
+    return value;                                                            \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline size_t MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::     \
+      SpaceUsedInMapEntryLong(const TypeOnMemory& /* value */) {             \
+    return 0;                                                                \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
+      TypeOnMemory* value, Arena* /* arena */) {                             \
+    *value = 0;                                                              \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
+      const MapEntryAccessorType& from, TypeOnMemory* to,                    \
+      Arena* /* arena */) {                                                  \
+    *to = from;                                                              \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType,               \
+                             Type>::DeleteNoArena(TypeOnMemory& /* x */) {}  \
+  template <typename Type>                                                   \
+  constexpr auto                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Constinit()        \
+      ->TypeOnMemory {                                                       \
+    return 0;                                                                \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,           \
+                                 Type>::MapEntryAccessorType*                \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable(     \
+      TypeOnMemory* value, Arena* /* arena */) {                             \
+    return value;                                                            \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,     \
+                                       Type>::MapEntryAccessorType&          \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                           \
+                 Type>::DefaultIfNotInitialized(const TypeOnMemory& value) { \
+    return value;                                                            \
+  }                                                                          \
+  template <typename Type>                                                   \
+  inline bool                                                                \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::IsInitialized(     \
+      const TypeOnMemory& /* value */) {                                     \
+    return true;                                                             \
+  }
+PRIMITIVE_HANDLER_FUNCTIONS(INT64)
+PRIMITIVE_HANDLER_FUNCTIONS(UINT64)
+PRIMITIVE_HANDLER_FUNCTIONS(INT32)
+PRIMITIVE_HANDLER_FUNCTIONS(UINT32)
+PRIMITIVE_HANDLER_FUNCTIONS(SINT64)
+PRIMITIVE_HANDLER_FUNCTIONS(SINT32)
+PRIMITIVE_HANDLER_FUNCTIONS(ENUM)
+PRIMITIVE_HANDLER_FUNCTIONS(DOUBLE)
+PRIMITIVE_HANDLER_FUNCTIONS(FLOAT)
+PRIMITIVE_HANDLER_FUNCTIONS(FIXED64)
+PRIMITIVE_HANDLER_FUNCTIONS(FIXED32)
+PRIMITIVE_HANDLER_FUNCTIONS(SFIXED64)
+PRIMITIVE_HANDLER_FUNCTIONS(SFIXED32)
+PRIMITIVE_HANDLER_FUNCTIONS(BOOL)
+#undef PRIMITIVE_HANDLER_FUNCTIONS
+
+// Functions for operating on a map entry using type handlers.
+//
+// Does not contain any representation (this class is not intended to be
+// instantiated).
+template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryFuncs {
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+  enum : int {
+    kKeyFieldNumber = 1,
+    kValueFieldNumber = 2
+  };
+
+  static uint8_t* InternalSerialize(int field_number, const Key& key,
+                                    const Value& value, uint8_t* ptr,
+                                    io::EpsCopyOutputStream* stream) {
+    ptr = stream->EnsureSpace(ptr);
+    ptr = WireFormatLite::WriteTagToArray(
+        field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
+    ptr = io::CodedOutputStream::WriteVarint32ToArray(GetCachedSize(key, value),
+                                                      ptr);
+
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key, ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value, ptr, stream);
+  }
+
+  static size_t ByteSizeLong(const Key& key, const Value& value) {
+    // Tags for key and value will both be one byte (field numbers 1 and 2).
+    size_t inner_length =
+        2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
+    return inner_length + io::CodedOutputStream::VarintSize32(
+                              static_cast<uint32_t>(inner_length));
+  }
+
+  static int GetCachedSize(const Key& key, const Value& value) {
+    // Tags for key and value will both be one byte (field numbers 1 and 2).
+    return 2 + KeyTypeHandler::GetCachedSize(key) +
+           ValueTypeHandler::GetCachedSize(value);
+  }
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/message.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/message.h
new file mode 100644
index 0000000..39ec154
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/message.h
@@ -0,0 +1,1497 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Defines Message, the abstract interface implemented by non-lite
+// protocol message objects.  Although it's possible to implement this
+// interface manually, most users will use the protocol compiler to
+// generate implementations.
+//
+// Example usage:
+//
+// Say you have a message defined as:
+//
+//   message Foo {
+//     optional string text = 1;
+//     repeated int32 numbers = 2;
+//   }
+//
+// Then, if you used the protocol compiler to generate a class from the above
+// definition, you could use it like so:
+//
+//   std::string data;  // Will store a serialized version of the message.
+//
+//   {
+//     // Create a message and serialize it.
+//     Foo foo;
+//     foo.set_text("Hello World!");
+//     foo.add_numbers(1);
+//     foo.add_numbers(5);
+//     foo.add_numbers(42);
+//
+//     foo.SerializeToString(&data);
+//   }
+//
+//   {
+//     // Parse the serialized message and check that it contains the
+//     // correct data.
+//     Foo foo;
+//     foo.ParseFromString(data);
+//
+//     assert(foo.text() == "Hello World!");
+//     assert(foo.numbers_size() == 3);
+//     assert(foo.numbers(0) == 1);
+//     assert(foo.numbers(1) == 5);
+//     assert(foo.numbers(2) == 42);
+//   }
+//
+//   {
+//     // Same as the last block, but do it dynamically via the Message
+//     // reflection interface.
+//     Message* foo = new Foo;
+//     const Descriptor* descriptor = foo->GetDescriptor();
+//
+//     // Get the descriptors for the fields we're interested in and verify
+//     // their types.
+//     const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
+//     assert(text_field != nullptr);
+//     assert(text_field->type() == FieldDescriptor::TYPE_STRING);
+//     assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
+//     const FieldDescriptor* numbers_field = descriptor->
+//                                            FindFieldByName("numbers");
+//     assert(numbers_field != nullptr);
+//     assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
+//     assert(numbers_field->label() == FieldDescriptor::LABEL_REPEATED);
+//
+//     // Parse the message.
+//     foo->ParseFromString(data);
+//
+//     // Use the reflection interface to examine the contents.
+//     const Reflection* reflection = foo->GetReflection();
+//     assert(reflection->GetString(*foo, text_field) == "Hello World!");
+//     assert(reflection->FieldSize(*foo, numbers_field) == 3);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 0) == 1);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 1) == 5);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 2) == 42);
+//
+//     delete foo;
+//   }
+
+#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
+#define GOOGLE_PROTOBUF_MESSAGE_H__
+
+
+#include <iosfwd>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map.h>  // TODO(b/211442718): cleanup
+#include <google/protobuf/message_lite.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Message;
+class Reflection;
+class MessageFactory;
+
+// Defined in other files.
+class AssignDescriptorsHelper;
+class DynamicMessageFactory;
+class GeneratedMessageReflectionTestHelper;
+class MapKey;
+class MapValueConstRef;
+class MapValueRef;
+class MapIterator;
+class MapReflectionTester;
+
+namespace internal {
+struct DescriptorTable;
+class MapFieldBase;
+class SwapFieldHelper;
+class CachedSize;
+}  // namespace internal
+class UnknownFieldSet;  // unknown_field_set.h
+namespace io {
+class ZeroCopyInputStream;   // zero_copy_stream.h
+class ZeroCopyOutputStream;  // zero_copy_stream.h
+class CodedInputStream;      // coded_stream.h
+class CodedOutputStream;     // coded_stream.h
+}  // namespace io
+namespace python {
+class MapReflectionFriend;  // scalar_map_container.h
+class MessageReflectionFriend;
+}  // namespace python
+namespace expr {
+class CelMapReflectionFriend;  // field_backed_map_impl.cc
+}
+
+namespace internal {
+class MapFieldPrinterHelper;  // text_format.cc
+}
+namespace util {
+class MessageDifferencer;
+}
+
+
+namespace internal {
+class ReflectionAccessor;      // message.cc
+class ReflectionOps;           // reflection_ops.h
+class MapKeySorter;            // wire_format.cc
+class WireFormat;              // wire_format.h
+class MapFieldReflectionTest;  // map_test.cc
+}  // namespace internal
+
+template <typename T>
+class RepeatedField;  // repeated_field.h
+
+template <typename T>
+class RepeatedPtrField;  // repeated_field.h
+
+// A container to hold message metadata.
+struct Metadata {
+  const Descriptor* descriptor;
+  const Reflection* reflection;
+};
+
+namespace internal {
+template <class To>
+inline To* GetPointerAtOffset(Message* message, uint32_t offset) {
+  return reinterpret_cast<To*>(reinterpret_cast<char*>(message) + offset);
+}
+
+template <class To>
+const To* GetConstPointerAtOffset(const Message* message, uint32_t offset) {
+  return reinterpret_cast<const To*>(reinterpret_cast<const char*>(message) +
+                                     offset);
+}
+
+template <class To>
+const To& GetConstRefAtOffset(const Message& message, uint32_t offset) {
+  return *GetConstPointerAtOffset<To>(&message, offset);
+}
+
+bool CreateUnknownEnumValues(const FieldDescriptor* field);
+
+// Returns true if "message" is a descendant of "root".
+PROTOBUF_EXPORT bool IsDescendant(Message& root, const Message& message);
+}  // namespace internal
+
+// Abstract interface for protocol messages.
+//
+// See also MessageLite, which contains most every-day operations.  Message
+// adds descriptors and reflection on top of that.
+//
+// The methods of this class that are virtual but not pure-virtual have
+// default implementations based on reflection.  Message classes which are
+// optimized for speed will want to override these with faster implementations,
+// but classes optimized for code size may be happy with keeping them.  See
+// the optimize_for option in descriptor.proto.
+//
+// Users must not derive from this class. Only the protocol compiler and
+// the internal library are allowed to create subclasses.
+class PROTOBUF_EXPORT Message : public MessageLite {
+ public:
+  constexpr Message() {}
+
+  // Basic Operations ------------------------------------------------
+
+  // Construct a new instance of the same type.  Ownership is passed to the
+  // caller.  (This is also defined in MessageLite, but is defined again here
+  // for return-type covariance.)
+  Message* New() const { return New(nullptr); }
+
+  // Construct a new instance on the arena. Ownership is passed to the caller
+  // if arena is a nullptr.
+  Message* New(Arena* arena) const override = 0;
+
+  // Make this message into a copy of the given message.  The given message
+  // must have the same descriptor, but need not necessarily be the same class.
+  // By default this is just implemented as "Clear(); MergeFrom(from);".
+  void CopyFrom(const Message& from);
+
+  // Merge the fields from the given message into this message.  Singular
+  // fields will be overwritten, if specified in from, except for embedded
+  // messages which will be merged.  Repeated fields will be concatenated.
+  // The given message must be of the same type as this message (i.e. the
+  // exact same class).
+  virtual void MergeFrom(const Message& from);
+
+  // Verifies that IsInitialized() returns true.  GOOGLE_CHECK-fails otherwise, with
+  // a nice error message.
+  void CheckInitialized() const;
+
+  // Slowly build a list of all required fields that are not set.
+  // This is much, much slower than IsInitialized() as it is implemented
+  // purely via reflection.  Generally, you should not call this unless you
+  // have already determined that an error exists by calling IsInitialized().
+  void FindInitializationErrors(std::vector<std::string>* errors) const;
+
+  // Like FindInitializationErrors, but joins all the strings, delimited by
+  // commas, and returns them.
+  std::string InitializationErrorString() const override;
+
+  // Clears all unknown fields from this message and all embedded messages.
+  // Normally, if unknown tag numbers are encountered when parsing a message,
+  // the tag and value are stored in the message's UnknownFieldSet and
+  // then written back out when the message is serialized.  This allows servers
+  // which simply route messages to other servers to pass through messages
+  // that have new field definitions which they don't yet know about.  However,
+  // this behavior can have security implications.  To avoid it, call this
+  // method after parsing.
+  //
+  // See Reflection::GetUnknownFields() for more on unknown fields.
+  void DiscardUnknownFields();
+
+  // Computes (an estimate of) the total number of bytes currently used for
+  // storing the message in memory.  The default implementation calls the
+  // Reflection object's SpaceUsed() method.
+  //
+  // SpaceUsed() is noticeably slower than ByteSize(), as it is implemented
+  // using reflection (rather than the generated code implementation for
+  // ByteSize()). Like ByteSize(), its CPU time is linear in the number of
+  // fields defined for the proto.
+  virtual size_t SpaceUsedLong() const;
+
+  PROTOBUF_DEPRECATED_MSG("Please use SpaceUsedLong() instead")
+  int SpaceUsed() const { return internal::ToIntSize(SpaceUsedLong()); }
+
+  // Debugging & Testing----------------------------------------------
+
+  // Generates a human-readable form of this message for debugging purposes.
+  // Note that the format and content of a debug string is not guaranteed, may
+  // change without notice, and should not be depended on. Code that does
+  // anything except display a string to assist in debugging should use
+  // TextFormat instead.
+  std::string DebugString() const;
+  // Like DebugString(), but with less whitespace.
+  std::string ShortDebugString() const;
+  // Like DebugString(), but do not escape UTF-8 byte sequences.
+  std::string Utf8DebugString() const;
+  // Convenience function useful in GDB.  Prints DebugString() to stdout.
+  void PrintDebugString() const;
+
+  // Reflection-based methods ----------------------------------------
+  // These methods are pure-virtual in MessageLite, but Message provides
+  // reflection-based default implementations.
+
+  std::string GetTypeName() const override;
+  void Clear() override;
+
+  // Returns whether all required fields have been set. Note that required
+  // fields no longer exist starting in proto3.
+  bool IsInitialized() const override;
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) override;
+  // Reflective parser
+  const char* _InternalParse(const char* ptr,
+                             internal::ParseContext* ctx) override;
+  size_t ByteSizeLong() const override;
+  uint8_t* _InternalSerialize(uint8_t* target,
+                              io::EpsCopyOutputStream* stream) const override;
+
+ private:
+  // This is called only by the default implementation of ByteSize(), to
+  // update the cached size.  If you override ByteSize(), you do not need
+  // to override this.  If you do not override ByteSize(), you MUST override
+  // this; the default implementation will crash.
+  //
+  // The method is private because subclasses should never call it; only
+  // override it.  Yes, C++ lets you do that.  Crazy, huh?
+  virtual void SetCachedSize(int size) const;
+
+ public:
+  // Introspection ---------------------------------------------------
+
+
+  // Get a non-owning pointer to a Descriptor for this message's type.  This
+  // describes what fields the message contains, the types of those fields, etc.
+  // This object remains property of the Message.
+  const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; }
+
+  // Get a non-owning pointer to the Reflection interface for this Message,
+  // which can be used to read and modify the fields of the Message dynamically
+  // (in other words, without knowing the message type at compile time).  This
+  // object remains property of the Message.
+  const Reflection* GetReflection() const { return GetMetadata().reflection; }
+
+ protected:
+  // Get a struct containing the metadata for the Message, which is used in turn
+  // to implement GetDescriptor() and GetReflection() above.
+  virtual Metadata GetMetadata() const = 0;
+
+  struct ClassData {
+    // Note: The order of arguments (to, then from) is chosen so that the ABI
+    // of this function is the same as the CopyFrom method.  That is, the
+    // hidden "this" parameter comes first.
+    void (*copy_to_from)(Message& to, const Message& from_msg);
+    void (*merge_to_from)(Message& to, const Message& from_msg);
+  };
+  // GetClassData() returns a pointer to a ClassData struct which
+  // exists in global memory and is unique to each subclass.  This uniqueness
+  // property is used in order to quickly determine whether two messages are
+  // of the same type.
+  // TODO(jorg): change to pure virtual
+  virtual const ClassData* GetClassData() const { return nullptr; }
+
+  // CopyWithSourceCheck calls Clear() and then MergeFrom(), and in debug
+  // builds, checks that calling Clear() on the destination message doesn't
+  // alter the source.  It assumes the messages are known to be of the same
+  // type, and thus uses GetClassData().
+  static void CopyWithSourceCheck(Message& to, const Message& from);
+
+  // Fail if "from" is a descendant of "to" as such copy is not allowed.
+  static void FailIfCopyFromDescendant(Message& to, const Message& from);
+
+  inline explicit Message(Arena* arena, bool is_message_owned = false)
+      : MessageLite(arena, is_message_owned) {}
+  size_t ComputeUnknownFieldsSize(size_t total_size,
+                                  internal::CachedSize* cached_size) const;
+  size_t MaybeComputeUnknownFieldsSize(size_t total_size,
+                                       internal::CachedSize* cached_size) const;
+
+
+ protected:
+  static uint64_t GetInvariantPerBuild(uint64_t salt);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
+};
+
+namespace internal {
+// Forward-declare interfaces used to implement RepeatedFieldRef.
+// These are protobuf internals that users shouldn't care about.
+class RepeatedFieldAccessor;
+}  // namespace internal
+
+// Forward-declare RepeatedFieldRef templates. The second type parameter is
+// used for SFINAE tricks. Users should ignore it.
+template <typename T, typename Enable = void>
+class RepeatedFieldRef;
+
+template <typename T, typename Enable = void>
+class MutableRepeatedFieldRef;
+
+// This interface contains methods that can be used to dynamically access
+// and modify the fields of a protocol message.  Their semantics are
+// similar to the accessors the protocol compiler generates.
+//
+// To get the Reflection for a given Message, call Message::GetReflection().
+//
+// This interface is separate from Message only for efficiency reasons;
+// the vast majority of implementations of Message will share the same
+// implementation of Reflection (GeneratedMessageReflection,
+// defined in generated_message.h), and all Messages of a particular class
+// should share the same Reflection object (though you should not rely on
+// the latter fact).
+//
+// There are several ways that these methods can be used incorrectly.  For
+// example, any of the following conditions will lead to undefined
+// results (probably assertion failures):
+// - The FieldDescriptor is not a field of this message type.
+// - The method called is not appropriate for the field's type.  For
+//   each field type in FieldDescriptor::TYPE_*, there is only one
+//   Get*() method, one Set*() method, and one Add*() method that is
+//   valid for that type.  It should be obvious which (except maybe
+//   for TYPE_BYTES, which are represented using strings in C++).
+// - A Get*() or Set*() method for singular fields is called on a repeated
+//   field.
+// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated
+//   field.
+// - The Message object passed to any method is not of the right type for
+//   this Reflection object (i.e. message.GetReflection() != reflection).
+//
+// You might wonder why there is not any abstract representation for a field
+// of arbitrary type.  E.g., why isn't there just a "GetField()" method that
+// returns "const Field&", where "Field" is some class with accessors like
+// "GetInt32Value()".  The problem is that someone would have to deal with
+// allocating these Field objects.  For generated message classes, having to
+// allocate space for an additional object to wrap every field would at least
+// double the message's memory footprint, probably worse.  Allocating the
+// objects on-demand, on the other hand, would be expensive and prone to
+// memory leaks.  So, instead we ended up with this flat interface.
+class PROTOBUF_EXPORT Reflection final {
+ public:
+  // Get the UnknownFieldSet for the message.  This contains fields which
+  // were seen when the Message was parsed but were not recognized according
+  // to the Message's definition.
+  const UnknownFieldSet& GetUnknownFields(const Message& message) const;
+  // Get a mutable pointer to the UnknownFieldSet for the message.  This
+  // contains fields which were seen when the Message was parsed but were not
+  // recognized according to the Message's definition.
+  UnknownFieldSet* MutableUnknownFields(Message* message) const;
+
+  // Estimate the amount of memory used by the message object.
+  size_t SpaceUsedLong(const Message& message) const;
+
+  PROTOBUF_DEPRECATED_MSG("Please use SpaceUsedLong() instead")
+  int SpaceUsed(const Message& message) const {
+    return internal::ToIntSize(SpaceUsedLong(message));
+  }
+
+  // Check if the given non-repeated field is set.
+  bool HasField(const Message& message, const FieldDescriptor* field) const;
+
+  // Get the number of elements of a repeated field.
+  int FieldSize(const Message& message, const FieldDescriptor* field) const;
+
+  // Clear the value of a field, so that HasField() returns false or
+  // FieldSize() returns zero.
+  void ClearField(Message* message, const FieldDescriptor* field) const;
+
+  // Check if the oneof is set. Returns true if any field in oneof
+  // is set, false otherwise.
+  bool HasOneof(const Message& message,
+                const OneofDescriptor* oneof_descriptor) const;
+
+  void ClearOneof(Message* message,
+                  const OneofDescriptor* oneof_descriptor) const;
+
+  // Returns the field descriptor if the oneof is set. nullptr otherwise.
+  const FieldDescriptor* GetOneofFieldDescriptor(
+      const Message& message, const OneofDescriptor* oneof_descriptor) const;
+
+  // Removes the last element of a repeated field.
+  // We don't provide a way to remove any element other than the last
+  // because it invites inefficient use, such as O(n^2) filtering loops
+  // that should have been O(n).  If you want to remove an element other
+  // than the last, the best way to do it is to re-arrange the elements
+  // (using Swap()) so that the one you want removed is at the end, then
+  // call RemoveLast().
+  void RemoveLast(Message* message, const FieldDescriptor* field) const;
+  // Removes the last element of a repeated message field, and returns the
+  // pointer to the caller.  Caller takes ownership of the returned pointer.
+  PROTOBUF_NODISCARD Message* ReleaseLast(Message* message,
+                                          const FieldDescriptor* field) const;
+
+  // Similar to ReleaseLast() without internal safety and ownershp checks. This
+  // method should only be used when the objects are on the same arena or paired
+  // with a call to `UnsafeArenaAddAllocatedMessage`.
+  Message* UnsafeArenaReleaseLast(Message* message,
+                                  const FieldDescriptor* field) const;
+
+  // Swap the complete contents of two messages.
+  void Swap(Message* message1, Message* message2) const;
+
+  // Swap fields listed in fields vector of two messages.
+  void SwapFields(Message* message1, Message* message2,
+                  const std::vector<const FieldDescriptor*>& fields) const;
+
+  // Swap two elements of a repeated field.
+  void SwapElements(Message* message, const FieldDescriptor* field, int index1,
+                    int index2) const;
+
+  // Swap without internal safety and ownership checks. This method should only
+  // be used when the objects are on the same arena.
+  void UnsafeArenaSwap(Message* lhs, Message* rhs) const;
+
+  // SwapFields without internal safety and ownership checks. This method should
+  // only be used when the objects are on the same arena.
+  void UnsafeArenaSwapFields(
+      Message* lhs, Message* rhs,
+      const std::vector<const FieldDescriptor*>& fields) const;
+
+  // List all fields of the message which are currently set, except for unknown
+  // fields, but including extension known to the parser (i.e. compiled in).
+  // Singular fields will only be listed if HasField(field) would return true
+  // and repeated fields will only be listed if FieldSize(field) would return
+  // non-zero.  Fields (both normal fields and extension fields) will be listed
+  // ordered by field number.
+  // Use Reflection::GetUnknownFields() or message.unknown_fields() to also get
+  // access to fields/extensions unknown to the parser.
+  void ListFields(const Message& message,
+                  std::vector<const FieldDescriptor*>* output) const;
+
+  // Singular field getters ------------------------------------------
+  // These get the value of a non-repeated field.  They return the default
+  // value for fields that aren't set.
+
+  int32_t GetInt32(const Message& message, const FieldDescriptor* field) const;
+  int64_t GetInt64(const Message& message, const FieldDescriptor* field) const;
+  uint32_t GetUInt32(const Message& message,
+                     const FieldDescriptor* field) const;
+  uint64_t GetUInt64(const Message& message,
+                     const FieldDescriptor* field) const;
+  float GetFloat(const Message& message, const FieldDescriptor* field) const;
+  double GetDouble(const Message& message, const FieldDescriptor* field) const;
+  bool GetBool(const Message& message, const FieldDescriptor* field) const;
+  std::string GetString(const Message& message,
+                        const FieldDescriptor* field) const;
+  const EnumValueDescriptor* GetEnum(const Message& message,
+                                     const FieldDescriptor* field) const;
+
+  // GetEnumValue() returns an enum field's value as an integer rather than
+  // an EnumValueDescriptor*. If the integer value does not correspond to a
+  // known value descriptor, a new value descriptor is created. (Such a value
+  // will only be present when the new unknown-enum-value semantics are enabled
+  // for a message.)
+  int GetEnumValue(const Message& message, const FieldDescriptor* field) const;
+
+  // See MutableMessage() for the meaning of the "factory" parameter.
+  const Message& GetMessage(const Message& message,
+                            const FieldDescriptor* field,
+                            MessageFactory* factory = nullptr) const;
+
+  // Get a string value without copying, if possible.
+  //
+  // GetString() necessarily returns a copy of the string.  This can be
+  // inefficient when the std::string is already stored in a std::string object
+  // in the underlying message.  GetStringReference() will return a reference to
+  // the underlying std::string in this case.  Otherwise, it will copy the
+  // string into *scratch and return that.
+  //
+  // Note:  It is perfectly reasonable and useful to write code like:
+  //     str = reflection->GetStringReference(message, field, &str);
+  //   This line would ensure that only one copy of the string is made
+  //   regardless of the field's underlying representation.  When initializing
+  //   a newly-constructed string, though, it's just as fast and more
+  //   readable to use code like:
+  //     std::string str = reflection->GetString(message, field);
+  const std::string& GetStringReference(const Message& message,
+                                        const FieldDescriptor* field,
+                                        std::string* scratch) const;
+
+
+  // Singular field mutators -----------------------------------------
+  // These mutate the value of a non-repeated field.
+
+  void SetInt32(Message* message, const FieldDescriptor* field,
+                int32_t value) const;
+  void SetInt64(Message* message, const FieldDescriptor* field,
+                int64_t value) const;
+  void SetUInt32(Message* message, const FieldDescriptor* field,
+                 uint32_t value) const;
+  void SetUInt64(Message* message, const FieldDescriptor* field,
+                 uint64_t value) const;
+  void SetFloat(Message* message, const FieldDescriptor* field,
+                float value) const;
+  void SetDouble(Message* message, const FieldDescriptor* field,
+                 double value) const;
+  void SetBool(Message* message, const FieldDescriptor* field,
+               bool value) const;
+  void SetString(Message* message, const FieldDescriptor* field,
+                 std::string value) const;
+  void SetEnum(Message* message, const FieldDescriptor* field,
+               const EnumValueDescriptor* value) const;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // For proto3 this is just setting the enum field to the value specified, for
+  // proto2 it's more complicated. If value is a known enum value the field is
+  // set as usual. If the value is unknown then it is added to the unknown field
+  // set. Note this matches the behavior of parsing unknown enum values.
+  // If multiple calls with unknown values happen than they are all added to the
+  // unknown field set in order of the calls.
+  void SetEnumValue(Message* message, const FieldDescriptor* field,
+                    int value) const;
+
+  // Get a mutable pointer to a field with a message type.  If a MessageFactory
+  // is provided, it will be used to construct instances of the sub-message;
+  // otherwise, the default factory is used.  If the field is an extension that
+  // does not live in the same pool as the containing message's descriptor (e.g.
+  // it lives in an overlay pool), then a MessageFactory must be provided.
+  // If you have no idea what that meant, then you probably don't need to worry
+  // about it (don't provide a MessageFactory).  WARNING:  If the
+  // FieldDescriptor is for a compiled-in extension, then
+  // factory->GetPrototype(field->message_type()) MUST return an instance of
+  // the compiled-in class for this type, NOT DynamicMessage.
+  Message* MutableMessage(Message* message, const FieldDescriptor* field,
+                          MessageFactory* factory = nullptr) const;
+
+  // Replaces the message specified by 'field' with the already-allocated object
+  // sub_message, passing ownership to the message.  If the field contained a
+  // message, that message is deleted.  If sub_message is nullptr, the field is
+  // cleared.
+  void SetAllocatedMessage(Message* message, Message* sub_message,
+                           const FieldDescriptor* field) const;
+
+  // Similar to `SetAllocatedMessage`, but omits all internal safety and
+  // ownership checks.  This method should only be used when the objects are on
+  // the same arena or paired with a call to `UnsafeArenaReleaseMessage`.
+  void UnsafeArenaSetAllocatedMessage(Message* message, Message* sub_message,
+                                      const FieldDescriptor* field) const;
+
+  // Releases the message specified by 'field' and returns the pointer,
+  // ReleaseMessage() will return the message the message object if it exists.
+  // Otherwise, it may or may not return nullptr.  In any case, if the return
+  // value is non-null, the caller takes ownership of the pointer.
+  // If the field existed (HasField() is true), then the returned pointer will
+  // be the same as the pointer returned by MutableMessage().
+  // This function has the same effect as ClearField().
+  PROTOBUF_NODISCARD Message* ReleaseMessage(
+      Message* message, const FieldDescriptor* field,
+      MessageFactory* factory = nullptr) const;
+
+  // Similar to `ReleaseMessage`, but omits all internal safety and ownership
+  // checks.  This method should only be used when the objects are on the same
+  // arena or paired with a call to `UnsafeArenaSetAllocatedMessage`.
+  Message* UnsafeArenaReleaseMessage(Message* message,
+                                     const FieldDescriptor* field,
+                                     MessageFactory* factory = nullptr) const;
+
+
+  // Repeated field getters ------------------------------------------
+  // These get the value of one element of a repeated field.
+
+  int32_t GetRepeatedInt32(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  int64_t GetRepeatedInt64(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  uint32_t GetRepeatedUInt32(const Message& message,
+                             const FieldDescriptor* field, int index) const;
+  uint64_t GetRepeatedUInt64(const Message& message,
+                             const FieldDescriptor* field, int index) const;
+  float GetRepeatedFloat(const Message& message, const FieldDescriptor* field,
+                         int index) const;
+  double GetRepeatedDouble(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  bool GetRepeatedBool(const Message& message, const FieldDescriptor* field,
+                       int index) const;
+  std::string GetRepeatedString(const Message& message,
+                                const FieldDescriptor* field, int index) const;
+  const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
+                                             const FieldDescriptor* field,
+                                             int index) const;
+  // GetRepeatedEnumValue() returns an enum field's value as an integer rather
+  // than an EnumValueDescriptor*. If the integer value does not correspond to a
+  // known value descriptor, a new value descriptor is created. (Such a value
+  // will only be present when the new unknown-enum-value semantics are enabled
+  // for a message.)
+  int GetRepeatedEnumValue(const Message& message, const FieldDescriptor* field,
+                           int index) const;
+  const Message& GetRepeatedMessage(const Message& message,
+                                    const FieldDescriptor* field,
+                                    int index) const;
+
+  // See GetStringReference(), above.
+  const std::string& GetRepeatedStringReference(const Message& message,
+                                                const FieldDescriptor* field,
+                                                int index,
+                                                std::string* scratch) const;
+
+
+  // Repeated field mutators -----------------------------------------
+  // These mutate the value of one element of a repeated field.
+
+  void SetRepeatedInt32(Message* message, const FieldDescriptor* field,
+                        int index, int32_t value) const;
+  void SetRepeatedInt64(Message* message, const FieldDescriptor* field,
+                        int index, int64_t value) const;
+  void SetRepeatedUInt32(Message* message, const FieldDescriptor* field,
+                         int index, uint32_t value) const;
+  void SetRepeatedUInt64(Message* message, const FieldDescriptor* field,
+                         int index, uint64_t value) const;
+  void SetRepeatedFloat(Message* message, const FieldDescriptor* field,
+                        int index, float value) const;
+  void SetRepeatedDouble(Message* message, const FieldDescriptor* field,
+                         int index, double value) const;
+  void SetRepeatedBool(Message* message, const FieldDescriptor* field,
+                       int index, bool value) const;
+  void SetRepeatedString(Message* message, const FieldDescriptor* field,
+                         int index, std::string value) const;
+  void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
+                       int index, const EnumValueDescriptor* value) const;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // For proto3 this is just setting the enum field to the value specified, for
+  // proto2 it's more complicated. If value is a known enum value the field is
+  // set as usual. If the value is unknown then it is added to the unknown field
+  // set. Note this matches the behavior of parsing unknown enum values.
+  // If multiple calls with unknown values happen than they are all added to the
+  // unknown field set in order of the calls.
+  void SetRepeatedEnumValue(Message* message, const FieldDescriptor* field,
+                            int index, int value) const;
+  // Get a mutable pointer to an element of a repeated field with a message
+  // type.
+  Message* MutableRepeatedMessage(Message* message,
+                                  const FieldDescriptor* field,
+                                  int index) const;
+
+
+  // Repeated field adders -------------------------------------------
+  // These add an element to a repeated field.
+
+  void AddInt32(Message* message, const FieldDescriptor* field,
+                int32_t value) const;
+  void AddInt64(Message* message, const FieldDescriptor* field,
+                int64_t value) const;
+  void AddUInt32(Message* message, const FieldDescriptor* field,
+                 uint32_t value) const;
+  void AddUInt64(Message* message, const FieldDescriptor* field,
+                 uint64_t value) const;
+  void AddFloat(Message* message, const FieldDescriptor* field,
+                float value) const;
+  void AddDouble(Message* message, const FieldDescriptor* field,
+                 double value) const;
+  void AddBool(Message* message, const FieldDescriptor* field,
+               bool value) const;
+  void AddString(Message* message, const FieldDescriptor* field,
+                 std::string value) const;
+  void AddEnum(Message* message, const FieldDescriptor* field,
+               const EnumValueDescriptor* value) const;
+  // Add an integer value to a repeated enum field rather than
+  // EnumValueDescriptor. For proto3 this is just setting the enum field to the
+  // value specified, for proto2 it's more complicated. If value is a known enum
+  // value the field is set as usual. If the value is unknown then it is added
+  // to the unknown field set. Note this matches the behavior of parsing unknown
+  // enum values. If multiple calls with unknown values happen than they are all
+  // added to the unknown field set in order of the calls.
+  void AddEnumValue(Message* message, const FieldDescriptor* field,
+                    int value) const;
+  // See MutableMessage() for comments on the "factory" parameter.
+  Message* AddMessage(Message* message, const FieldDescriptor* field,
+                      MessageFactory* factory = nullptr) const;
+
+  // Appends an already-allocated object 'new_entry' to the repeated field
+  // specified by 'field' passing ownership to the message.
+  void AddAllocatedMessage(Message* message, const FieldDescriptor* field,
+                           Message* new_entry) const;
+
+  // Similar to AddAllocatedMessage() without internal safety and ownership
+  // checks. This method should only be used when the objects are on the same
+  // arena or paired with a call to `UnsafeArenaReleaseLast`.
+  void UnsafeArenaAddAllocatedMessage(Message* message,
+                                      const FieldDescriptor* field,
+                                      Message* new_entry) const;
+
+
+  // Get a RepeatedFieldRef object that can be used to read the underlying
+  // repeated field. The type parameter T must be set according to the
+  // field's cpp type. The following table shows the mapping from cpp type
+  // to acceptable T.
+  //
+  //   field->cpp_type()      T
+  //   CPPTYPE_INT32        int32_t
+  //   CPPTYPE_UINT32       uint32_t
+  //   CPPTYPE_INT64        int64_t
+  //   CPPTYPE_UINT64       uint64_t
+  //   CPPTYPE_DOUBLE       double
+  //   CPPTYPE_FLOAT        float
+  //   CPPTYPE_BOOL         bool
+  //   CPPTYPE_ENUM         generated enum type or int32_t
+  //   CPPTYPE_STRING       std::string
+  //   CPPTYPE_MESSAGE      generated message type or google::protobuf::Message
+  //
+  // A RepeatedFieldRef object can be copied and the resulted object will point
+  // to the same repeated field in the same message. The object can be used as
+  // long as the message is not destroyed.
+  //
+  // Note that to use this method users need to include the header file
+  // "reflection.h" (which defines the RepeatedFieldRef class templates).
+  template <typename T>
+  RepeatedFieldRef<T> GetRepeatedFieldRef(const Message& message,
+                                          const FieldDescriptor* field) const;
+
+  // Like GetRepeatedFieldRef() but return an object that can also be used
+  // manipulate the underlying repeated field.
+  template <typename T>
+  MutableRepeatedFieldRef<T> GetMutableRepeatedFieldRef(
+      Message* message, const FieldDescriptor* field) const;
+
+  // DEPRECATED. Please use Get(Mutable)RepeatedFieldRef() for repeated field
+  // access. The following repeated field accessors will be removed in the
+  // future.
+  //
+  // Repeated field accessors  -------------------------------------------------
+  // The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular
+  // access to the data in a RepeatedField.  The methods below provide aggregate
+  // access by exposing the RepeatedField object itself with the Message.
+  // Applying these templates to inappropriate types will lead to an undefined
+  // reference at link time (e.g. GetRepeatedField<***double>), or possibly a
+  // template matching error at compile time (e.g. GetRepeatedPtrField<File>).
+  //
+  // Usage example: my_doubs = refl->GetRepeatedField<double>(msg, fd);
+
+  // DEPRECATED. Please use GetRepeatedFieldRef().
+  //
+  // for T = Cord and all protobuf scalar types except enums.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetRepeatedFieldRef() instead")
+  const RepeatedField<T>& GetRepeatedField(const Message& msg,
+                                           const FieldDescriptor* d) const {
+    return GetRepeatedFieldInternal<T>(msg, d);
+  }
+
+  // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+  //
+  // for T = Cord and all protobuf scalar types except enums.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetMutableRepeatedFieldRef() instead")
+  RepeatedField<T>* MutableRepeatedField(Message* msg,
+                                         const FieldDescriptor* d) const {
+    return MutableRepeatedFieldInternal<T>(msg, d);
+  }
+
+  // DEPRECATED. Please use GetRepeatedFieldRef().
+  //
+  // for T = std::string, google::protobuf::internal::StringPieceField
+  //         google::protobuf::Message & descendants.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetRepeatedFieldRef() instead")
+  const RepeatedPtrField<T>& GetRepeatedPtrField(
+      const Message& msg, const FieldDescriptor* d) const {
+    return GetRepeatedPtrFieldInternal<T>(msg, d);
+  }
+
+  // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+  //
+  // for T = std::string, google::protobuf::internal::StringPieceField
+  //         google::protobuf::Message & descendants.
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Please use GetMutableRepeatedFieldRef() instead")
+  RepeatedPtrField<T>* MutableRepeatedPtrField(Message* msg,
+                                               const FieldDescriptor* d) const {
+    return MutableRepeatedPtrFieldInternal<T>(msg, d);
+  }
+
+  // Extensions ----------------------------------------------------------------
+
+  // Try to find an extension of this message type by fully-qualified field
+  // name.  Returns nullptr if no extension is known for this name or number.
+  const FieldDescriptor* FindKnownExtensionByName(
+      const std::string& name) const;
+
+  // Try to find an extension of this message type by field number.
+  // Returns nullptr if no extension is known for this name or number.
+  const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
+
+  // Feature Flags -------------------------------------------------------------
+
+  // Does this message support storing arbitrary integer values in enum fields?
+  // If |true|, GetEnumValue/SetEnumValue and associated repeated-field versions
+  // take arbitrary integer values, and the legacy GetEnum() getter will
+  // dynamically create an EnumValueDescriptor for any integer value without
+  // one. If |false|, setting an unknown enum value via the integer-based
+  // setters results in undefined behavior (in practice, GOOGLE_DCHECK-fails).
+  //
+  // Generic code that uses reflection to handle messages with enum fields
+  // should check this flag before using the integer-based setter, and either
+  // downgrade to a compatible value or use the UnknownFieldSet if not. For
+  // example:
+  //
+  //   int new_value = GetValueFromApplicationLogic();
+  //   if (reflection->SupportsUnknownEnumValues()) {
+  //     reflection->SetEnumValue(message, field, new_value);
+  //   } else {
+  //     if (field_descriptor->enum_type()->
+  //             FindValueByNumber(new_value) != nullptr) {
+  //       reflection->SetEnumValue(message, field, new_value);
+  //     } else if (emit_unknown_enum_values) {
+  //       reflection->MutableUnknownFields(message)->AddVarint(
+  //           field->number(), new_value);
+  //     } else {
+  //       // convert value to a compatible/default value.
+  //       new_value = CompatibleDowngrade(new_value);
+  //       reflection->SetEnumValue(message, field, new_value);
+  //     }
+  //   }
+  bool SupportsUnknownEnumValues() const;
+
+  // Returns the MessageFactory associated with this message.  This can be
+  // useful for determining if a message is a generated message or not, for
+  // example:
+  //   if (message->GetReflection()->GetMessageFactory() ==
+  //       google::protobuf::MessageFactory::generated_factory()) {
+  //     // This is a generated message.
+  //   }
+  // It can also be used to create more messages of this type, though
+  // Message::New() is an easier way to accomplish this.
+  MessageFactory* GetMessageFactory() const;
+
+ private:
+  template <typename T>
+  const RepeatedField<T>& GetRepeatedFieldInternal(
+      const Message& message, const FieldDescriptor* field) const;
+  template <typename T>
+  RepeatedField<T>* MutableRepeatedFieldInternal(
+      Message* message, const FieldDescriptor* field) const;
+  template <typename T>
+  const RepeatedPtrField<T>& GetRepeatedPtrFieldInternal(
+      const Message& message, const FieldDescriptor* field) const;
+  template <typename T>
+  RepeatedPtrField<T>* MutableRepeatedPtrFieldInternal(
+      Message* message, const FieldDescriptor* field) const;
+  // Obtain a pointer to a Repeated Field Structure and do some type checking:
+  //   on field->cpp_type(),
+  //   on field->field_option().ctype() (if ctype >= 0)
+  //   of field->message_type() (if message_type != nullptr).
+  // We use 2 routine rather than 4 (const vs mutable) x (scalar vs pointer).
+  void* MutableRawRepeatedField(Message* message, const FieldDescriptor* field,
+                                FieldDescriptor::CppType, int ctype,
+                                const Descriptor* message_type) const;
+
+  const void* GetRawRepeatedField(const Message& message,
+                                  const FieldDescriptor* field,
+                                  FieldDescriptor::CppType cpptype, int ctype,
+                                  const Descriptor* message_type) const;
+
+  // The following methods are used to implement (Mutable)RepeatedFieldRef.
+  // A Ref object will store a raw pointer to the repeated field data (obtained
+  // from RepeatedFieldData()) and a pointer to a Accessor (obtained from
+  // RepeatedFieldAccessor) which will be used to access the raw data.
+
+  // Returns a raw pointer to the repeated field
+  //
+  // "cpp_type" and "message_type" are deduced from the type parameter T passed
+  // to Get(Mutable)RepeatedFieldRef. If T is a generated message type,
+  // "message_type" should be set to its descriptor. Otherwise "message_type"
+  // should be set to nullptr. Implementations of this method should check
+  // whether "cpp_type"/"message_type" is consistent with the actual type of the
+  // field. We use 1 routine rather than 2 (const vs mutable) because it is
+  // protected and it doesn't change the message.
+  void* RepeatedFieldData(Message* message, const FieldDescriptor* field,
+                          FieldDescriptor::CppType cpp_type,
+                          const Descriptor* message_type) const;
+
+  // The returned pointer should point to a singleton instance which implements
+  // the RepeatedFieldAccessor interface.
+  const internal::RepeatedFieldAccessor* RepeatedFieldAccessor(
+      const FieldDescriptor* field) const;
+
+  // Lists all fields of the message which are currently set, except for unknown
+  // fields and stripped fields. See ListFields for details.
+  void ListFieldsOmitStripped(
+      const Message& message,
+      std::vector<const FieldDescriptor*>* output) const;
+
+  bool IsMessageStripped(const Descriptor* descriptor) const {
+    return schema_.IsMessageStripped(descriptor);
+  }
+
+  friend class TextFormat;
+
+  void ListFieldsMayFailOnStripped(
+      const Message& message, bool should_fail,
+      std::vector<const FieldDescriptor*>* output) const;
+
+  // Returns true if the message field is backed by a LazyField.
+  //
+  // A message field may be backed by a LazyField without the user annotation
+  // ([lazy = true]). While the user-annotated LazyField is lazily verified on
+  // first touch (i.e. failure on access rather than parsing if the LazyField is
+  // not initialized), the inferred LazyField is eagerly verified to avoid lazy
+  // parsing error at the cost of lower efficiency. When reflecting a message
+  // field, use this API instead of checking field->options().lazy().
+  bool IsLazyField(const FieldDescriptor* field) const {
+    return IsLazilyVerifiedLazyField(field) ||
+           IsEagerlyVerifiedLazyField(field);
+  }
+
+  // Returns true if the field is lazy extension. It is meant to allow python
+  // reparse lazy field until b/157559327 is fixed.
+  bool IsLazyExtension(const Message& message,
+                       const FieldDescriptor* field) const;
+
+  bool IsLazilyVerifiedLazyField(const FieldDescriptor* field) const;
+  bool IsEagerlyVerifiedLazyField(const FieldDescriptor* field) const;
+
+  friend class FastReflectionMessageMutator;
+  friend bool internal::IsDescendant(Message& root, const Message& message);
+
+  const Descriptor* const descriptor_;
+  const internal::ReflectionSchema schema_;
+  const DescriptorPool* const descriptor_pool_;
+  MessageFactory* const message_factory_;
+
+  // Last non weak field index. This is an optimization when most weak fields
+  // are at the end of the containing message. If a message proto doesn't
+  // contain weak fields, then this field equals descriptor_->field_count().
+  int last_non_weak_field_index_;
+
+  template <typename T, typename Enable>
+  friend class RepeatedFieldRef;
+  template <typename T, typename Enable>
+  friend class MutableRepeatedFieldRef;
+  friend class ::PROTOBUF_NAMESPACE_ID::MessageLayoutInspector;
+  friend class ::PROTOBUF_NAMESPACE_ID::AssignDescriptorsHelper;
+  friend class DynamicMessageFactory;
+  friend class GeneratedMessageReflectionTestHelper;
+  friend class python::MapReflectionFriend;
+  friend class python::MessageReflectionFriend;
+  friend class util::MessageDifferencer;
+#define GOOGLE_PROTOBUF_HAS_CEL_MAP_REFLECTION_FRIEND
+  friend class expr::CelMapReflectionFriend;
+  friend class internal::MapFieldReflectionTest;
+  friend class internal::MapKeySorter;
+  friend class internal::WireFormat;
+  friend class internal::ReflectionOps;
+  friend class internal::SwapFieldHelper;
+  // Needed for implementing text format for map.
+  friend class internal::MapFieldPrinterHelper;
+
+  Reflection(const Descriptor* descriptor,
+             const internal::ReflectionSchema& schema,
+             const DescriptorPool* pool, MessageFactory* factory);
+
+  // Special version for specialized implementations of string.  We can't
+  // call MutableRawRepeatedField directly here because we don't have access to
+  // FieldOptions::* which are defined in descriptor.pb.h.  Including that
+  // file here is not possible because it would cause a circular include cycle.
+  // We use 1 routine rather than 2 (const vs mutable) because it is private
+  // and mutable a repeated string field doesn't change the message.
+  void* MutableRawRepeatedString(Message* message, const FieldDescriptor* field,
+                                 bool is_string) const;
+
+  friend class MapReflectionTester;
+  // Returns true if key is in map. Returns false if key is not in map field.
+  bool ContainsMapKey(const Message& message, const FieldDescriptor* field,
+                      const MapKey& key) const;
+
+  // If key is in map field: Saves the value pointer to val and returns
+  // false. If key in not in map field: Insert the key into map, saves
+  // value pointer to val and returns true. Users are able to modify the
+  // map value by MapValueRef.
+  bool InsertOrLookupMapValue(Message* message, const FieldDescriptor* field,
+                              const MapKey& key, MapValueRef* val) const;
+
+  // If key is in map field: Saves the value pointer to val and returns true.
+  // Returns false if key is not in map field. Users are NOT able to modify
+  // the value by MapValueConstRef.
+  bool LookupMapValue(const Message& message, const FieldDescriptor* field,
+                      const MapKey& key, MapValueConstRef* val) const;
+  bool LookupMapValue(const Message&, const FieldDescriptor*, const MapKey&,
+                      MapValueRef*) const = delete;
+
+  // Delete and returns true if key is in the map field. Returns false
+  // otherwise.
+  bool DeleteMapValue(Message* message, const FieldDescriptor* field,
+                      const MapKey& key) const;
+
+  // Returns a MapIterator referring to the first element in the map field.
+  // If the map field is empty, this function returns the same as
+  // reflection::MapEnd. Mutation to the field may invalidate the iterator.
+  MapIterator MapBegin(Message* message, const FieldDescriptor* field) const;
+
+  // Returns a MapIterator referring to the theoretical element that would
+  // follow the last element in the map field. It does not point to any
+  // real element. Mutation to the field may invalidate the iterator.
+  MapIterator MapEnd(Message* message, const FieldDescriptor* field) const;
+
+  // Get the number of <key, value> pair of a map field. The result may be
+  // different from FieldSize which can have duplicate keys.
+  int MapSize(const Message& message, const FieldDescriptor* field) const;
+
+  // Help method for MapIterator.
+  friend class MapIterator;
+  friend class WireFormatForMapFieldTest;
+  internal::MapFieldBase* MutableMapData(Message* message,
+                                         const FieldDescriptor* field) const;
+
+  const internal::MapFieldBase* GetMapData(const Message& message,
+                                           const FieldDescriptor* field) const;
+
+  template <class T>
+  const T& GetRawNonOneof(const Message& message,
+                          const FieldDescriptor* field) const;
+  template <class T>
+  T* MutableRawNonOneof(Message* message, const FieldDescriptor* field) const;
+
+  template <typename Type>
+  const Type& GetRaw(const Message& message,
+                     const FieldDescriptor* field) const;
+  template <typename Type>
+  inline Type* MutableRaw(Message* message, const FieldDescriptor* field) const;
+  template <typename Type>
+  const Type& DefaultRaw(const FieldDescriptor* field) const;
+
+  const Message* GetDefaultMessageInstance(const FieldDescriptor* field) const;
+
+  inline const uint32_t* GetHasBits(const Message& message) const;
+  inline uint32_t* MutableHasBits(Message* message) const;
+  inline uint32_t GetOneofCase(const Message& message,
+                               const OneofDescriptor* oneof_descriptor) const;
+  inline uint32_t* MutableOneofCase(
+      Message* message, const OneofDescriptor* oneof_descriptor) const;
+  inline bool HasExtensionSet(const Message& /* message */) const {
+    return schema_.HasExtensionSet();
+  }
+  const internal::ExtensionSet& GetExtensionSet(const Message& message) const;
+  internal::ExtensionSet* MutableExtensionSet(Message* message) const;
+
+  const internal::InternalMetadata& GetInternalMetadata(
+      const Message& message) const;
+
+  internal::InternalMetadata* MutableInternalMetadata(Message* message) const;
+
+  inline bool IsInlined(const FieldDescriptor* field) const;
+
+  inline bool HasBit(const Message& message,
+                     const FieldDescriptor* field) const;
+  inline void SetBit(Message* message, const FieldDescriptor* field) const;
+  inline void ClearBit(Message* message, const FieldDescriptor* field) const;
+  inline void SwapBit(Message* message1, Message* message2,
+                      const FieldDescriptor* field) const;
+
+  inline const uint32_t* GetInlinedStringDonatedArray(
+      const Message& message) const;
+  inline uint32_t* MutableInlinedStringDonatedArray(Message* message) const;
+  inline bool IsInlinedStringDonated(const Message& message,
+                                     const FieldDescriptor* field) const;
+  inline void SwapInlinedStringDonated(Message* lhs, Message* rhs,
+                                       const FieldDescriptor* field) const;
+
+  // Shallow-swap fields listed in fields vector of two messages. It is the
+  // caller's responsibility to make sure shallow swap is safe.
+  void UnsafeShallowSwapFields(
+      Message* message1, Message* message2,
+      const std::vector<const FieldDescriptor*>& fields) const;
+
+  // This function only swaps the field. Should swap corresponding has_bit
+  // before or after using this function.
+  void SwapField(Message* message1, Message* message2,
+                 const FieldDescriptor* field) const;
+
+  // Unsafe but shallow version of SwapField.
+  void UnsafeShallowSwapField(Message* message1, Message* message2,
+                              const FieldDescriptor* field) const;
+
+  template <bool unsafe_shallow_swap>
+  void SwapFieldsImpl(Message* message1, Message* message2,
+                      const std::vector<const FieldDescriptor*>& fields) const;
+
+  template <bool unsafe_shallow_swap>
+  void SwapOneofField(Message* lhs, Message* rhs,
+                      const OneofDescriptor* oneof_descriptor) const;
+
+  inline bool HasOneofField(const Message& message,
+                            const FieldDescriptor* field) const;
+  inline void SetOneofCase(Message* message,
+                           const FieldDescriptor* field) const;
+  inline void ClearOneofField(Message* message,
+                              const FieldDescriptor* field) const;
+
+  template <typename Type>
+  inline const Type& GetField(const Message& message,
+                              const FieldDescriptor* field) const;
+  template <typename Type>
+  inline void SetField(Message* message, const FieldDescriptor* field,
+                       const Type& value) const;
+  template <typename Type>
+  inline Type* MutableField(Message* message,
+                            const FieldDescriptor* field) const;
+  template <typename Type>
+  inline const Type& GetRepeatedField(const Message& message,
+                                      const FieldDescriptor* field,
+                                      int index) const;
+  template <typename Type>
+  inline const Type& GetRepeatedPtrField(const Message& message,
+                                         const FieldDescriptor* field,
+                                         int index) const;
+  template <typename Type>
+  inline void SetRepeatedField(Message* message, const FieldDescriptor* field,
+                               int index, Type value) const;
+  template <typename Type>
+  inline Type* MutableRepeatedField(Message* message,
+                                    const FieldDescriptor* field,
+                                    int index) const;
+  template <typename Type>
+  inline void AddField(Message* message, const FieldDescriptor* field,
+                       const Type& value) const;
+  template <typename Type>
+  inline Type* AddField(Message* message, const FieldDescriptor* field) const;
+
+  int GetExtensionNumberOrDie(const Descriptor* type) const;
+
+  // Internal versions of EnumValue API perform no checking. Called after checks
+  // by public methods.
+  void SetEnumValueInternal(Message* message, const FieldDescriptor* field,
+                            int value) const;
+  void SetRepeatedEnumValueInternal(Message* message,
+                                    const FieldDescriptor* field, int index,
+                                    int value) const;
+  void AddEnumValueInternal(Message* message, const FieldDescriptor* field,
+                            int value) const;
+
+  friend inline  // inline so nobody can call this function.
+      void
+      RegisterAllTypesInternal(const Metadata* file_level_metadata, int size);
+  friend inline const char* ParseLenDelim(int field_number,
+                                          const FieldDescriptor* field,
+                                          Message* msg,
+                                          const Reflection* reflection,
+                                          const char* ptr,
+                                          internal::ParseContext* ctx);
+  friend inline const char* ParsePackedField(const FieldDescriptor* field,
+                                             Message* msg,
+                                             const Reflection* reflection,
+                                             const char* ptr,
+                                             internal::ParseContext* ctx);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
+};
+
+// Abstract interface for a factory for message objects.
+class PROTOBUF_EXPORT MessageFactory {
+ public:
+  inline MessageFactory() {}
+  virtual ~MessageFactory();
+
+  // Given a Descriptor, gets or constructs the default (prototype) Message
+  // of that type.  You can then call that message's New() method to construct
+  // a mutable message of that type.
+  //
+  // Calling this method twice with the same Descriptor returns the same
+  // object.  The returned object remains property of the factory.  Also, any
+  // objects created by calling the prototype's New() method share some data
+  // with the prototype, so these must be destroyed before the MessageFactory
+  // is destroyed.
+  //
+  // The given descriptor must outlive the returned message, and hence must
+  // outlive the MessageFactory.
+  //
+  // Some implementations do not support all types.  GetPrototype() will
+  // return nullptr if the descriptor passed in is not supported.
+  //
+  // This method may or may not be thread-safe depending on the implementation.
+  // Each implementation should document its own degree thread-safety.
+  virtual const Message* GetPrototype(const Descriptor* type) = 0;
+
+  // Gets a MessageFactory which supports all generated, compiled-in messages.
+  // In other words, for any compiled-in type FooMessage, the following is true:
+  //   MessageFactory::generated_factory()->GetPrototype(
+  //     FooMessage::descriptor()) == FooMessage::default_instance()
+  // This factory supports all types which are found in
+  // DescriptorPool::generated_pool().  If given a descriptor from any other
+  // pool, GetPrototype() will return nullptr.  (You can also check if a
+  // descriptor is for a generated message by checking if
+  // descriptor->file()->pool() == DescriptorPool::generated_pool().)
+  //
+  // This factory is 100% thread-safe; calling GetPrototype() does not modify
+  // any shared data.
+  //
+  // This factory is a singleton.  The caller must not delete the object.
+  static MessageFactory* generated_factory();
+
+  // For internal use only:  Registers a .proto file at static initialization
+  // time, to be placed in generated_factory.  The first time GetPrototype()
+  // is called with a descriptor from this file, |register_messages| will be
+  // called, with the file name as the parameter.  It must call
+  // InternalRegisterGeneratedMessage() (below) to register each message type
+  // in the file.  This strange mechanism is necessary because descriptors are
+  // built lazily, so we can't register types by their descriptor until we
+  // know that the descriptor exists.  |filename| must be a permanent string.
+  static void InternalRegisterGeneratedFile(
+      const google::protobuf::internal::DescriptorTable* table);
+
+  // For internal use only:  Registers a message type.  Called only by the
+  // functions which are registered with InternalRegisterGeneratedFile(),
+  // above.
+  static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
+                                               const Message* prototype);
+
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
+};
+
+#define DECLARE_GET_REPEATED_FIELD(TYPE)                           \
+  template <>                                                      \
+  PROTOBUF_EXPORT const RepeatedField<TYPE>&                       \
+  Reflection::GetRepeatedFieldInternal<TYPE>(                      \
+      const Message& message, const FieldDescriptor* field) const; \
+                                                                   \
+  template <>                                                      \
+  PROTOBUF_EXPORT RepeatedField<TYPE>*                             \
+  Reflection::MutableRepeatedFieldInternal<TYPE>(                  \
+      Message * message, const FieldDescriptor* field) const;
+
+DECLARE_GET_REPEATED_FIELD(int32_t)
+DECLARE_GET_REPEATED_FIELD(int64_t)
+DECLARE_GET_REPEATED_FIELD(uint32_t)
+DECLARE_GET_REPEATED_FIELD(uint64_t)
+DECLARE_GET_REPEATED_FIELD(float)
+DECLARE_GET_REPEATED_FIELD(double)
+DECLARE_GET_REPEATED_FIELD(bool)
+
+#undef DECLARE_GET_REPEATED_FIELD
+
+// Tries to downcast this message to a generated message type.  Returns nullptr
+// if this class is not an instance of T.  This works even if RTTI is disabled.
+//
+// This also has the effect of creating a strong reference to T that will
+// prevent the linker from stripping it out at link time.  This can be important
+// if you are using a DynamicMessageFactory that delegates to the generated
+// factory.
+template <typename T>
+const T* DynamicCastToGenerated(const Message* from) {
+  // Compile-time assert that T is a generated type that has a
+  // default_instance() accessor, but avoid actually calling it.
+  const T& (*get_default_instance)() = &T::default_instance;
+  (void)get_default_instance;
+
+  // Compile-time assert that T is a subclass of google::protobuf::Message.
+  const Message* unused = static_cast<T*>(nullptr);
+  (void)unused;
+
+#if PROTOBUF_RTTI
+  return dynamic_cast<const T*>(from);
+#else
+  bool ok = from != nullptr &&
+            T::default_instance().GetReflection() == from->GetReflection();
+  return ok ? down_cast<const T*>(from) : nullptr;
+#endif
+}
+
+template <typename T>
+T* DynamicCastToGenerated(Message* from) {
+  const Message* message_const = from;
+  return const_cast<T*>(DynamicCastToGenerated<T>(message_const));
+}
+
+// Call this function to ensure that this message's reflection is linked into
+// the binary:
+//
+//   google::protobuf::LinkMessageReflection<pkg::FooMessage>();
+//
+// This will ensure that the following lookup will succeed:
+//
+//   DescriptorPool::generated_pool()->FindMessageTypeByName("pkg.FooMessage");
+//
+// As a side-effect, it will also guarantee that anything else from the same
+// .proto file will also be available for lookup in the generated pool.
+//
+// This function does not actually register the message, so it does not need
+// to be called before the lookup.  However it does need to occur in a function
+// that cannot be stripped from the binary (ie. it must be reachable from main).
+//
+// Best practice is to call this function as close as possible to where the
+// reflection is actually needed.  This function is very cheap to call, so you
+// should not need to worry about its runtime overhead except in the tightest
+// of loops (on x86-64 it compiles into two "mov" instructions).
+template <typename T>
+void LinkMessageReflection() {
+  internal::StrongReference(T::default_instance);
+}
+
+// =============================================================================
+// Implementation details for {Get,Mutable}RawRepeatedPtrField.  We provide
+// specializations for <std::string>, <StringPieceField> and <Message> and
+// handle everything else with the default template which will match any type
+// having a method with signature "static const google::protobuf::Descriptor*
+// descriptor()". Such a type presumably is a descendant of google::protobuf::Message.
+
+template <>
+inline const RepeatedPtrField<std::string>&
+Reflection::GetRepeatedPtrFieldInternal<std::string>(
+    const Message& message, const FieldDescriptor* field) const {
+  return *static_cast<RepeatedPtrField<std::string>*>(
+      MutableRawRepeatedString(const_cast<Message*>(&message), field, true));
+}
+
+template <>
+inline RepeatedPtrField<std::string>*
+Reflection::MutableRepeatedPtrFieldInternal<std::string>(
+    Message* message, const FieldDescriptor* field) const {
+  return static_cast<RepeatedPtrField<std::string>*>(
+      MutableRawRepeatedString(message, field, true));
+}
+
+
+// -----
+
+template <>
+inline const RepeatedPtrField<Message>& Reflection::GetRepeatedPtrFieldInternal(
+    const Message& message, const FieldDescriptor* field) const {
+  return *static_cast<const RepeatedPtrField<Message>*>(GetRawRepeatedField(
+      message, field, FieldDescriptor::CPPTYPE_MESSAGE, -1, nullptr));
+}
+
+template <>
+inline RepeatedPtrField<Message>* Reflection::MutableRepeatedPtrFieldInternal(
+    Message* message, const FieldDescriptor* field) const {
+  return static_cast<RepeatedPtrField<Message>*>(MutableRawRepeatedField(
+      message, field, FieldDescriptor::CPPTYPE_MESSAGE, -1, nullptr));
+}
+
+template <typename PB>
+inline const RepeatedPtrField<PB>& Reflection::GetRepeatedPtrFieldInternal(
+    const Message& message, const FieldDescriptor* field) const {
+  return *static_cast<const RepeatedPtrField<PB>*>(
+      GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE, -1,
+                          PB::default_instance().GetDescriptor()));
+}
+
+template <typename PB>
+inline RepeatedPtrField<PB>* Reflection::MutableRepeatedPtrFieldInternal(
+    Message* message, const FieldDescriptor* field) const {
+  return static_cast<RepeatedPtrField<PB>*>(
+      MutableRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE,
+                              -1, PB::default_instance().GetDescriptor()));
+}
+
+template <typename Type>
+const Type& Reflection::DefaultRaw(const FieldDescriptor* field) const {
+  return *reinterpret_cast<const Type*>(schema_.GetFieldDefault(field));
+}
+
+uint32_t Reflection::GetOneofCase(
+    const Message& message, const OneofDescriptor* oneof_descriptor) const {
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  return internal::GetConstRefAtOffset<uint32_t>(
+      message, schema_.GetOneofCaseOffset(oneof_descriptor));
+}
+
+bool Reflection::HasOneofField(const Message& message,
+                               const FieldDescriptor* field) const {
+  return (GetOneofCase(message, field->containing_oneof()) ==
+          static_cast<uint32_t>(field->number()));
+}
+
+template <typename Type>
+const Type& Reflection::GetRaw(const Message& message,
+                               const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!schema_.InRealOneof(field) || HasOneofField(message, field))
+      << "Field = " << field->full_name();
+  return internal::GetConstRefAtOffset<Type>(message,
+                                             schema_.GetFieldOffset(field));
+}
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MESSAGE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/message_lite.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/message_lite.h
new file mode 100644
index 0000000..950ae1a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/message_lite.h
@@ -0,0 +1,591 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Authors: wink@google.com (Wink Saville),
+//          kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Defines MessageLite, the abstract interface implemented by all (lite
+// and non-lite) protocol message objects.
+
+#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__
+#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
+
+
+#include <climits>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/explicitly_constructed.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/stubs/hash.h>  // TODO(b/211442718): cleanup
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+template <typename T>
+class RepeatedPtrField;
+
+class FastReflectionMessageMutator;
+class FastReflectionStringSetter;
+class Reflection;
+
+namespace io {
+
+class CodedInputStream;
+class CodedOutputStream;
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+
+}  // namespace io
+namespace internal {
+
+class SwapFieldHelper;
+
+// See parse_context.h for explanation
+class ParseContext;
+
+class ExtensionSet;
+class LazyField;
+class RepeatedPtrFieldBase;
+class TcParser;
+class WireFormatLite;
+class WeakFieldMap;
+
+template <typename Type>
+class GenericTypeHandler;  // defined in repeated_field.h
+
+// We compute sizes as size_t but cache them as int.  This function converts a
+// computed size to a cached size.  Since we don't proceed with serialization
+// if the total size was > INT_MAX, it is not important what this function
+// returns for inputs > INT_MAX.  However this case should not error or
+// GOOGLE_CHECK-fail, because the full size_t resolution is still returned from
+// ByteSizeLong() and checked against INT_MAX; we can catch the overflow
+// there.
+inline int ToCachedSize(size_t size) { return static_cast<int>(size); }
+
+// We mainly calculate sizes in terms of size_t, but some functions that
+// compute sizes return "int".  These int sizes are expected to always be
+// positive. This function is more efficient than casting an int to size_t
+// directly on 64-bit platforms because it avoids making the compiler emit a
+// sign extending instruction, which we don't want and don't want to pay for.
+inline size_t FromIntSize(int size) {
+  // Convert to unsigned before widening so sign extension is not necessary.
+  return static_cast<unsigned int>(size);
+}
+
+// For cases where a legacy function returns an integer size.  We GOOGLE_DCHECK()
+// that the conversion will fit within an integer; if this is false then we
+// are losing information.
+inline int ToIntSize(size_t size) {
+  GOOGLE_DCHECK_LE(size, static_cast<size_t>(INT_MAX));
+  return static_cast<int>(size);
+}
+
+// Default empty string object. Don't use this directly. Instead, call
+// GetEmptyString() to get the reference. This empty string is aligned with a
+// minimum alignment of 8 bytes to match the requirement of ArenaStringPtr.
+PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
+    fixed_address_empty_string;
+
+
+PROTOBUF_EXPORT constexpr const std::string& GetEmptyStringAlreadyInited() {
+  return fixed_address_empty_string.get();
+}
+
+PROTOBUF_EXPORT size_t StringSpaceUsedExcludingSelfLong(const std::string& str);
+
+}  // namespace internal
+
+// Interface to light weight protocol messages.
+//
+// This interface is implemented by all protocol message objects.  Non-lite
+// messages additionally implement the Message interface, which is a
+// subclass of MessageLite.  Use MessageLite instead when you only need
+// the subset of features which it supports -- namely, nothing that uses
+// descriptors or reflection.  You can instruct the protocol compiler
+// to generate classes which implement only MessageLite, not the full
+// Message interface, by adding the following line to the .proto file:
+//
+//   option optimize_for = LITE_RUNTIME;
+//
+// This is particularly useful on resource-constrained systems where
+// the full protocol buffers runtime library is too big.
+//
+// Note that on non-constrained systems (e.g. servers) when you need
+// to link in lots of protocol definitions, a better way to reduce
+// total code footprint is to use optimize_for = CODE_SIZE.  This
+// will make the generated code smaller while still supporting all the
+// same features (at the expense of speed).  optimize_for = LITE_RUNTIME
+// is best when you only have a small number of message types linked
+// into your binary, in which case the size of the protocol buffers
+// runtime itself is the biggest problem.
+//
+// Users must not derive from this class. Only the protocol compiler and
+// the internal library are allowed to create subclasses.
+class PROTOBUF_EXPORT MessageLite {
+ public:
+  constexpr MessageLite() {}
+  virtual ~MessageLite() = default;
+
+  // Basic Operations ------------------------------------------------
+
+  // Get the name of this message type, e.g. "foo.bar.BazProto".
+  virtual std::string GetTypeName() const = 0;
+
+  // Construct a new instance of the same type.  Ownership is passed to the
+  // caller.
+  MessageLite* New() const { return New(nullptr); }
+
+  // Construct a new instance on the arena. Ownership is passed to the caller
+  // if arena is a nullptr.
+  virtual MessageLite* New(Arena* arena) const = 0;
+
+  // Returns user-owned arena; nullptr if it's message owned.
+  Arena* GetArena() const { return _internal_metadata_.user_arena(); }
+
+  // Clear all fields of the message and set them to their default values.
+  // Clear() assumes that any memory allocated to hold parts of the message
+  // will likely be needed again, so the memory used may not be freed.
+  // To ensure that all memory used by a Message is freed, you must delete it.
+  virtual void Clear() = 0;
+
+  // Quickly check if all required fields have values set.
+  virtual bool IsInitialized() const = 0;
+
+  // This is not implemented for Lite messages -- it just returns "(cannot
+  // determine missing fields for lite message)".  However, it is implemented
+  // for full messages.  See message.h.
+  virtual std::string InitializationErrorString() const;
+
+  // If |other| is the exact same class as this, calls MergeFrom(). Otherwise,
+  // results are undefined (probably crash).
+  virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0;
+
+  // These methods return a human-readable summary of the message. Note that
+  // since the MessageLite interface does not support reflection, there is very
+  // little information that these methods can provide. They are shadowed by
+  // methods of the same name on the Message interface which provide much more
+  // information. The methods here are intended primarily to facilitate code
+  // reuse for logic that needs to interoperate with both full and lite protos.
+  //
+  // The format of the returned string is subject to change, so please do not
+  // assume it will remain stable over time.
+  std::string DebugString() const;
+  std::string ShortDebugString() const { return DebugString(); }
+  // MessageLite::DebugString is already Utf8 Safe. This is to add compatibility
+  // with Message.
+  std::string Utf8DebugString() const { return DebugString(); }
+
+  // Parsing ---------------------------------------------------------
+  // Methods for parsing in protocol buffer format.  Most of these are
+  // just simple wrappers around MergeFromCodedStream().  Clear() will be
+  // called before merging the input.
+
+  // Fill the message with a protocol buffer parsed from the given input
+  // stream. Returns false on a read error or if the input is in the wrong
+  // format.  A successful return does not indicate the entire input is
+  // consumed, ensure you call ConsumedEntireMessage() to check that if
+  // applicable.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromCodedStream(
+      io::CodedInputStream* input);
+  // Like ParseFromCodedStream(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromCodedStream(
+      io::CodedInputStream* input);
+  // Read a protocol buffer from the given zero-copy input stream.  If
+  // successful, the entire input will be consumed.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromZeroCopyStream(
+      io::ZeroCopyInputStream* input);
+  // Like ParseFromZeroCopyStream(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromZeroCopyStream(
+      io::ZeroCopyInputStream* input);
+  // Parse a protocol buffer from a file descriptor.  If successful, the entire
+  // input will be consumed.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromFileDescriptor(
+      int file_descriptor);
+  // Like ParseFromFileDescriptor(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromFileDescriptor(
+      int file_descriptor);
+  // Parse a protocol buffer from a C++ istream.  If successful, the entire
+  // input will be consumed.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromIstream(std::istream* input);
+  // Like ParseFromIstream(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromIstream(
+      std::istream* input);
+  // Read a protocol buffer from the given zero-copy input stream, expecting
+  // the message to be exactly "size" bytes long.  If successful, exactly
+  // this many bytes will have been consumed from the input.
+  bool MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                             int size);
+  // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+  // missing required fields.
+  bool MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromBoundedZeroCopyStream(
+      io::ZeroCopyInputStream* input, int size);
+  // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+  // missing required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromBoundedZeroCopyStream(
+      io::ZeroCopyInputStream* input, int size);
+  // Parses a protocol buffer contained in a string. Returns true on success.
+  // This function takes a string in the (non-human-readable) binary wire
+  // format, matching the encoding output by MessageLite::SerializeToString().
+  // If you'd like to convert a human-readable string into a protocol buffer
+  // object, see google::protobuf::TextFormat::ParseFromString().
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromString(ConstStringParam data);
+  // Like ParseFromString(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromString(
+      ConstStringParam data);
+  // Parse a protocol buffer contained in an array of bytes.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromArray(const void* data,
+                                                       int size);
+  // Like ParseFromArray(), but accepts messages that are missing
+  // required fields.
+  PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromArray(const void* data,
+                                                              int size);
+
+
+  // Reads a protocol buffer from the stream and merges it into this
+  // Message.  Singular fields read from the what is
+  // already in the Message and repeated fields are appended to those
+  // already present.
+  //
+  // It is the responsibility of the caller to call input->LastTagWas()
+  // (for groups) or input->ConsumedEntireMessage() (for non-groups) after
+  // this returns to verify that the message's end was delimited correctly.
+  //
+  // ParseFromCodedStream() is implemented as Clear() followed by
+  // MergeFromCodedStream().
+  bool MergeFromCodedStream(io::CodedInputStream* input);
+
+  // Like MergeFromCodedStream(), but succeeds even if required fields are
+  // missing in the input.
+  //
+  // MergeFromCodedStream() is just implemented as MergePartialFromCodedStream()
+  // followed by IsInitialized().
+  bool MergePartialFromCodedStream(io::CodedInputStream* input);
+
+  // Merge a protocol buffer contained in a string.
+  bool MergeFromString(ConstStringParam data);
+
+
+  // Serialization ---------------------------------------------------
+  // Methods for serializing in protocol buffer format.  Most of these
+  // are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
+
+  // Write a protocol buffer of this message to the given output.  Returns
+  // false on a write error.  If the message is missing required fields,
+  // this may GOOGLE_CHECK-fail.
+  bool SerializeToCodedStream(io::CodedOutputStream* output) const;
+  // Like SerializeToCodedStream(), but allows missing required fields.
+  bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;
+  // Write the message to the given zero-copy output stream.  All required
+  // fields must be set.
+  bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
+  // Like SerializeToZeroCopyStream(), but allows missing required fields.
+  bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
+  // Serialize the message and store it in the given string.  All required
+  // fields must be set.
+  bool SerializeToString(std::string* output) const;
+  // Like SerializeToString(), but allows missing required fields.
+  bool SerializePartialToString(std::string* output) const;
+  // Serialize the message and store it in the given byte array.  All required
+  // fields must be set.
+  bool SerializeToArray(void* data, int size) const;
+  // Like SerializeToArray(), but allows missing required fields.
+  bool SerializePartialToArray(void* data, int size) const;
+
+  // Make a string encoding the message. Is equivalent to calling
+  // SerializeToString() on a string and using that.  Returns the empty
+  // string if SerializeToString() would have returned an error.
+  // Note: If you intend to generate many such strings, you may
+  // reduce heap fragmentation by instead re-using the same string
+  // object with calls to SerializeToString().
+  std::string SerializeAsString() const;
+  // Like SerializeAsString(), but allows missing required fields.
+  std::string SerializePartialAsString() const;
+
+  // Serialize the message and write it to the given file descriptor.  All
+  // required fields must be set.
+  bool SerializeToFileDescriptor(int file_descriptor) const;
+  // Like SerializeToFileDescriptor(), but allows missing required fields.
+  bool SerializePartialToFileDescriptor(int file_descriptor) const;
+  // Serialize the message and write it to the given C++ ostream.  All
+  // required fields must be set.
+  bool SerializeToOstream(std::ostream* output) const;
+  // Like SerializeToOstream(), but allows missing required fields.
+  bool SerializePartialToOstream(std::ostream* output) const;
+
+  // Like SerializeToString(), but appends to the data to the string's
+  // existing contents.  All required fields must be set.
+  bool AppendToString(std::string* output) const;
+  // Like AppendToString(), but allows missing required fields.
+  bool AppendPartialToString(std::string* output) const;
+
+
+  // Computes the serialized size of the message.  This recursively calls
+  // ByteSizeLong() on all embedded messages.
+  //
+  // ByteSizeLong() is generally linear in the number of fields defined for the
+  // proto.
+  virtual size_t ByteSizeLong() const = 0;
+
+  // Legacy ByteSize() API.
+  PROTOBUF_DEPRECATED_MSG("Please use ByteSizeLong() instead")
+  int ByteSize() const { return internal::ToIntSize(ByteSizeLong()); }
+
+  // Serializes the message without recomputing the size.  The message must not
+  // have changed since the last call to ByteSize(), and the value returned by
+  // ByteSize must be non-negative.  Otherwise the results are undefined.
+  void SerializeWithCachedSizes(io::CodedOutputStream* output) const {
+    output->SetCur(_InternalSerialize(output->Cur(), output->EpsCopy()));
+  }
+
+  // Functions below here are not part of the public interface.  It isn't
+  // enforced, but they should be treated as private, and will be private
+  // at some future time.  Unfortunately the implementation of the "friend"
+  // keyword in GCC is broken at the moment, but we expect it will be fixed.
+
+  // Like SerializeWithCachedSizes, but writes directly to *target, returning
+  // a pointer to the byte immediately after the last byte written.  "target"
+  // must point at a byte array of at least ByteSize() bytes.  Whether to use
+  // deterministic serialization, e.g., maps in sorted order, is determined by
+  // CodedOutputStream::IsDefaultSerializationDeterministic().
+  uint8_t* SerializeWithCachedSizesToArray(uint8_t* target) const;
+
+  // Returns the result of the last call to ByteSize().  An embedded message's
+  // size is needed both to serialize it (because embedded messages are
+  // length-delimited) and to compute the outer message's size.  Caching
+  // the size avoids computing it multiple times.
+  //
+  // ByteSize() does not automatically use the cached size when available
+  // because this would require invalidating it every time the message was
+  // modified, which would be too hard and expensive.  (E.g. if a deeply-nested
+  // sub-message is changed, all of its parents' cached sizes would need to be
+  // invalidated, which is too much work for an otherwise inlined setter
+  // method.)
+  virtual int GetCachedSize() const = 0;
+
+  virtual const char* _InternalParse(const char* /*ptr*/,
+                                     internal::ParseContext* /*ctx*/) {
+    return nullptr;
+  }
+
+  virtual void OnDemandRegisterArenaDtor(Arena* /*arena*/) {}
+
+ protected:
+  template <typename T>
+  static T* CreateMaybeMessage(Arena* arena) {
+    return Arena::CreateMaybeMessage<T>(arena);
+  }
+
+  inline explicit MessageLite(Arena* arena, bool is_message_owned = false)
+      : _internal_metadata_(arena, is_message_owned) {}
+
+  // Returns the arena, if any, that directly owns this message and its internal
+  // memory (Arena::Own is different in that the arena doesn't directly own the
+  // internal memory). This method is used in proto's implementation for
+  // swapping, moving and setting allocated, for deciding whether the ownership
+  // of this message or its internal memory could be changed.
+  Arena* GetOwningArena() const { return _internal_metadata_.owning_arena(); }
+
+  // Returns the arena, used for allocating internal objects(e.g., child
+  // messages, etc), or owning incoming objects (e.g., set allocated).
+  Arena* GetArenaForAllocation() const { return _internal_metadata_.arena(); }
+
+  // Returns true if this message is enabled for message-owned arena (MOA)
+  // trials. No lite messages are eligible for MOA.
+  static bool InMoaTrial() { return false; }
+
+  internal::InternalMetadata _internal_metadata_;
+
+ public:
+  enum ParseFlags {
+    kMerge = 0,
+    kParse = 1,
+    kMergePartial = 2,
+    kParsePartial = 3,
+    kMergeWithAliasing = 4,
+    kParseWithAliasing = 5,
+    kMergePartialWithAliasing = 6,
+    kParsePartialWithAliasing = 7
+  };
+
+  template <ParseFlags flags, typename T>
+  bool ParseFrom(const T& input);
+
+  // Fast path when conditions match (ie. non-deterministic)
+  //  uint8_t* _InternalSerialize(uint8_t* ptr) const;
+  virtual uint8_t* _InternalSerialize(
+      uint8_t* ptr, io::EpsCopyOutputStream* stream) const = 0;
+
+  // Identical to IsInitialized() except that it logs an error message.
+  bool IsInitializedWithErrors() const {
+    if (IsInitialized()) return true;
+    LogInitializationErrorMessage();
+    return false;
+  }
+
+ private:
+  friend class FastReflectionMessageMutator;
+  friend class FastReflectionStringSetter;
+  friend class Message;
+  friend class Reflection;
+  friend class internal::ExtensionSet;
+  friend class internal::LazyField;
+  friend class internal::SwapFieldHelper;
+  friend class internal::TcParser;
+  friend class internal::WeakFieldMap;
+  friend class internal::WireFormatLite;
+
+  template <typename Type>
+  friend class Arena::InternalHelper;
+  template <typename Type>
+  friend class internal::GenericTypeHandler;
+
+  void LogInitializationErrorMessage() const;
+
+  bool MergeFromImpl(io::CodedInputStream* input, ParseFlags parse_flags);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
+};
+
+namespace internal {
+
+template <bool alias>
+bool MergeFromImpl(StringPiece input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<false>(StringPiece input,
+                                          MessageLite* msg,
+                                          MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<true>(StringPiece input,
+                                         MessageLite* msg,
+                                         MessageLite::ParseFlags parse_flags);
+
+template <bool alias>
+bool MergeFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<false>(io::ZeroCopyInputStream* input,
+                                          MessageLite* msg,
+                                          MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<true>(io::ZeroCopyInputStream* input,
+                                         MessageLite* msg,
+                                         MessageLite::ParseFlags parse_flags);
+
+struct BoundedZCIS {
+  io::ZeroCopyInputStream* zcis;
+  int limit;
+};
+
+template <bool alias>
+bool MergeFromImpl(BoundedZCIS input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<false>(BoundedZCIS input, MessageLite* msg,
+                                          MessageLite::ParseFlags parse_flags);
+extern template bool MergeFromImpl<true>(BoundedZCIS input, MessageLite* msg,
+                                         MessageLite::ParseFlags parse_flags);
+
+template <typename T>
+struct SourceWrapper;
+
+template <bool alias, typename T>
+bool MergeFromImpl(const SourceWrapper<T>& input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  return input.template MergeInto<alias>(msg, parse_flags);
+}
+
+}  // namespace internal
+
+template <MessageLite::ParseFlags flags, typename T>
+bool MessageLite::ParseFrom(const T& input) {
+  if (flags & kParse) Clear();
+  constexpr bool alias = (flags & kMergeWithAliasing) != 0;
+  return internal::MergeFromImpl<alias>(input, this, flags);
+}
+
+// ===================================================================
+// Shutdown support.
+
+
+// Shut down the entire protocol buffers library, deleting all static-duration
+// objects allocated by the library or by generated .pb.cc files.
+//
+// There are two reasons you might want to call this:
+// * You use a draconian definition of "memory leak" in which you expect
+//   every single malloc() to have a corresponding free(), even for objects
+//   which live until program exit.
+// * You are writing a dynamically-loaded library which needs to clean up
+//   after itself when the library is unloaded.
+//
+// It is safe to call this multiple times.  However, it is not safe to use
+// any other part of the protocol buffers library after
+// ShutdownProtobufLibrary() has been called. Furthermore this call is not
+// thread safe, user needs to synchronize multiple calls.
+PROTOBUF_EXPORT void ShutdownProtobufLibrary();
+
+namespace internal {
+
+// Register a function to be called when ShutdownProtocolBuffers() is called.
+PROTOBUF_EXPORT void OnShutdown(void (*func)());
+// Run an arbitrary function on an arg
+PROTOBUF_EXPORT void OnShutdownRun(void (*f)(const void*), const void* arg);
+
+template <typename T>
+T* OnShutdownDelete(T* p) {
+  OnShutdownRun([](const void* pp) { delete static_cast<const T*>(pp); }, p);
+  return p;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_MESSAGE_LITE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/metadata.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/metadata.h
new file mode 100644
index 0000000..4e89648
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/metadata.h
@@ -0,0 +1,36 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_METADATA_H__
+#define GOOGLE_PROTOBUF_METADATA_H__
+
+// TODO(b/151117630): Remove this file and all instances where it gets imported.
+
+#endif  // GOOGLE_PROTOBUF_METADATA_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/metadata_lite.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/metadata_lite.h
new file mode 100644
index 0000000..0c31517
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/metadata_lite.h
@@ -0,0 +1,316 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_METADATA_LITE_H__
+#define GOOGLE_PROTOBUF_METADATA_LITE_H__
+
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This is the representation for messages that support arena allocation. It
+// uses a tagged pointer to either store the owning Arena pointer, if there are
+// no unknown fields, or a pointer to a block of memory with both the owning
+// Arena pointer and the UnknownFieldSet, if there are unknown fields. Besides,
+// it also uses the tag to distinguish whether the owning Arena pointer is also
+// used by sub-structure allocation. This optimization allows for
+// "zero-overhead" storage of the Arena pointer, relative to the above baseline
+// implementation.
+//
+// The tagged pointer uses the least two significant bits to disambiguate cases.
+// It uses bit 0 == 0 to indicate an arena pointer and bit 0 == 1 to indicate a
+// UFS+Arena-container pointer. Besides it uses bit 1 == 0 to indicate arena
+// allocation and bit 1 == 1 to indicate heap allocation.
+class PROTOBUF_EXPORT InternalMetadata {
+ public:
+  constexpr InternalMetadata() : ptr_(0) {}
+  explicit InternalMetadata(Arena* arena, bool is_message_owned = false) {
+    SetArena(arena, is_message_owned);
+  }
+
+  void SetArena(Arena* arena, bool is_message_owned) {
+    ptr_ = is_message_owned
+               ? reinterpret_cast<intptr_t>(arena) | kMessageOwnedArenaTagMask
+               : reinterpret_cast<intptr_t>(arena);
+    GOOGLE_DCHECK(!is_message_owned || arena != nullptr);
+  }
+
+  // To keep the ABI identical between debug and non-debug builds,
+  // the destructor is always defined here even though it may delegate
+  // to a non-inline private method.
+  // (see https://github.com/protocolbuffers/protobuf/issues/9947)
+  ~InternalMetadata() {
+#if defined(NDEBUG) || defined(_MSC_VER)
+    if (HasMessageOwnedArenaTag()) {
+      delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
+    }
+#else
+    CheckedDestruct();
+#endif
+  }
+
+  template <typename T>
+  void Delete() {
+    // Note that Delete<> should be called not more than once.
+    if (have_unknown_fields()) {
+      DeleteOutOfLineHelper<T>();
+    }
+  }
+
+  // DeleteReturnArena will delete the unknown fields only if they weren't
+  // allocated on an arena.  Then it updates the flags so that if you call
+  // have_unknown_fields(), it will return false.  Finally, it returns the
+  // current value of arena().  It is designed to be used as part of a
+  // Message class's destructor call, so that when control eventually gets
+  // to ~InternalMetadata(), we don't need to check for have_unknown_fields()
+  // again.
+  template <typename T>
+  Arena* DeleteReturnArena() {
+    if (have_unknown_fields()) {
+      return DeleteOutOfLineHelper<T>();
+    } else {
+      return PtrValue<Arena>();
+    }
+  }
+
+  PROTOBUF_NDEBUG_INLINE Arena* owning_arena() const {
+    return HasMessageOwnedArenaTag() ? nullptr : arena();
+  }
+
+  PROTOBUF_NDEBUG_INLINE Arena* user_arena() const {
+    Arena* a = arena();
+    return a && !a->IsMessageOwned() ? a : nullptr;
+  }
+
+  PROTOBUF_NDEBUG_INLINE Arena* arena() const {
+    if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
+      return PtrValue<ContainerBase>()->arena;
+    } else {
+      return PtrValue<Arena>();
+    }
+  }
+
+  PROTOBUF_NDEBUG_INLINE bool have_unknown_fields() const {
+    return HasUnknownFieldsTag();
+  }
+
+  PROTOBUF_NDEBUG_INLINE void* raw_arena_ptr() const {
+    return reinterpret_cast<void*>(ptr_);
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE const T& unknown_fields(
+      const T& (*default_instance)()) const {
+    if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
+      return PtrValue<Container<T>>()->unknown_fields;
+    } else {
+      return default_instance();
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE T* mutable_unknown_fields() {
+    if (PROTOBUF_PREDICT_TRUE(have_unknown_fields())) {
+      return &PtrValue<Container<T>>()->unknown_fields;
+    } else {
+      return mutable_unknown_fields_slow<T>();
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE void Swap(InternalMetadata* other) {
+    // Semantics here are that we swap only the unknown fields, not the arena
+    // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
+    // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
+    // different states (direct arena pointer vs. container with UFS) so we
+    // cannot simply swap ptr_ and then restore the arena pointers. We reuse
+    // UFS's swap implementation instead.
+    if (have_unknown_fields() || other->have_unknown_fields()) {
+      DoSwap<T>(other->mutable_unknown_fields<T>());
+    }
+  }
+
+  PROTOBUF_NDEBUG_INLINE void InternalSwap(InternalMetadata* other) {
+    std::swap(ptr_, other->ptr_);
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE void MergeFrom(const InternalMetadata& other) {
+    if (other.have_unknown_fields()) {
+      DoMergeFrom<T>(other.unknown_fields<T>(nullptr));
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE void Clear() {
+    if (have_unknown_fields()) {
+      DoClear<T>();
+    }
+  }
+
+ private:
+  intptr_t ptr_;
+
+  // Tagged pointer implementation.
+  static constexpr intptr_t kUnknownFieldsTagMask = 1;
+  static constexpr intptr_t kMessageOwnedArenaTagMask = 2;
+  static constexpr intptr_t kPtrTagMask =
+      kUnknownFieldsTagMask | kMessageOwnedArenaTagMask;
+  static constexpr intptr_t kPtrValueMask = ~kPtrTagMask;
+
+  // Accessors for pointer tag and pointer value.
+  PROTOBUF_ALWAYS_INLINE bool HasUnknownFieldsTag() const {
+    return ptr_ & kUnknownFieldsTagMask;
+  }
+  PROTOBUF_ALWAYS_INLINE bool HasMessageOwnedArenaTag() const {
+    return ptr_ & kMessageOwnedArenaTagMask;
+  }
+
+  template <typename U>
+  U* PtrValue() const {
+    return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
+  }
+
+  // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
+  struct ContainerBase {
+    Arena* arena;
+  };
+
+  template <typename T>
+  struct Container : public ContainerBase {
+    T unknown_fields;
+  };
+
+  template <typename T>
+  PROTOBUF_NOINLINE Arena* DeleteOutOfLineHelper() {
+    if (auto* a = arena()) {
+      // Subtle: we want to preserve the message-owned arena flag, while at the
+      // same time replacing the pointer to Container<T> with a pointer to the
+      // arena.
+      intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
+      ptr_ = reinterpret_cast<intptr_t>(a) | message_owned_arena_tag;
+      return a;
+    } else {
+      delete PtrValue<Container<T>>();
+      ptr_ = 0;
+      return nullptr;
+    }
+  }
+
+  template <typename T>
+  PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() {
+    Arena* my_arena = arena();
+    Container<T>* container = Arena::Create<Container<T>>(my_arena);
+    intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
+    // Two-step assignment works around a bug in clang's static analyzer:
+    // https://bugs.llvm.org/show_bug.cgi?id=34198.
+    ptr_ = reinterpret_cast<intptr_t>(container);
+    ptr_ |= kUnknownFieldsTagMask | message_owned_arena_tag;
+    container->arena = my_arena;
+    return &(container->unknown_fields);
+  }
+
+  // Templated functions.
+
+  template <typename T>
+  PROTOBUF_NOINLINE void DoClear() {
+    mutable_unknown_fields<T>()->Clear();
+  }
+
+  template <typename T>
+  PROTOBUF_NOINLINE void DoMergeFrom(const T& other) {
+    mutable_unknown_fields<T>()->MergeFrom(other);
+  }
+
+  template <typename T>
+  PROTOBUF_NOINLINE void DoSwap(T* other) {
+    mutable_unknown_fields<T>()->Swap(other);
+  }
+
+  // Private helper with debug checks for ~InternalMetadata()
+  void CheckedDestruct();
+};
+
+// String Template specializations.
+
+template <>
+PROTOBUF_EXPORT void InternalMetadata::DoClear<std::string>();
+template <>
+PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom<std::string>(
+    const std::string& other);
+template <>
+PROTOBUF_EXPORT void InternalMetadata::DoSwap<std::string>(std::string* other);
+
+// This helper RAII class is needed to efficiently parse unknown fields. We
+// should only call mutable_unknown_fields if there are actual unknown fields.
+// The obvious thing to just use a stack string and swap it at the end of
+// the parse won't work, because the destructor of StringOutputStream needs to
+// be called before we can modify the string (it check-fails). Using
+// LiteUnknownFieldSetter setter(&_internal_metadata_);
+// StringOutputStream stream(setter.buffer());
+// guarantees that the string is only swapped after stream is destroyed.
+class PROTOBUF_EXPORT LiteUnknownFieldSetter {
+ public:
+  explicit LiteUnknownFieldSetter(InternalMetadata* metadata)
+      : metadata_(metadata) {
+    if (metadata->have_unknown_fields()) {
+      buffer_.swap(*metadata->mutable_unknown_fields<std::string>());
+    }
+  }
+  ~LiteUnknownFieldSetter() {
+    if (!buffer_.empty())
+      metadata_->mutable_unknown_fields<std::string>()->swap(buffer_);
+  }
+  std::string* buffer() { return &buffer_; }
+
+ private:
+  InternalMetadata* metadata_;
+  std::string buffer_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_METADATA_LITE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/parse_context.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/parse_context.h
new file mode 100644
index 0000000..97daae0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/parse_context.h
@@ -0,0 +1,1033 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
+#define GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <type_traits>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/endian.h>
+#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/inlined_string_field.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class UnknownFieldSet;
+class DescriptorPool;
+class MessageFactory;
+
+namespace internal {
+
+// Template code below needs to know about the existence of these functions.
+PROTOBUF_EXPORT void WriteVarint(uint32_t num, uint64_t val, std::string* s);
+PROTOBUF_EXPORT void WriteLengthDelimited(uint32_t num, StringPiece val,
+                                          std::string* s);
+// Inline because it is just forwarding to s->WriteVarint
+inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* s);
+inline void WriteLengthDelimited(uint32_t num, StringPiece val,
+                                 UnknownFieldSet* s);
+
+
+// The basic abstraction the parser is designed for is a slight modification
+// of the ZeroCopyInputStream (ZCIS) abstraction. A ZCIS presents a serialized
+// stream as a series of buffers that concatenate to the full stream.
+// Pictorially a ZCIS presents a stream in chunks like so
+// [---------------------------------------------------------------]
+// [---------------------] chunk 1
+//                      [----------------------------] chunk 2
+//                                          chunk 3 [--------------]
+//
+// Where the '-' represent the bytes which are vertically lined up with the
+// bytes of the stream. The proto parser requires its input to be presented
+// similarly with the extra
+// property that each chunk has kSlopBytes past its end that overlaps with the
+// first kSlopBytes of the next chunk, or if there is no next chunk at least its
+// still valid to read those bytes. Again, pictorially, we now have
+//
+// [---------------------------------------------------------------]
+// [-------------------....] chunk 1
+//                    [------------------------....] chunk 2
+//                                    chunk 3 [------------------..**]
+//                                                      chunk 4 [--****]
+// Here '-' mean the bytes of the stream or chunk and '.' means bytes past the
+// chunk that match up with the start of the next chunk. Above each chunk has
+// 4 '.' after the chunk. In the case these 'overflow' bytes represents bytes
+// past the stream, indicated by '*' above, their values are unspecified. It is
+// still legal to read them (ie. should not segfault). Reading past the
+// end should be detected by the user and indicated as an error.
+//
+// The reason for this, admittedly, unconventional invariant is to ruthlessly
+// optimize the protobuf parser. Having an overlap helps in two important ways.
+// Firstly it alleviates having to performing bounds checks if a piece of code
+// is guaranteed to not read more than kSlopBytes. Secondly, and more
+// importantly, the protobuf wireformat is such that reading a key/value pair is
+// always less than 16 bytes. This removes the need to change to next buffer in
+// the middle of reading primitive values. Hence there is no need to store and
+// load the current position.
+
+class PROTOBUF_EXPORT EpsCopyInputStream {
+ public:
+  enum { kSlopBytes = 16, kMaxCordBytesToCopy = 512 };
+
+  explicit EpsCopyInputStream(bool enable_aliasing)
+      : aliasing_(enable_aliasing ? kOnPatch : kNoAliasing) {}
+
+  void BackUp(const char* ptr) {
+    GOOGLE_DCHECK(ptr <= buffer_end_ + kSlopBytes);
+    int count;
+    if (next_chunk_ == buffer_) {
+      count = static_cast<int>(buffer_end_ + kSlopBytes - ptr);
+    } else {
+      count = size_ + static_cast<int>(buffer_end_ - ptr);
+    }
+    if (count > 0) StreamBackUp(count);
+  }
+
+  // If return value is negative it's an error
+  PROTOBUF_NODISCARD int PushLimit(const char* ptr, int limit) {
+    GOOGLE_DCHECK(limit >= 0 && limit <= INT_MAX - kSlopBytes);
+    // This add is safe due to the invariant above, because
+    // ptr - buffer_end_ <= kSlopBytes.
+    limit += static_cast<int>(ptr - buffer_end_);
+    limit_end_ = buffer_end_ + (std::min)(0, limit);
+    auto old_limit = limit_;
+    limit_ = limit;
+    return old_limit - limit;
+  }
+
+  PROTOBUF_NODISCARD bool PopLimit(int delta) {
+    if (PROTOBUF_PREDICT_FALSE(!EndedAtLimit())) return false;
+    limit_ = limit_ + delta;
+    // TODO(gerbens) We could remove this line and hoist the code to
+    // DoneFallback. Study the perf/bin-size effects.
+    limit_end_ = buffer_end_ + (std::min)(0, limit_);
+    return true;
+  }
+
+  PROTOBUF_NODISCARD const char* Skip(const char* ptr, int size) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      return ptr + size;
+    }
+    return SkipFallback(ptr, size);
+  }
+  PROTOBUF_NODISCARD const char* ReadString(const char* ptr, int size,
+                                            std::string* s) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      s->assign(ptr, size);
+      return ptr + size;
+    }
+    return ReadStringFallback(ptr, size, s);
+  }
+  PROTOBUF_NODISCARD const char* AppendString(const char* ptr, int size,
+                                              std::string* s) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      s->append(ptr, size);
+      return ptr + size;
+    }
+    return AppendStringFallback(ptr, size, s);
+  }
+  // Implemented in arenastring.cc
+  PROTOBUF_NODISCARD const char* ReadArenaString(const char* ptr,
+                                                 ArenaStringPtr* s,
+                                                 Arena* arena);
+
+  template <typename Tag, typename T>
+  PROTOBUF_NODISCARD const char* ReadRepeatedFixed(const char* ptr,
+                                                   Tag expected_tag,
+                                                   RepeatedField<T>* out);
+
+  template <typename T>
+  PROTOBUF_NODISCARD const char* ReadPackedFixed(const char* ptr, int size,
+                                                 RepeatedField<T>* out);
+  template <typename Add>
+  PROTOBUF_NODISCARD const char* ReadPackedVarint(const char* ptr, Add add);
+
+  uint32_t LastTag() const { return last_tag_minus_1_ + 1; }
+  bool ConsumeEndGroup(uint32_t start_tag) {
+    bool res = last_tag_minus_1_ == start_tag;
+    last_tag_minus_1_ = 0;
+    return res;
+  }
+  bool EndedAtLimit() const { return last_tag_minus_1_ == 0; }
+  bool EndedAtEndOfStream() const { return last_tag_minus_1_ == 1; }
+  void SetLastTag(uint32_t tag) { last_tag_minus_1_ = tag - 1; }
+  void SetEndOfStream() { last_tag_minus_1_ = 1; }
+  bool IsExceedingLimit(const char* ptr) {
+    return ptr > limit_end_ &&
+           (next_chunk_ == nullptr || ptr - buffer_end_ > limit_);
+  }
+  bool AliasingEnabled() const { return aliasing_ != kNoAliasing; }
+  int BytesUntilLimit(const char* ptr) const {
+    return limit_ + static_cast<int>(buffer_end_ - ptr);
+  }
+  // Returns true if more data is available, if false is returned one has to
+  // call Done for further checks.
+  bool DataAvailable(const char* ptr) { return ptr < limit_end_; }
+
+ protected:
+  // Returns true is limit (either an explicit limit or end of stream) is
+  // reached. It aligns *ptr across buffer seams.
+  // If limit is exceeded it returns true and ptr is set to null.
+  bool DoneWithCheck(const char** ptr, int d) {
+    GOOGLE_DCHECK(*ptr);
+    if (PROTOBUF_PREDICT_TRUE(*ptr < limit_end_)) return false;
+    int overrun = static_cast<int>(*ptr - buffer_end_);
+    GOOGLE_DCHECK_LE(overrun, kSlopBytes);  // Guaranteed by parse loop.
+    if (overrun ==
+        limit_) {  //  No need to flip buffers if we ended on a limit.
+      // If we actually overrun the buffer and next_chunk_ is null. It means
+      // the stream ended and we passed the stream end.
+      if (overrun > 0 && next_chunk_ == nullptr) *ptr = nullptr;
+      return true;
+    }
+    auto res = DoneFallback(overrun, d);
+    *ptr = res.first;
+    return res.second;
+  }
+
+  const char* InitFrom(StringPiece flat) {
+    overall_limit_ = 0;
+    if (flat.size() > kSlopBytes) {
+      limit_ = kSlopBytes;
+      limit_end_ = buffer_end_ = flat.data() + flat.size() - kSlopBytes;
+      next_chunk_ = buffer_;
+      if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+      return flat.data();
+    } else {
+      std::memcpy(buffer_, flat.data(), flat.size());
+      limit_ = 0;
+      limit_end_ = buffer_end_ = buffer_ + flat.size();
+      next_chunk_ = nullptr;
+      if (aliasing_ == kOnPatch) {
+        aliasing_ = reinterpret_cast<std::uintptr_t>(flat.data()) -
+                    reinterpret_cast<std::uintptr_t>(buffer_);
+      }
+      return buffer_;
+    }
+  }
+
+  const char* InitFrom(io::ZeroCopyInputStream* zcis);
+
+  const char* InitFrom(io::ZeroCopyInputStream* zcis, int limit) {
+    if (limit == -1) return InitFrom(zcis);
+    overall_limit_ = limit;
+    auto res = InitFrom(zcis);
+    limit_ = limit - static_cast<int>(buffer_end_ - res);
+    limit_end_ = buffer_end_ + (std::min)(0, limit_);
+    return res;
+  }
+
+ private:
+  const char* limit_end_;  // buffer_end_ + min(limit_, 0)
+  const char* buffer_end_;
+  const char* next_chunk_;
+  int size_;
+  int limit_;  // relative to buffer_end_;
+  io::ZeroCopyInputStream* zcis_ = nullptr;
+  char buffer_[2 * kSlopBytes] = {};
+  enum { kNoAliasing = 0, kOnPatch = 1, kNoDelta = 2 };
+  std::uintptr_t aliasing_ = kNoAliasing;
+  // This variable is used to communicate how the parse ended, in order to
+  // completely verify the parsed data. A wire-format parse can end because of
+  // one of the following conditions:
+  // 1) A parse can end on a pushed limit.
+  // 2) A parse can end on End Of Stream (EOS).
+  // 3) A parse can end on 0 tag (only valid for toplevel message).
+  // 4) A parse can end on an end-group tag.
+  // This variable should always be set to 0, which indicates case 1. If the
+  // parse terminated due to EOS (case 2), it's set to 1. In case the parse
+  // ended due to a terminating tag (case 3 and 4) it's set to (tag - 1).
+  // This var doesn't really belong in EpsCopyInputStream and should be part of
+  // the ParseContext, but case 2 is most easily and optimally implemented in
+  // DoneFallback.
+  uint32_t last_tag_minus_1_ = 0;
+  int overall_limit_ = INT_MAX;  // Overall limit independent of pushed limits.
+  // Pretty random large number that seems like a safe allocation on most
+  // systems. TODO(gerbens) do we need to set this as build flag?
+  enum { kSafeStringSize = 50000000 };
+
+  // Advances to next buffer chunk returns a pointer to the same logical place
+  // in the stream as set by overrun. Overrun indicates the position in the slop
+  // region the parse was left (0 <= overrun <= kSlopBytes). Returns true if at
+  // limit, at which point the returned pointer maybe null if there was an
+  // error. The invariant of this function is that it's guaranteed that
+  // kSlopBytes bytes can be accessed from the returned ptr. This function might
+  // advance more buffers than one in the underlying ZeroCopyInputStream.
+  std::pair<const char*, bool> DoneFallback(int overrun, int depth);
+  // Advances to the next buffer, at most one call to Next() on the underlying
+  // ZeroCopyInputStream is made. This function DOES NOT match the returned
+  // pointer to where in the slop region the parse ends, hence no overrun
+  // parameter. This is useful for string operations where you always copy
+  // to the end of the buffer (including the slop region).
+  const char* Next();
+  // overrun is the location in the slop region the stream currently is
+  // (0 <= overrun <= kSlopBytes). To prevent flipping to the next buffer of
+  // the ZeroCopyInputStream in the case the parse will end in the last
+  // kSlopBytes of the current buffer. depth is the current depth of nested
+  // groups (or negative if the use case does not need careful tracking).
+  inline const char* NextBuffer(int overrun, int depth);
+  const char* SkipFallback(const char* ptr, int size);
+  const char* AppendStringFallback(const char* ptr, int size, std::string* str);
+  const char* ReadStringFallback(const char* ptr, int size, std::string* str);
+  bool StreamNext(const void** data) {
+    bool res = zcis_->Next(data, &size_);
+    if (res) overall_limit_ -= size_;
+    return res;
+  }
+  void StreamBackUp(int count) {
+    zcis_->BackUp(count);
+    overall_limit_ += count;
+  }
+
+  template <typename A>
+  const char* AppendSize(const char* ptr, int size, const A& append) {
+    int chunk_size = buffer_end_ + kSlopBytes - ptr;
+    do {
+      GOOGLE_DCHECK(size > chunk_size);
+      if (next_chunk_ == nullptr) return nullptr;
+      append(ptr, chunk_size);
+      ptr += chunk_size;
+      size -= chunk_size;
+      // TODO(gerbens) Next calls NextBuffer which generates buffers with
+      // overlap and thus incurs cost of copying the slop regions. This is not
+      // necessary for reading strings. We should just call Next buffers.
+      if (limit_ <= kSlopBytes) return nullptr;
+      ptr = Next();
+      if (ptr == nullptr) return nullptr;  // passed the limit
+      ptr += kSlopBytes;
+      chunk_size = buffer_end_ + kSlopBytes - ptr;
+    } while (size > chunk_size);
+    append(ptr, size);
+    return ptr + size;
+  }
+
+  // AppendUntilEnd appends data until a limit (either a PushLimit or end of
+  // stream. Normal payloads are from length delimited fields which have an
+  // explicit size. Reading until limit only comes when the string takes
+  // the place of a protobuf, ie RawMessage/StringRawMessage, lazy fields and
+  // implicit weak messages. We keep these methods private and friend them.
+  template <typename A>
+  const char* AppendUntilEnd(const char* ptr, const A& append) {
+    if (ptr - buffer_end_ > limit_) return nullptr;
+    while (limit_ > kSlopBytes) {
+      size_t chunk_size = buffer_end_ + kSlopBytes - ptr;
+      append(ptr, chunk_size);
+      ptr = Next();
+      if (ptr == nullptr) return limit_end_;
+      ptr += kSlopBytes;
+    }
+    auto end = buffer_end_ + limit_;
+    GOOGLE_DCHECK(end >= ptr);
+    append(ptr, end - ptr);
+    return end;
+  }
+
+  PROTOBUF_NODISCARD const char* AppendString(const char* ptr,
+                                              std::string* str) {
+    return AppendUntilEnd(
+        ptr, [str](const char* p, ptrdiff_t s) { str->append(p, s); });
+  }
+  friend class ImplicitWeakMessage;
+};
+
+using LazyEagerVerifyFnType = const char* (*)(const char* ptr,
+                                              ParseContext* ctx);
+using LazyEagerVerifyFnRef = std::remove_pointer<LazyEagerVerifyFnType>::type&;
+
+// ParseContext holds all data that is global to the entire parse. Most
+// importantly it contains the input stream, but also recursion depth and also
+// stores the end group tag, in case a parser ended on a endgroup, to verify
+// matching start/end group tags.
+class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream {
+ public:
+  struct Data {
+    const DescriptorPool* pool = nullptr;
+    MessageFactory* factory = nullptr;
+    Arena* arena = nullptr;
+  };
+
+  template <typename... T>
+  ParseContext(int depth, bool aliasing, const char** start, T&&... args)
+      : EpsCopyInputStream(aliasing), depth_(depth) {
+    *start = InitFrom(std::forward<T>(args)...);
+  }
+
+  void TrackCorrectEnding() { group_depth_ = 0; }
+
+  bool Done(const char** ptr) { return DoneWithCheck(ptr, group_depth_); }
+
+  int depth() const { return depth_; }
+
+  Data& data() { return data_; }
+  const Data& data() const { return data_; }
+
+  const char* ParseMessage(MessageLite* msg, const char* ptr);
+
+  // Spawns a child parsing context that inherits key properties. New context
+  // inherits the following:
+  // --depth_, data_, check_required_fields_, lazy_parse_mode_
+  // The spawned context always disables aliasing (different input).
+  template <typename... T>
+  ParseContext Spawn(const char** start, T&&... args) {
+    ParseContext spawned(depth_, false, start, std::forward<T>(args)...);
+    // Transfer key context states.
+    spawned.data_ = data_;
+    return spawned;
+  }
+
+  // This overload supports those few cases where ParseMessage is called
+  // on a class that is not actually a proto message.
+  // TODO(jorg): Eliminate this use case.
+  template <typename T,
+            typename std::enable_if<!std::is_base_of<MessageLite, T>::value,
+                                    bool>::type = true>
+  PROTOBUF_NODISCARD const char* ParseMessage(T* msg, const char* ptr);
+
+  template <typename T>
+  PROTOBUF_NODISCARD PROTOBUF_NDEBUG_INLINE const char* ParseGroup(
+      T* msg, const char* ptr, uint32_t tag) {
+    if (--depth_ < 0) return nullptr;
+    group_depth_++;
+    ptr = msg->_InternalParse(ptr, this);
+    group_depth_--;
+    depth_++;
+    if (PROTOBUF_PREDICT_FALSE(!ConsumeEndGroup(tag))) return nullptr;
+    return ptr;
+  }
+
+ private:
+  // Out-of-line routine to save space in ParseContext::ParseMessage<T>
+  //   int old;
+  //   ptr = ReadSizeAndPushLimitAndDepth(ptr, &old)
+  // is equivalent to:
+  //   int size = ReadSize(&ptr);
+  //   if (!ptr) return nullptr;
+  //   int old = PushLimit(ptr, size);
+  //   if (--depth_ < 0) return nullptr;
+  PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(const char* ptr,
+                                                              int* old_limit);
+
+  // The context keeps an internal stack to keep track of the recursive
+  // part of the parse state.
+  // Current depth of the active parser, depth counts down.
+  // This is used to limit recursion depth (to prevent overflow on malicious
+  // data), but is also used to index in stack_ to store the current state.
+  int depth_;
+  // Unfortunately necessary for the fringe case of ending on 0 or end-group tag
+  // in the last kSlopBytes of a ZeroCopyInputStream chunk.
+  int group_depth_ = INT_MIN;
+  Data data_;
+};
+
+template <uint32_t tag>
+bool ExpectTag(const char* ptr) {
+  if (tag < 128) {
+    return *ptr == static_cast<char>(tag);
+  } else {
+    static_assert(tag < 128 * 128, "We only expect tags for 1 or 2 bytes");
+    char buf[2] = {static_cast<char>(tag | 0x80), static_cast<char>(tag >> 7)};
+    return std::memcmp(ptr, buf, 2) == 0;
+  }
+}
+
+template <int>
+struct EndianHelper;
+
+template <>
+struct EndianHelper<1> {
+  static uint8_t Load(const void* p) { return *static_cast<const uint8_t*>(p); }
+};
+
+template <>
+struct EndianHelper<2> {
+  static uint16_t Load(const void* p) {
+    uint16_t tmp;
+    std::memcpy(&tmp, p, 2);
+    return little_endian::ToHost(tmp);
+  }
+};
+
+template <>
+struct EndianHelper<4> {
+  static uint32_t Load(const void* p) {
+    uint32_t tmp;
+    std::memcpy(&tmp, p, 4);
+    return little_endian::ToHost(tmp);
+  }
+};
+
+template <>
+struct EndianHelper<8> {
+  static uint64_t Load(const void* p) {
+    uint64_t tmp;
+    std::memcpy(&tmp, p, 8);
+    return little_endian::ToHost(tmp);
+  }
+};
+
+template <typename T>
+T UnalignedLoad(const char* p) {
+  auto tmp = EndianHelper<sizeof(T)>::Load(p);
+  T res;
+  memcpy(&res, &tmp, sizeof(T));
+  return res;
+}
+
+PROTOBUF_EXPORT
+std::pair<const char*, uint32_t> VarintParseSlow32(const char* p, uint32_t res);
+PROTOBUF_EXPORT
+std::pair<const char*, uint64_t> VarintParseSlow64(const char* p, uint32_t res);
+
+inline const char* VarintParseSlow(const char* p, uint32_t res, uint32_t* out) {
+  auto tmp = VarintParseSlow32(p, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
+inline const char* VarintParseSlow(const char* p, uint32_t res, uint64_t* out) {
+  auto tmp = VarintParseSlow64(p, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
+template <typename T>
+PROTOBUF_NODISCARD const char* VarintParse(const char* p, T* out) {
+  auto ptr = reinterpret_cast<const uint8_t*>(p);
+  uint32_t res = ptr[0];
+  if (!(res & 0x80)) {
+    *out = res;
+    return p + 1;
+  }
+  uint32_t byte = ptr[1];
+  res += (byte - 1) << 7;
+  if (!(byte & 0x80)) {
+    *out = res;
+    return p + 2;
+  }
+  return VarintParseSlow(p, res, out);
+}
+
+// Used for tags, could read up to 5 bytes which must be available.
+// Caller must ensure its safe to call.
+
+PROTOBUF_EXPORT
+std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res);
+
+// Same as ParseVarint but only accept 5 bytes at most.
+inline const char* ReadTag(const char* p, uint32_t* out,
+                           uint32_t /*max_tag*/ = 0) {
+  uint32_t res = static_cast<uint8_t>(p[0]);
+  if (res < 128) {
+    *out = res;
+    return p + 1;
+  }
+  uint32_t second = static_cast<uint8_t>(p[1]);
+  res += (second - 1) << 7;
+  if (second < 128) {
+    *out = res;
+    return p + 2;
+  }
+  auto tmp = ReadTagFallback(p, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
+// As above, but optimized to consume very few registers while still being fast,
+// ReadTagInlined is useful for callers that don't mind the extra code but would
+// like to avoid an extern function call causing spills into the stack.
+//
+// Two support routines for ReadTagInlined come first...
+template <class T>
+PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE constexpr T RotateLeft(
+    T x, int s) noexcept {
+  return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
+         static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+PROTOBUF_NODISCARD inline PROTOBUF_ALWAYS_INLINE uint64_t
+RotRight7AndReplaceLowByte(uint64_t res, const char& byte) {
+#if defined(__x86_64__) && defined(__GNUC__)
+  // This will only use one register for `res`.
+  // `byte` comes as a reference to allow the compiler to generate code like:
+  //
+  //   rorq    $7, %rcx
+  //   movb    1(%rax), %cl
+  //
+  // which avoids loading the incoming bytes into a separate register first.
+  asm("ror $7,%0\n\t"
+      "movb %1,%b0"
+      : "+r"(res)
+      : "m"(byte));
+#else
+  res = RotateLeft(res, -7);
+  res = res & ~0xFF;
+  res |= 0xFF & byte;
+#endif
+  return res;
+};
+
+inline PROTOBUF_ALWAYS_INLINE
+const char* ReadTagInlined(const char* ptr, uint32_t* out) {
+  uint64_t res = 0xFF & ptr[0];
+  if (PROTOBUF_PREDICT_FALSE(res >= 128)) {
+    res = RotRight7AndReplaceLowByte(res, ptr[1]);
+    if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+      res = RotRight7AndReplaceLowByte(res, ptr[2]);
+      if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+        res = RotRight7AndReplaceLowByte(res, ptr[3]);
+        if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+          // Note: this wouldn't work if res were 32-bit,
+          // because then replacing the low byte would overwrite
+          // the bottom 4 bits of the result.
+          res = RotRight7AndReplaceLowByte(res, ptr[4]);
+          if (PROTOBUF_PREDICT_FALSE(res & 0x80)) {
+            // The proto format does not permit longer than 5-byte encodings for
+            // tags.
+            *out = 0;
+            return nullptr;
+          }
+          *out = static_cast<uint32_t>(RotateLeft(res, 28));
+#if defined(__GNUC__)
+          // Note: this asm statement prevents the compiler from
+          // trying to share the "return ptr + constant" among all
+          // branches.
+          asm("" : "+r"(ptr));
+#endif
+          return ptr + 5;
+        }
+        *out = static_cast<uint32_t>(RotateLeft(res, 21));
+        return ptr + 4;
+      }
+      *out = static_cast<uint32_t>(RotateLeft(res, 14));
+      return ptr + 3;
+    }
+    *out = static_cast<uint32_t>(RotateLeft(res, 7));
+    return ptr + 2;
+  }
+  *out = static_cast<uint32_t>(res);
+  return ptr + 1;
+}
+
+// Decode 2 consecutive bytes of a varint and returns the value, shifted left
+// by 1. It simultaneous updates *ptr to *ptr + 1 or *ptr + 2 depending if the
+// first byte's continuation bit is set.
+// If bit 15 of return value is set (equivalent to the continuation bits of both
+// bytes being set) the varint continues, otherwise the parse is done. On x86
+// movsx eax, dil
+// and edi, eax
+// add eax, edi
+// adc [rsi], 1
+inline uint32_t DecodeTwoBytes(const char** ptr) {
+  uint32_t value = UnalignedLoad<uint16_t>(*ptr);
+  // Sign extend the low byte continuation bit
+  uint32_t x = static_cast<int8_t>(value);
+  value &= x;  // Mask out the high byte iff no continuation
+  // This add is an amazing operation, it cancels the low byte continuation bit
+  // from y transferring it to the carry. Simultaneously it also shifts the 7
+  // LSB left by one tightly against high byte varint bits. Hence value now
+  // contains the unpacked value shifted left by 1.
+  value += x;
+  // Use the carry to update the ptr appropriately.
+  *ptr += value < x ? 2 : 1;
+  return value;
+}
+
+// More efficient varint parsing for big varints
+inline const char* ParseBigVarint(const char* p, uint64_t* out) {
+  auto pnew = p;
+  auto tmp = DecodeTwoBytes(&pnew);
+  uint64_t res = tmp >> 1;
+  if (PROTOBUF_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
+    *out = res;
+    return pnew;
+  }
+  for (std::uint32_t i = 1; i < 5; i++) {
+    pnew = p + 2 * i;
+    tmp = DecodeTwoBytes(&pnew);
+    res += (static_cast<std::uint64_t>(tmp) - 2) << (14 * i - 1);
+    if (PROTOBUF_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
+      *out = res;
+      return pnew;
+    }
+  }
+  return nullptr;
+}
+
+PROTOBUF_EXPORT
+std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t first);
+// Used for tags, could read up to 5 bytes which must be available. Additionally
+// it makes sure the unsigned value fits a int32_t, otherwise returns nullptr.
+// Caller must ensure its safe to call.
+inline uint32_t ReadSize(const char** pp) {
+  auto p = *pp;
+  uint32_t res = static_cast<uint8_t>(p[0]);
+  if (res < 128) {
+    *pp = p + 1;
+    return res;
+  }
+  auto x = ReadSizeFallback(p, res);
+  *pp = x.first;
+  return x.second;
+}
+
+// Some convenience functions to simplify the generated parse loop code.
+// Returning the value and updating the buffer pointer allows for nicer
+// function composition. We rely on the compiler to inline this.
+// Also in debug compiles having local scoped variables tend to generated
+// stack frames that scale as O(num fields).
+inline uint64_t ReadVarint64(const char** p) {
+  uint64_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return tmp;
+}
+
+inline uint32_t ReadVarint32(const char** p) {
+  uint32_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return tmp;
+}
+
+inline int64_t ReadVarintZigZag64(const char** p) {
+  uint64_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return WireFormatLite::ZigZagDecode64(tmp);
+}
+
+inline int32_t ReadVarintZigZag32(const char** p) {
+  uint64_t tmp;
+  *p = VarintParse(*p, &tmp);
+  return WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
+}
+
+template <typename T, typename std::enable_if<
+                          !std::is_base_of<MessageLite, T>::value, bool>::type>
+PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
+                                                          const char* ptr) {
+  int old;
+  ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
+  ptr = ptr ? msg->_InternalParse(ptr, this) : nullptr;
+  depth_++;
+  if (!PopLimit(old)) return nullptr;
+  return ptr;
+}
+
+template <typename Tag, typename T>
+const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
+                                                  Tag expected_tag,
+                                                  RepeatedField<T>* out) {
+  do {
+    out->Add(UnalignedLoad<T>(ptr));
+    ptr += sizeof(T);
+    if (PROTOBUF_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
+  } while (UnalignedLoad<Tag>(ptr) == expected_tag && (ptr += sizeof(Tag)));
+  return ptr;
+}
+
+// Add any of the following lines to debug which parse function is failing.
+
+#define GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, ret) \
+  if (!(predicate)) {                                  \
+    /*  ::raise(SIGINT);  */                           \
+    /*  GOOGLE_LOG(ERROR) << "Parse failure";  */             \
+    return ret;                                        \
+  }
+
+#define GOOGLE_PROTOBUF_PARSER_ASSERT(predicate) \
+  GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
+
+template <typename T>
+const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
+                                                RepeatedField<T>* out) {
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  int nbytes = buffer_end_ + kSlopBytes - ptr;
+  while (size > nbytes) {
+    int num = nbytes / sizeof(T);
+    int old_entries = out->size();
+    out->Reserve(old_entries + num);
+    int block_size = num * sizeof(T);
+    auto dst = out->AddNAlreadyReserved(num);
+#ifdef PROTOBUF_LITTLE_ENDIAN
+    std::memcpy(dst, ptr, block_size);
+#else
+    for (int i = 0; i < num; i++)
+      dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
+#endif
+    size -= block_size;
+    if (limit_ <= kSlopBytes) return nullptr;
+    ptr = Next();
+    if (ptr == nullptr) return nullptr;
+    ptr += kSlopBytes - (nbytes - block_size);
+    nbytes = buffer_end_ + kSlopBytes - ptr;
+  }
+  int num = size / sizeof(T);
+  int old_entries = out->size();
+  out->Reserve(old_entries + num);
+  int block_size = num * sizeof(T);
+  auto dst = out->AddNAlreadyReserved(num);
+#ifdef PROTOBUF_LITTLE_ENDIAN
+  std::memcpy(dst, ptr, block_size);
+#else
+  for (int i = 0; i < num; i++) dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
+#endif
+  ptr += block_size;
+  if (size != block_size) return nullptr;
+  return ptr;
+}
+
+template <typename Add>
+const char* ReadPackedVarintArray(const char* ptr, const char* end, Add add) {
+  while (ptr < end) {
+    uint64_t varint;
+    ptr = VarintParse(ptr, &varint);
+    if (ptr == nullptr) return nullptr;
+    add(varint);
+  }
+  return ptr;
+}
+
+template <typename Add>
+const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  int chunk_size = buffer_end_ - ptr;
+  while (size > chunk_size) {
+    ptr = ReadPackedVarintArray(ptr, buffer_end_, add);
+    if (ptr == nullptr) return nullptr;
+    int overrun = ptr - buffer_end_;
+    GOOGLE_DCHECK(overrun >= 0 && overrun <= kSlopBytes);
+    if (size - chunk_size <= kSlopBytes) {
+      // The current buffer contains all the information needed, we don't need
+      // to flip buffers. However we must parse from a buffer with enough space
+      // so we are not prone to a buffer overflow.
+      char buf[kSlopBytes + 10] = {};
+      std::memcpy(buf, buffer_end_, kSlopBytes);
+      GOOGLE_CHECK_LE(size - chunk_size, kSlopBytes);
+      auto end = buf + (size - chunk_size);
+      auto res = ReadPackedVarintArray(buf + overrun, end, add);
+      if (res == nullptr || res != end) return nullptr;
+      return buffer_end_ + (res - buf);
+    }
+    size -= overrun + chunk_size;
+    GOOGLE_DCHECK_GT(size, 0);
+    // We must flip buffers
+    if (limit_ <= kSlopBytes) return nullptr;
+    ptr = Next();
+    if (ptr == nullptr) return nullptr;
+    ptr += overrun;
+    chunk_size = buffer_end_ - ptr;
+  }
+  auto end = ptr + size;
+  ptr = ReadPackedVarintArray(ptr, end, add);
+  return end == ptr ? ptr : nullptr;
+}
+
+// Helper for verification of utf8
+PROTOBUF_EXPORT
+bool VerifyUTF8(StringPiece s, const char* field_name);
+
+inline bool VerifyUTF8(const std::string* s, const char* field_name) {
+  return VerifyUTF8(*s, field_name);
+}
+
+// All the string parsers with or without UTF checking and for all CTypes.
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* InlineGreedyStringParser(
+    std::string* s, const char* ptr, ParseContext* ctx);
+
+
+template <typename T>
+PROTOBUF_NODISCARD const char* FieldParser(uint64_t tag, T& field_parser,
+                                           const char* ptr, ParseContext* ctx) {
+  uint32_t number = tag >> 3;
+  GOOGLE_PROTOBUF_PARSER_ASSERT(number != 0);
+  using WireType = internal::WireFormatLite::WireType;
+  switch (tag & 7) {
+    case WireType::WIRETYPE_VARINT: {
+      uint64_t value;
+      ptr = VarintParse(ptr, &value);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      field_parser.AddVarint(number, value);
+      break;
+    }
+    case WireType::WIRETYPE_FIXED64: {
+      uint64_t value = UnalignedLoad<uint64_t>(ptr);
+      ptr += 8;
+      field_parser.AddFixed64(number, value);
+      break;
+    }
+    case WireType::WIRETYPE_LENGTH_DELIMITED: {
+      ptr = field_parser.ParseLengthDelimited(number, ptr, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      break;
+    }
+    case WireType::WIRETYPE_START_GROUP: {
+      ptr = field_parser.ParseGroup(number, ptr, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      break;
+    }
+    case WireType::WIRETYPE_END_GROUP: {
+      GOOGLE_LOG(FATAL) << "Can't happen";
+      break;
+    }
+    case WireType::WIRETYPE_FIXED32: {
+      uint32_t value = UnalignedLoad<uint32_t>(ptr);
+      ptr += 4;
+      field_parser.AddFixed32(number, value);
+      break;
+    }
+    default:
+      return nullptr;
+  }
+  return ptr;
+}
+
+template <typename T>
+PROTOBUF_NODISCARD const char* WireFormatParser(T& field_parser,
+                                                const char* ptr,
+                                                ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ReadTag(ptr, &tag);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+    if (tag == 0 || (tag & 7) == 4) {
+      ctx->SetLastTag(tag);
+      return ptr;
+    }
+    ptr = FieldParser(tag, field_parser, ptr, ctx);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+  }
+  return ptr;
+}
+
+// The packed parsers parse repeated numeric primitives directly into  the
+// corresponding field
+
+// These are packed varints
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedUInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedUInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedEnumParser(
+    void* object, const char* ptr, ParseContext* ctx);
+
+template <typename T>
+PROTOBUF_NODISCARD const char* PackedEnumParser(void* object, const char* ptr,
+                                                ParseContext* ctx,
+                                                bool (*is_valid)(int),
+                                                InternalMetadata* metadata,
+                                                int field_num) {
+  return ctx->ReadPackedVarint(
+      ptr, [object, is_valid, metadata, field_num](uint64_t val) {
+        if (is_valid(val)) {
+          static_cast<RepeatedField<int>*>(object)->Add(val);
+        } else {
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields<T>());
+        }
+      });
+}
+
+template <typename T>
+PROTOBUF_NODISCARD const char* PackedEnumParserArg(
+    void* object, const char* ptr, ParseContext* ctx,
+    bool (*is_valid)(const void*, int), const void* data,
+    InternalMetadata* metadata, int field_num) {
+  return ctx->ReadPackedVarint(
+      ptr, [object, is_valid, data, metadata, field_num](uint64_t val) {
+        if (is_valid(data, val)) {
+          static_cast<RepeatedField<int>*>(object)->Add(val);
+        } else {
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields<T>());
+        }
+      });
+}
+
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedBoolParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedFixed32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSFixed32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedFixed64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedSFixed64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedFloatParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* PackedDoubleParser(
+    void* object, const char* ptr, ParseContext* ctx);
+
+// This is the only recursive parser.
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* UnknownGroupLiteParse(
+    std::string* unknown, const char* ptr, ParseContext* ctx);
+// This is a helper to for the UnknownGroupLiteParse but is actually also
+// useful in the generated code. It uses overload on std::string* vs
+// UnknownFieldSet* to make the generated code isomorphic between full and lite.
+PROTOBUF_NODISCARD PROTOBUF_EXPORT const char* UnknownFieldParse(
+    uint32_t tag, std::string* unknown, const char* ptr, ParseContext* ctx);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port.h
new file mode 100644
index 0000000..a5c060b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port.h
@@ -0,0 +1,80 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A common header that is included across all protobuf headers.  We do our best
+// to avoid #defining any macros here; instead we generally put macros in
+// port_def.inc and port_undef.inc so they are not visible from outside of
+// protobuf.
+
+#ifndef GOOGLE_PROTOBUF_PORT_H__
+#define GOOGLE_PROTOBUF_PORT_H__
+
+#include <cstddef>
+#include <new>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+inline void SizedDelete(void* p, size_t size) {
+#if defined(__cpp_sized_deallocation)
+  ::operator delete(p, size);
+#else
+  ::operator delete(p);
+#endif
+}
+inline void SizedArrayDelete(void* p, size_t size) {
+#if defined(__cpp_sized_deallocation)
+  ::operator delete[](p, size);
+#else
+  ::operator delete[](p);
+#endif
+}
+
+// Tag type used to invoke the constinit constructor overload of classes
+// such as ArenaStringPtr and MapFieldBase. Such constructors are internal
+// implementation details of the library.
+struct ConstantInitialized {
+  explicit ConstantInitialized() = default;
+};
+
+// Tag type used to invoke the arena constructor overload of classes such
+// as ExtensionSet and MapFieldLite in aggregate initialization. These
+// classes typically don't have move/copy constructors, which rules out
+// explicit initialization in pre-C++17.
+struct ArenaInitialized {
+  explicit ArenaInitialized() = default;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_PORT_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port_def.inc b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port_def.inc
new file mode 100644
index 0000000..6c6aa18
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port_def.inc
@@ -0,0 +1,928 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines common macros that are used in protobuf.
+//
+// To hide these definitions from the outside world (and to prevent collisions
+// if more than one version of protobuf is #included in the same project) you
+// must follow this pattern when #including port_def.inc in a header file:
+//
+// #include "other_header.h"
+// #include "message.h"
+// // etc.
+//
+// #include "port_def.inc"  // MUST be last header included
+//
+// // Definitions for this header.
+//
+// #include "port_undef.inc"
+//
+// This is a textual header with no include guard, because we want to
+// detect/prohibit anytime it is #included twice without a corresponding
+// #undef.
+
+// The definitions in this file are intended to be portable across Clang,
+// GCC, and MSVC. Function-like macros are usable without an #ifdef guard.
+// Syntax macros (for example, attributes) are always defined, although
+// they may be empty.
+//
+// Some definitions rely on the NDEBUG macro and/or (in MSVC) _DEBUG:
+// - https://en.cppreference.com/w/c/error/assert
+// - https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros#microsoft-specific-predefined-macros
+//
+// References for predefined macros:
+// - Standard: https://en.cppreference.com/w/cpp/preprocessor/replace
+// - Clang: https://clang.llvm.org/docs/LanguageExtensions.html
+//          (see also GCC predefined macros)
+// - GCC: https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html
+// - MSVC: https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+// - Interactive (Clang/GCC only): https://www.compiler-explorer.com/z/hc6jKd3sj
+//
+// References for attributes (and extension attributes):
+// - Standard: https://en.cppreference.com/w/cpp/language/attributes
+// - Clang: https://clang.llvm.org/docs/AttributeReference.html
+// - GCC: https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+//        (see Clang attribute docs as well)
+//
+// References for standard C++ language conformance (and minimum versions):
+// - Clang: https://clang.llvm.org/cxx_status.html
+// - GCC: https://gcc.gnu.org/projects/cxx-status.html
+// - MSVC: https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance
+//
+// Historical release notes (which can help to determine minimum versions):
+// - Clang: https://releases.llvm.org/
+// - GCC: https://gcc.gnu.org/releases.html
+// - MSVC: https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-history
+//         https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-relnotes-history
+
+// Portable fallbacks for C++20 feature test macros:
+// https://en.cppreference.com/w/cpp/feature_test
+#ifndef __has_cpp_attribute
+#define __has_cpp_attribute(x) 0
+#define PROTOBUF_has_cpp_attribute_DEFINED_
+#endif
+
+// Portable fallback for Clang's __has_feature macro:
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
+#ifndef __has_feature
+#define __has_feature(x) 0
+#define PROTOBUF_has_feature_DEFINED_
+#endif
+
+// Portable fallback for Clang's __has_warning macro:
+#ifndef __has_warning
+#define __has_warning(x) 0
+#define PROTOBUF_has_warning_DEFINED_
+#endif
+
+// Portable fallbacks for the __has_attribute macro (GCC and Clang):
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
+// https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#define PROTOBUF_has_attribute_DEFINED_
+#endif
+
+// Portable fallback for __has_builtin (GCC and Clang):
+// https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin
+// https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fbuiltin.html
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#define PROTOBUF_has_builtin_DEFINED_
+#endif
+
+// Portable PROTOBUF_BUILTIN_BSWAPxx definitions
+// Code must check for availability, e.g.: `defined(PROTOBUF_BUILTIN_BSWAP32)`
+#ifdef PROTOBUF_BUILTIN_BSWAP16
+#error PROTOBUF_BUILTIN_BSWAP16 was previously defined
+#endif
+#ifdef PROTOBUF_BUILTIN_BSWAP32
+#error PROTOBUF_BUILTIN_BSWAP32 was previously defined
+#endif
+#ifdef PROTOBUF_BUILTIN_BSWAP64
+#error PROTOBUF_BUILTIN_BSWAP64 was previously defined
+#endif
+#if defined(__GNUC__) || __has_builtin(__builtin_bswap16)
+#define PROTOBUF_BUILTIN_BSWAP16(x) __builtin_bswap16(x)
+#endif
+#if defined(__GNUC__) || __has_builtin(__builtin_bswap32)
+#define PROTOBUF_BUILTIN_BSWAP32(x) __builtin_bswap32(x)
+#endif
+#if defined(__GNUC__) || __has_builtin(__builtin_bswap64)
+#define PROTOBUF_BUILTIN_BSWAP64(x) __builtin_bswap64(x)
+#endif
+
+// Portable check for GCC minimum version:
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) \
+    && defined(__GNUC_PATCHLEVEL__)
+#  define PROTOBUF_GNUC_MIN(x, y) \
+  (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
+#else
+#  define PROTOBUF_GNUC_MIN(x, y) 0
+#endif
+
+// Portable check for MSVC minimum version:
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+#if defined(_MSC_VER)
+#define PROTOBUF_MSC_VER_MIN(x) (_MSC_VER >= x)
+#else
+#define PROTOBUF_MSC_VER_MIN(x) 0
+#endif
+
+// Portable check for minimum C++ language version:
+// https://en.cppreference.com/w/cpp/preprocessor/replace
+// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
+#if !defined(_MSVC_LANG)
+#define PROTOBUF_CPLUSPLUS_MIN(x) (__cplusplus >= x)
+#else
+#define PROTOBUF_CPLUSPLUS_MIN(x) (_MSVC_LANG >= x)
+#endif
+
+// Future versions of protobuf will include breaking changes to some APIs.
+// This macro can be set to enable these API changes ahead of time, so that
+// user code can be updated before upgrading versions of protobuf.
+// PROTOBUF_FUTURE_FINAL is used on classes that are historically not marked as
+// final, but that may be marked final in future (breaking) releases.
+// #define PROTOBUF_FUTURE_BREAKING_CHANGES 1
+// #define PROTOBUF_FUTURE_FINAL final
+#define PROTOBUF_FUTURE_FINAL
+
+#ifdef PROTOBUF_VERSION
+#error PROTOBUF_VERSION was previously defined
+#endif
+#define PROTOBUF_VERSION 3021012
+
+#ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC
+#error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined
+#endif
+#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC 3021000
+
+#ifdef PROTOBUF_MIN_PROTOC_VERSION
+#error PROTOBUF_MIN_PROTOC_VERSION was previously defined
+#endif
+#define PROTOBUF_MIN_PROTOC_VERSION 3021000
+
+#ifdef PROTOBUF_VERSION_SUFFIX
+#error PROTOBUF_VERSION_SUFFIX was previously defined
+#endif
+#define PROTOBUF_VERSION_SUFFIX ""
+
+#if defined(PROTOBUF_NAMESPACE) || defined(PROTOBUF_NAMESPACE_ID)
+#error PROTOBUF_NAMESPACE or PROTOBUF_NAMESPACE_ID was previously defined
+#endif
+#define PROTOBUF_NAMESPACE "google::protobuf"
+#define PROTOBUF_NAMESPACE_ID google::protobuf
+#define PROTOBUF_NAMESPACE_OPEN \
+  namespace google {            \
+  namespace protobuf {
+#define PROTOBUF_NAMESPACE_CLOSE \
+  } /* namespace protobuf */     \
+  } /* namespace google */
+
+#ifdef PROTOBUF_ALWAYS_INLINE
+#error PROTOBUF_ALWAYS_INLINE was previously defined
+#endif
+// For functions we want to force inline.
+#if defined(PROTOBUF_NO_INLINE)
+# define PROTOBUF_ALWAYS_INLINE
+#elif PROTOBUF_GNUC_MIN(3, 1)
+# define PROTOBUF_ALWAYS_INLINE __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define PROTOBUF_ALWAYS_INLINE __forceinline
+#else
+# define PROTOBUF_ALWAYS_INLINE
+#endif
+
+#ifdef PROTOBUF_NDEBUG_INLINE
+#error PROTOBUF_NDEBUG_INLINE was previously defined
+#endif
+// Avoid excessive inlining in non-optimized builds. Without other optimizations
+// the inlining is not going to provide benefits anyway and the huge resulting
+// functions, especially in the proto-generated serialization functions, produce
+// stack frames so large that many tests run into stack overflows (b/32192897).
+#if defined(NDEBUG) || (defined(_MSC_VER) && !defined(_DEBUG))
+# define PROTOBUF_NDEBUG_INLINE PROTOBUF_ALWAYS_INLINE
+#else
+# define PROTOBUF_NDEBUG_INLINE
+#endif
+
+// Note that PROTOBUF_NOINLINE is an attribute applied to functions, to prevent
+// them from being inlined by the compiler. This is different from
+// PROTOBUF_NO_INLINE, which is a user-supplied macro that disables forced
+// inlining by PROTOBUF_(ALWAYS|NDEBUG)_INLINE.
+#ifdef PROTOBUF_NOINLINE
+#error PROTOBUF_NOINLINE was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 1)
+# define PROTOBUF_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+// Seems to have been around since at least Visual Studio 2005
+# define PROTOBUF_NOINLINE __declspec(noinline)
+#endif
+
+#ifdef PROTOBUF_MUSTTAIL
+#error PROTOBUF_MUSTTAIL was previously defined
+#endif
+#ifdef PROTOBUF_TAILCALL
+#error PROTOBUF_TAILCALL was previously defined
+#endif
+#if __has_cpp_attribute(clang::musttail) && !defined(__arm__) && \
+    !defined(_ARCH_PPC) && !defined(__wasm__) &&                 \
+    !(defined(_MSC_VER) && defined(_M_IX86)) &&                  \
+    !(defined(__NDK_MAJOR__) && __NDK_MAJOR <= 24)
+#  ifndef PROTO2_OPENSOURCE
+// Compilation fails on ARM32: b/195943306
+// Compilation fails on powerpc64le: b/187985113
+// Compilation fails on X86 Windows:
+// https://github.com/llvm/llvm-project/issues/53271
+#  endif
+#define PROTOBUF_MUSTTAIL [[clang::musttail]]
+#define PROTOBUF_TAILCALL true
+#else
+#define PROTOBUF_MUSTTAIL
+#define PROTOBUF_TAILCALL false
+#endif
+
+#ifdef PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED
+#error PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED was previously defined
+#endif
+#if __has_attribute(exclusive_locks_required)
+#define PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED(...) \
+  __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#else
+#define PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED(...)
+#endif
+
+#ifdef PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
+#error PROTOBUF_NO_THREAD_SAFETY_ANALYSIS was previously defined
+#endif
+#if __has_attribute(no_thread_safety_analysis)
+#define PROTOBUF_NO_THREAD_SAFETY_ANALYSIS \
+  __attribute__((no_thread_safety_analysis))
+#else
+#define PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
+#endif
+
+#ifdef PROTOBUF_GUARDED_BY
+#error PROTOBUF_GUARDED_BY was previously defined
+#endif
+#if __has_attribute(guarded_by)
+#define PROTOBUF_GUARDED_BY(x) __attribute__((guarded_by(x)))
+#else
+#define PROTOBUF_GUARDED_BY(x)
+#endif
+
+#ifdef PROTOBUF_LOCKS_EXCLUDED
+#error PROTOBUF_LOCKS_EXCLUDED was previously defined
+#endif
+#if __has_attribute(locks_excluded)
+#define PROTOBUF_LOCKS_EXCLUDED(...) \
+  __attribute__((locks_excluded(__VA_ARGS__)))
+#else
+#define PROTOBUF_LOCKS_EXCLUDED(...)
+#endif
+
+#ifdef PROTOBUF_COLD
+#error PROTOBUF_COLD was previously defined
+#endif
+#if __has_attribute(cold) || PROTOBUF_GNUC_MIN(4, 3)
+# define PROTOBUF_COLD __attribute__((cold))
+#else
+# define PROTOBUF_COLD
+#endif
+
+#ifdef PROTOBUF_SECTION_VARIABLE
+#error PROTOBUF_SECTION_VARIABLE was previously defined
+#endif
+#if (__has_attribute(section) || defined(__GNUC__)) && defined(__ELF__)
+// Place a variable in the given ELF section.
+# define PROTOBUF_SECTION_VARIABLE(x) __attribute__((section(#x)))
+#else
+# define PROTOBUF_SECTION_VARIABLE(x)
+#endif
+
+#if defined(PROTOBUF_DEPRECATED)
+#error PROTOBUF_DEPRECATED was previously defined
+#endif
+#if defined(PROTOBUF_DEPRECATED_MSG)
+#error PROTOBUF_DEPRECATED_MSG was previously defined
+#endif
+#if __has_attribute(deprecated) || PROTOBUF_GNUC_MIN(3, 0)
+# define PROTOBUF_DEPRECATED __attribute__((deprecated))
+# define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+# define PROTOBUF_DEPRECATED __declspec(deprecated)
+# define PROTOBUF_DEPRECATED_MSG(msg) __declspec(deprecated(msg))
+#else
+# define PROTOBUF_DEPRECATED
+# define PROTOBUF_DEPRECATED_MSG(msg)
+#endif
+
+#if defined(PROTOBUF_DEPRECATED_ENUM)
+#error PROTOBUF_DEPRECATED_ENUM was previously defined
+#endif
+#if defined(__clang__) || PROTOBUF_GNUC_MIN(6, 0)
+// https://gcc.gnu.org/gcc-6/changes.html
+# define PROTOBUF_DEPRECATED_ENUM __attribute__((deprecated))
+#else
+# define PROTOBUF_DEPRECATED_ENUM
+#endif
+
+#ifdef PROTOBUF_FUNC_ALIGN
+#error PROTOBUF_FUNC_ALIGN was previously defined
+#endif
+#if __has_attribute(aligned) || PROTOBUF_GNUC_MIN(4, 3)
+#define PROTOBUF_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
+#else
+#define PROTOBUF_FUNC_ALIGN(bytes)
+#endif
+
+#ifdef PROTOBUF_RETURNS_NONNULL
+#error PROTOBUF_RETURNS_NONNULL was previously defined
+#endif
+#if __has_attribute(returns_nonnull) || PROTOBUF_GNUC_MIN(4, 9)
+#define PROTOBUF_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define PROTOBUF_RETURNS_NONNULL
+#endif
+
+#ifdef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#error PROTOBUF_ATTRIBUTE_REINITIALIZES was previously defined
+#endif
+#if __has_cpp_attribute(clang::reinitializes)
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES
+#endif
+
+// The minimum library version which works with the current version of the
+// headers.
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3021000
+
+#ifdef PROTOBUF_RTTI
+#error PROTOBUF_RTTI was previously defined
+#endif
+#if defined(GOOGLE_PROTOBUF_NO_RTTI) && GOOGLE_PROTOBUF_NO_RTTI
+// A user-provided definition GOOGLE_PROTOBUF_NO_RTTI=1 disables RTTI.
+#define PROTOBUF_RTTI 0
+#elif defined(__cpp_rtti)
+// https://en.cppreference.com/w/cpp/feature_test
+#define PROTOBUF_RTTI 1
+#elif __has_feature(cxx_rtti)
+// https://clang.llvm.org/docs/LanguageExtensions.html#c-rtti
+#define PROTOBUF_RTTI 1
+#elif defined(__GXX_RTTI)
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#define PROTOBUF_RTTI 1
+#elif defined(_CPPRTTI)
+// https://docs.microsoft.com/en-us/cpp/build/reference/gr-enable-run-time-type-information
+#define PROTOBUF_RTTI 1
+#else
+#define PROTOBUF_RTTI 0
+#endif
+
+// Returns the offset of the given field within the given aggregate type.
+// This is equivalent to the ANSI C offsetof() macro.  However, according
+// to the C++ standard, offsetof() only works on POD types, and GCC
+// enforces this requirement with a warning.  In practice, this rule is
+// unnecessarily strict; there is probably no compiler or platform on
+// which the offsets of the direct fields of a class are non-constant.
+// Fields inherited from superclasses *can* have non-constant offsets,
+// but that's not what this macro will be used for.
+#ifdef PROTOBUF_FIELD_OFFSET
+#error PROTOBUF_FIELD_OFFSET was previously defined
+#endif
+#if defined(__clang__)
+// For Clang we use __builtin_offsetof() and suppress the warning,
+// to avoid Control Flow Integrity and UBSan vptr sanitizers from
+// crashing while trying to validate the invalid reinterpret_casts.
+#define PROTOBUF_FIELD_OFFSET(TYPE, FIELD)                   \
+  _Pragma("clang diagnostic push")                           \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(TYPE, FIELD)                            \
+  _Pragma("clang diagnostic pop")
+#elif PROTOBUF_GNUC_MIN(4, 8)
+#define PROTOBUF_FIELD_OFFSET(TYPE, FIELD) __builtin_offsetof(TYPE, FIELD)
+#else  // defined(__clang__)
+// Note that we calculate relative to the pointer value 16 here since if we
+// just use zero, GCC complains about dereferencing a NULL pointer.  We
+// choose 16 rather than some other number just in case the compiler would
+// be confused by an unaligned pointer.
+#define PROTOBUF_FIELD_OFFSET(TYPE, FIELD)                                \
+  static_cast< ::uint32_t>(reinterpret_cast<const char*>(                   \
+                             &reinterpret_cast<const TYPE*>(16)->FIELD) - \
+                         reinterpret_cast<const char*>(16))
+#endif
+
+#ifdef PROTOBUF_EXPORT
+#error PROTOBUF_EXPORT was previously defined
+#endif
+
+#if defined(PROTOBUF_USE_DLLS) && defined(_MSC_VER)
+# if defined(LIBPROTOBUF_EXPORTS)
+#  define PROTOBUF_EXPORT __declspec(dllexport)
+#  define PROTOBUF_EXPORT_TEMPLATE_DECLARE
+#  define PROTOBUF_EXPORT_TEMPLATE_DEFINE __declspec(dllexport)
+# else
+#  define PROTOBUF_EXPORT __declspec(dllimport)
+#  define PROTOBUF_EXPORT_TEMPLATE_DECLARE
+#  define PROTOBUF_EXPORT_TEMPLATE_DEFINE __declspec(dllimport)
+# endif  // defined(LIBPROTOBUF_EXPORTS)
+#elif defined(PROTOBUF_USE_DLLS) && defined(LIBPROTOBUF_EXPORTS)
+# define PROTOBUF_EXPORT __attribute__((visibility("default")))
+# define PROTOBUF_EXPORT_TEMPLATE_DECLARE __attribute__((visibility("default")))
+# define PROTOBUF_EXPORT_TEMPLATE_DEFINE
+#else
+# define PROTOBUF_EXPORT
+# define PROTOBUF_EXPORT_TEMPLATE_DECLARE
+# define PROTOBUF_EXPORT_TEMPLATE_DEFINE
+#endif
+
+#ifdef PROTOC_EXPORT
+#error PROTOC_EXPORT was previously defined
+#endif
+
+#if defined(PROTOBUF_USE_DLLS) && defined(_MSC_VER)
+# if defined(LIBPROTOC_EXPORTS)
+#  define PROTOC_EXPORT __declspec(dllexport)
+# else
+#  define PROTOC_EXPORT __declspec(dllimport)
+# endif  // defined(LIBPROTOC_EXPORTS)
+#elif defined(PROTOBUF_USE_DLLS) && defined(LIBPROTOC_EXPORTS)
+# define PROTOC_EXPORT __attribute__((visibility("default")))
+#else
+# define PROTOC_EXPORT
+#endif
+
+#if defined(PROTOBUF_PREDICT_TRUE) || defined(PROTOBUF_PREDICT_FALSE)
+#error PROTOBUF_PREDICT_(TRUE|FALSE) was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 0)
+# define PROTOBUF_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
+# define PROTOBUF_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
+#else
+# define PROTOBUF_PREDICT_TRUE(x) (x)
+# define PROTOBUF_PREDICT_FALSE(x) (x)
+#endif
+
+#ifdef PROTOBUF_NODISCARD
+#error PROTOBUF_NODISCARD was previously defined
+#endif
+#if __has_cpp_attribute(nodiscard) && PROTOBUF_CPLUSPLUS_MIN(201703L)
+#define PROTOBUF_NODISCARD [[nodiscard]]
+#elif __has_attribute(warn_unused_result) || PROTOBUF_GNUC_MIN(4, 8)
+#define PROTOBUF_NODISCARD __attribute__((warn_unused_result))
+#else
+#define PROTOBUF_NODISCARD
+#endif
+
+// Enable all stable experiments if this flag is set.  This allows us to group
+// all of these experiments under a single build flag, which can be enabled in
+// the protobuf.stable-experiments TAP project.
+#ifdef PROTOBUF_ENABLE_STABLE_EXPERIMENTS
+#define PROTOBUF_FORCE_MESSAGE_OWNED_ARENA
+#endif  // !PROTOBUF_ENABLE_STABLE_EXPERIMENTS
+
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+#error PROTOBUF_FORCE_COPY_IN_RELEASE was previously defined
+#endif
+
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+#error PROTOBUF_FORCE_COPY_IN_SWAP was previously defined
+#endif
+
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+#error PROTOBUF_FORCE_COPY_IN_MOVE was previously defined
+#endif
+
+#ifdef PROTOBUF_FORCE_RESET_IN_CLEAR
+#error PROTOBUF_FORCE_RESET_IN_CLEAR was previously defined
+#endif
+
+// Force copy the default string to a string field so that non-optimized builds
+// have harder-to-rely-on address stability.
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+#error PROTOBUF_FORCE_COPY_DEFAULT_STRING was previously defined
+#endif
+
+#ifdef PROTOBUF_FALLTHROUGH_INTENDED
+#error PROTOBUF_FALLTHROUGH_INTENDED was previously defined
+#endif
+#if __has_cpp_attribute(fallthrough)
+#define PROTOBUF_FALLTHROUGH_INTENDED [[fallthrough]]
+#elif __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define PROTOBUF_FALLTHROUGH_INTENDED [[clang::fallthrough]]
+#elif PROTOBUF_GNUC_MIN(7, 0)
+#define PROTOBUF_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
+#else
+#define PROTOBUF_FALLTHROUGH_INTENDED
+#endif
+
+// PROTOBUF_ASSUME(pred) tells the compiler that it can assume pred is true. To
+// be safe, we also validate the assumption with a GOOGLE_DCHECK in unoptimized
+// builds. The macro does not do anything useful if the compiler does not
+// support __builtin_assume.
+#ifdef PROTOBUF_ASSUME
+#error PROTOBUF_ASSUME was previously defined
+#endif
+#if __has_builtin(__builtin_assume)
+#define PROTOBUF_ASSUME(pred) \
+  GOOGLE_DCHECK(pred);               \
+  __builtin_assume(pred)
+#else
+#define PROTOBUF_ASSUME(pred) GOOGLE_DCHECK(pred)
+#endif
+
+// Specify memory alignment for structs, classes, etc.
+// Use like:
+//   class PROTOBUF_ALIGNAS(16) MyClass { ... }
+//   PROTOBUF_ALIGNAS(16) int array[4];
+//
+// In most places you can use the C++11 keyword "alignas", which is preferred.
+//
+// But compilers have trouble mixing __attribute__((...)) syntax with
+// alignas(...) syntax.
+//
+// Doesn't work in clang or gcc:
+//   struct alignas(16) __attribute__((packed)) S { char c; };
+// Works in clang but not gcc:
+//   struct __attribute__((packed)) alignas(16) S2 { char c; };
+// Works in clang and gcc:
+//   struct alignas(16) S3 { char c; } __attribute__((packed));
+//
+// There are also some attributes that must be specified *before* a class
+// definition: visibility (used for exporting functions/classes) is one of
+// these attributes. This means that it is not possible to use alignas() with a
+// class that is marked as exported.
+#ifdef PROTOBUF_ALIGNAS
+#error PROTOBUF_ALIGNAS was previously defined
+#endif
+#if defined(_MSC_VER)
+#define PROTOBUF_ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#elif PROTOBUF_GNUC_MIN(3, 0)
+#define PROTOBUF_ALIGNAS(byte_alignment) \
+  __attribute__((aligned(byte_alignment)))
+#else
+#define PROTOBUF_ALIGNAS(byte_alignment) alignas(byte_alignment)
+#endif
+
+#ifdef PROTOBUF_FINAL
+#error PROTOBUF_FINAL was previously defined
+#endif
+#define PROTOBUF_FINAL final
+
+#ifdef PROTOBUF_THREAD_LOCAL
+#error PROTOBUF_THREAD_LOCAL was previously defined
+#endif
+#if defined(_MSC_VER)
+#define PROTOBUF_THREAD_LOCAL __declspec(thread)
+#else
+#define PROTOBUF_THREAD_LOCAL __thread
+#endif
+
+// TODO(b/228173843): cleanup PROTOBUF_LITTLE_ENDIAN in various 3p forks.
+#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+     __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define PROTOBUF_LITTLE_ENDIAN 1
+#ifdef PROTOBUF_BIG_ENDIAN
+#error Conflicting PROTOBUF_BIG_ENDIAN was previously defined
+#endif
+#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
+    __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define PROTOBUF_BIG_ENDIAN 1
+#elif defined(_WIN32) || defined(__x86_64__) || defined(__aarch64__)
+#define PROTOBUF_LITTLE_ENDIAN 1
+#else
+#error "endian detection failed for current compiler"
+#endif
+
+// For enabling message owned arena, one major blocker is semantic change from
+// moving to copying when there is ownership transfer (e.g., move ctor, swap,
+// set allocated, release). This change not only causes performance regression
+// but also breaks users code (e.g., dangling reference). For top-level
+// messages, since it owns the arena, we can mitigate the issue by transferring
+// ownership of arena. However, we cannot do that for nested messages. In order
+// to tell how many usages of nested messages affected by message owned arena,
+// we need to simulate the arena ownership.
+// This experiment is purely for the purpose of gathering data. All code guarded
+// by this flag is supposed to be removed after this experiment.
+#define PROTOBUF_MESSAGE_OWNED_ARENA_EXPERIMENT
+#ifdef PROTOBUF_CONSTINIT
+#error PROTOBUF_CONSTINIT was previously defined
+#endif
+#if defined(__cpp_constinit) && !defined(_MSC_VER)
+#define PROTOBUF_CONSTINIT constinit
+#define PROTOBUF_CONSTEXPR constexpr
+// Some older Clang versions incorrectly raise an error about
+// constant-initializing weak default instance pointers. Versions 12.0 and
+// higher seem to work, except that XCode 12.5.1 shows the error even though it
+// uses Clang 12.0.5.
+// Clang-cl on Windows raises error also.
+#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization) && \
+    ((defined(__APPLE__) && __clang_major__ >= 13) ||                \
+     (!defined(__APPLE__) && __clang_major__ >= 12))
+#define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
+#define PROTOBUF_CONSTEXPR constexpr
+#elif PROTOBUF_GNUC_MIN(12, 2)
+#define PROTOBUF_CONSTINIT __constinit
+#define PROTOBUF_CONSTEXPR constexpr
+// MSVC 17 currently seems to raise an error about constant-initialized pointers.
+#elif defined(_MSC_VER) && _MSC_VER >= 1930
+#define PROTOBUF_CONSTINIT
+#define PROTOBUF_CONSTEXPR constexpr
+#else
+#define PROTOBUF_CONSTINIT
+#define PROTOBUF_CONSTEXPR
+#endif
+
+// Some globals with an empty non-trivial destructor are annotated with
+// no_destroy for performance reasons. It reduces the cost of these globals in
+// non-opt mode and under sanitizers.
+#ifdef PROTOBUF_ATTRIBUTE_NO_DESTROY
+#error PROTOBUF_ATTRIBUTE_NO_DESTROY was previously defined
+#endif
+#if __has_cpp_attribute(clang::no_destroy)
+#define PROTOBUF_ATTRIBUTE_NO_DESTROY [[clang::no_destroy]]
+#else
+#define PROTOBUF_ATTRIBUTE_NO_DESTROY
+#endif
+
+// Force clang to always emit complete debug info for a type.
+// Clang uses constructor homing to determine when to emit debug info for a
+// type. If the constructor of a type is never used, which can happen in some
+// cases where member variables are constructed in place for optimization
+// purposes (see b/208803175 for an example), the type will have incomplete
+// debug info unless this attribute is used.
+#ifdef PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#error PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG was previously defined
+#endif
+#if __has_cpp_attribute(clang::standalone_debug)
+#define PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG [[clang::standalone_debug]]
+#else
+#define PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#endif
+
+// Protobuf extensions and reflection require registration of the protos linked
+// in the binary. Not until everything is registered does the runtime have a
+// complete view on all protos. When code is using reflection or extensions
+// in between registration calls this can lead to surprising behavior. By
+// having the registration run first we mitigate this scenario.
+// Highest priority is 101. We use 102 for registration, to allow code that
+// really wants to higher priority to still beat us. Some initialization happens
+// at higher priority, though, since it is needed before registration.
+#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 was previously defined
+#endif
+#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 0) && (!defined(__APPLE__) || defined(__clang__)) && \
+    !((defined(sun) || defined(__sun)) &&                                     \
+      (defined(__SVR4) || defined(__svr4__)))
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 __attribute__((init_priority((101))))
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 __attribute__((init_priority((102))))
+#else
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#endif
+
+#ifdef PROTOBUF_PRAGMA_INIT_SEG
+#error PROTOBUF_PRAGMA_INIT_SEG was previously defined
+#endif
+#ifdef _MSC_VER
+#define PROTOBUF_PRAGMA_INIT_SEG __pragma(init_seg(lib))
+#else
+#define PROTOBUF_PRAGMA_INIT_SEG
+#endif
+
+#ifdef PROTOBUF_ATTRIBUTE_WEAK
+#error PROTOBUF_ATTRIBUTE_WEAK was previously defined
+#endif
+#if __has_attribute(weak) && \
+    !defined(__APPLE__) && \
+    (!defined(_WIN32) || __clang_major__ < 9) && \
+    !defined(__MINGW32__)
+#define PROTOBUF_ATTRIBUTE_WEAK __attribute__((weak))
+#define PROTOBUF_HAVE_ATTRIBUTE_WEAK 1
+#else
+#define PROTOBUF_ATTRIBUTE_WEAK
+#define PROTOBUF_HAVE_ATTRIBUTE_WEAK 0
+#endif
+
+// Macros to detect sanitizers.
+#ifdef PROTOBUF_ASAN
+#error PROTOBUF_ASAN was previously defined
+#endif
+#ifdef PROTOBUF_MSAN
+#error PROTOBUF_MSAN was previously defined
+#endif
+#ifdef PROTOBUF_TSAN
+#error PROTOBUF_TSAN was previously defined
+#endif
+#if defined(__clang__)
+#  if __has_feature(address_sanitizer)
+#    define PROTOBUF_ASAN 1
+#  endif
+#  if __has_feature(thread_sanitizer)
+#    define PROTOBUF_TSAN 1
+#  endif
+#  if __has_feature(memory_sanitizer)
+#    define PROTOBUF_MSAN 1
+#  endif
+#elif PROTOBUF_GNUC_MIN(3, 0)
+// Double-guard is needed for -Wundef:
+#  ifdef __SANITIZE_ADDRESS__
+#  if    __SANITIZE_ADDRESS__
+#    define PROTOBUF_ASAN 1
+#  endif
+#  endif
+#  ifdef __SANITIZE_THREAD__
+#  if    __SANITIZE_THREAD__
+#    define PROTOBUF_TSAN 1
+#  endif
+#  endif
+#endif
+
+// Tail call table-driven parsing can be enabled by defining
+// PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER at compilation time. Note
+// that this macro is for small-scale testing only, and is not supported.
+#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
+#error PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED was previously declared
+#endif
+#if defined(PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER)
+#define PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED 1
+#endif
+
+#define PROTOBUF_TC_PARAM_DECL                                 \
+  ::google::protobuf::MessageLite *msg, const char *ptr,                 \
+      ::google::protobuf::internal::ParseContext *ctx,                   \
+      const ::google::protobuf::internal::TcParseTableBase *table,       \
+      uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
+
+#ifdef PROTOBUF_UNUSED
+#error PROTOBUF_UNUSED was previously defined
+#endif
+#if __has_cpp_attribute(maybe_unused) || \
+    (PROTOBUF_MSC_VER_MIN(1911) && PROTOBUF_CPLUSPLUS_MIN(201703L))
+#define PROTOBUF_UNUSED [[maybe_unused]]
+#elif __has_attribute(unused) || PROTOBUF_GNUC_MIN(3, 0)
+#define PROTOBUF_UNUSED __attribute__((__unused__))
+#else
+#define PROTOBUF_UNUSED
+#endif
+
+// ThreadSafeArenaz is turned off completely in opensource builds.
+
+// Windows declares several inconvenient macro names.  We #undef them and then
+// restore them in port_undef.inc.
+#ifdef _MSC_VER
+#pragma push_macro("CREATE_NEW")
+#undef CREATE_NEW
+#pragma push_macro("DELETE")
+#undef DELETE
+#pragma push_macro("DOUBLE_CLICK")
+#undef DOUBLE_CLICK
+#pragma push_macro("ERROR")
+#undef ERROR
+#pragma push_macro("ERROR_BUSY")
+#undef ERROR_BUSY
+#pragma push_macro("ERROR_INSTALL_FAILED")
+#undef ERROR_INSTALL_FAILED
+#pragma push_macro("ERROR_NOT_FOUND")
+#undef ERROR_NOT_FOUND
+#pragma push_macro("GetClassName")
+#undef GetClassName
+#pragma push_macro("GetMessage")
+#undef GetMessage
+#pragma push_macro("GetObject")
+#undef GetObject
+#pragma push_macro("IGNORE")
+#undef IGNORE
+#pragma push_macro("IN")
+#undef IN
+#pragma push_macro("INPUT_KEYBOARD")
+#undef INPUT_KEYBOARD
+#pragma push_macro("NO_ERROR")
+#undef NO_ERROR
+#pragma push_macro("OUT")
+#undef OUT
+#pragma push_macro("OPTIONAL")
+#undef OPTIONAL
+#pragma push_macro("min")
+#undef min
+#pragma push_macro("max")
+#undef max
+#pragma push_macro("NEAR")
+#undef NEAR
+#pragma push_macro("NO_DATA")
+#undef NO_DATA
+#pragma push_macro("REASON_UNKNOWN")
+#undef REASON_UNKNOWN
+#pragma push_macro("SERVICE_DISABLED")
+#undef SERVICE_DISABLED
+#pragma push_macro("SEVERITY_ERROR")
+#undef SEVERITY_ERROR
+#pragma push_macro("STATUS_PENDING")
+#undef STATUS_PENDING
+#pragma push_macro("STRICT")
+#undef STRICT
+#pragma push_macro("timezone")
+#undef timezone
+#endif  // _MSC_VER
+
+#ifdef __APPLE__
+// Inconvenient macro names from usr/include/math.h in some macOS SDKs.
+#pragma push_macro("DOMAIN")
+#undef DOMAIN
+// Inconvenient macro names from /usr/include/mach/boolean.h in some macOS SDKs.
+#pragma push_macro("TRUE")
+#undef TRUE
+#pragma push_macro("FALSE")
+#undef FALSE
+// Inconvenient macro names from usr/include/sys/syslimits.h in some macOS SDKs.
+#pragma push_macro("UID_MAX")
+#undef UID_MAX
+#endif  // __APPLE__
+
+#if defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER)
+// Don't let Objective-C Macros interfere with proto identifiers with the same
+// name.
+#pragma push_macro("DEBUG")
+#undef DEBUG
+#endif // defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER)
+
+#if PROTOBUF_GNUC_MIN(3, 0)
+// GCC does not allow disabling diagnostics within an expression:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60875, so we disable this one
+// globally even though it's only used for PROTOBUF_FIELD_OFFSET.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+// Silence some MSVC warnings in all our code.
+#ifdef _MSC_VER
+#pragma warning(push)
+// For non-trivial unions
+#pragma warning(disable : 4582)
+#pragma warning(disable : 4583)
+// For init_seg(lib)
+#pragma warning(disable : 4073)
+// To silence the fact that we will pop this push from another file
+#pragma warning(disable : 5031)
+// Conditional expression is constant
+#pragma warning(disable: 4127)
+// decimal digit terminates octal escape sequence
+#pragma warning(disable: 4125)
+#endif
+
+// We don't want code outside port_def doing complex testing, so
+// remove our portable condition test macros to nudge folks away from
+// using it themselves.
+#ifdef PROTOBUF_has_cpp_attribute_DEFINED_
+#  undef __has_cpp_attribute
+#  undef PROTOBUF_has_cpp_attribute_DEFINED_
+#endif
+#ifdef PROTOBUF_has_feature_DEFINED_
+#  undef __has_feature
+#  undef PROTOBUF_has_feature_DEFINED_
+#endif
+#ifdef PROTOBUF_has_warning_DEFINED_
+#  undef __has_warning
+#  undef PROTOBUF_has_warning_DEFINED_
+#endif
+#ifdef PROTOBUF_has_attribute_DEFINED_
+#  undef __has_attribute
+#  undef PROTOBUF_has_attribute_DEFINED_
+#endif
+#ifdef PROTOBUF_has_builtin_DEFINED_
+#  undef __has_builtin
+#  undef PROTOBUF_has_builtin_DEFINED_
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port_undef.inc b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port_undef.inc
new file mode 100644
index 0000000..e880fa5
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/port_undef.inc
@@ -0,0 +1,160 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// #undefs all macros defined in port_def.inc.  See comments in port_def.inc
+// for more info.
+
+#ifndef PROTOBUF_NAMESPACE
+#error "port_undef.inc must be included after port_def.inc"
+#endif
+
+#undef PROTOBUF_BUILTIN_BSWAP16
+#undef PROTOBUF_BUILTIN_BSWAP32
+#undef PROTOBUF_BUILTIN_BSWAP64
+#undef PROTOBUF_GNUC_MIN
+#undef PROTOBUF_MSC_VER_MIN
+#undef PROTOBUF_CPLUSPLUS_MIN
+#undef PROTOBUF_NAMESPACE
+#undef PROTOBUF_NAMESPACE_ID
+#undef PROTOBUF_ALWAYS_INLINE
+#undef PROTOBUF_NDEBUG_INLINE
+#undef PROTOBUF_MUSTTAIL
+#undef PROTOBUF_TAILCALL
+#undef PROTOBUF_COLD
+#undef PROTOBUF_NOINLINE
+#undef PROTOBUF_SECTION_VARIABLE
+#undef PROTOBUF_DEPRECATED
+#undef PROTOBUF_DEPRECATED_ENUM
+#undef PROTOBUF_DEPRECATED_MSG
+#undef PROTOBUF_FUNC_ALIGN
+#undef PROTOBUF_RETURNS_NONNULL
+#undef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#undef PROTOBUF_RTTI
+#undef PROTOBUF_VERSION
+#undef PROTOBUF_VERSION_SUFFIX
+#undef PROTOBUF_FIELD_OFFSET
+#undef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC
+#undef PROTOBUF_MIN_PROTOC_VERSION
+#undef PROTOBUF_PREDICT_TRUE
+#undef PROTOBUF_PREDICT_FALSE
+#undef PROTOBUF_FALLTHROUGH_INTENDED
+#undef PROTOBUF_EXPORT
+#undef PROTOC_EXPORT
+#undef PROTOBUF_NODISCARD
+#undef PROTOBUF_FORCE_COPY_IN_RELEASE
+#undef PROTOBUF_FORCE_COPY_IN_SWAP
+#undef PROTOBUF_FORCE_COPY_IN_MOVE
+#undef PROTOBUF_FORCE_RESET_IN_CLEAR
+#undef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+#undef PROTOBUF_NAMESPACE_OPEN
+#undef PROTOBUF_NAMESPACE_CLOSE
+#undef PROTOBUF_UNUSED
+#undef PROTOBUF_ASSUME
+#undef PROTOBUF_EXPORT_TEMPLATE_DECLARE
+#undef PROTOBUF_EXPORT_TEMPLATE_DEFINE
+#undef PROTOBUF_ALIGNAS
+#undef PROTOBUF_FINAL
+#undef PROTOBUF_FUTURE_FINAL
+#undef PROTOBUF_THREAD_LOCAL
+#undef PROTOBUF_LITTLE_ENDIAN
+#undef PROTOBUF_BIG_ENDIAN
+#undef PROTOBUF_MESSAGE_OWNED_ARENA_EXPERIMENT
+#undef PROTOBUF_CONSTINIT
+#undef PROTOBUF_CONSTEXPR
+#undef PROTOBUF_ATTRIBUTE_WEAK
+#undef PROTOBUF_HAVE_ATTRIBUTE_WEAK
+#undef PROTOBUF_ATTRIBUTE_NO_DESTROY
+#undef PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#undef PROTOBUF_PRAGMA_INIT_SEG
+#undef PROTOBUF_ASAN
+#undef PROTOBUF_MSAN
+#undef PROTOBUF_TSAN
+#undef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
+#undef PROTOBUF_TC_PARAM_DECL
+#undef PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED
+#undef PROTOBUF_LOCKS_EXCLUDED
+#undef PROTOBUF_NO_THREAD_SAFETY_ANALYSIS
+#undef PROTOBUF_GUARDED_BY
+
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+#undef PROTOBUF_FUTURE_BREAKING_CHANGES
+#endif
+
+// Restore macro that may have been #undef'd in port_def.inc.
+#ifdef _MSC_VER
+#pragma pop_macro("CREATE_NEW")
+#pragma pop_macro("DELETE")
+#pragma pop_macro("DOUBLE_CLICK")
+#pragma pop_macro("ERROR")
+#pragma pop_macro("ERROR_BUSY")
+#pragma pop_macro("ERROR_INSTALL_FAILED")
+#pragma pop_macro("ERROR_NOT_FOUND")
+#pragma pop_macro("GetClassName")
+#pragma pop_macro("GetMessage")
+#pragma pop_macro("GetObject")
+#pragma pop_macro("IGNORE")
+#pragma pop_macro("IN")
+#pragma pop_macro("INPUT_KEYBOARD")
+#pragma pop_macro("OUT")
+#pragma pop_macro("OPTIONAL")
+#pragma pop_macro("min")
+#pragma pop_macro("max")
+#pragma pop_macro("NEAR")
+#pragma pop_macro("NO_DATA")
+#pragma pop_macro("NO_ERROR")
+#pragma pop_macro("REASON_UNKNOWN")
+#pragma pop_macro("SERVICE_DISABLED")
+#pragma pop_macro("SEVERITY_ERROR")
+#pragma pop_macro("STRICT")
+#pragma pop_macro("STATUS_PENDING")
+#pragma pop_macro("timezone")
+#endif
+
+#ifdef __APPLE__
+#pragma pop_macro("DOMAIN")
+#pragma pop_macro("TRUE")
+#pragma pop_macro("FALSE")
+#pragma pop_macro("UID_MAX")
+#endif  // __APPLE__
+
+#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
+#pragma pop_macro("DEBUG")
+#endif // defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+// Pop the warning(push) from port_def.inc
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection.h
new file mode 100644
index 0000000..7b75a43
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection.h
@@ -0,0 +1,570 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This header defines the RepeatedFieldRef class template used to access
+// repeated fields with protobuf reflection API.
+#ifndef GOOGLE_PROTOBUF_REFLECTION_H__
+#define GOOGLE_PROTOBUF_REFLECTION_H__
+
+
+#include <memory>
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/generated_enum_util.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template <typename T, typename Enable = void>
+struct RefTypeTraits;
+}  // namespace internal
+
+template <typename T>
+RepeatedFieldRef<T> Reflection::GetRepeatedFieldRef(
+    const Message& message, const FieldDescriptor* field) const {
+  return RepeatedFieldRef<T>(message, field);
+}
+
+template <typename T>
+MutableRepeatedFieldRef<T> Reflection::GetMutableRepeatedFieldRef(
+    Message* message, const FieldDescriptor* field) const {
+  return MutableRepeatedFieldRef<T>(message, field);
+}
+
+// RepeatedFieldRef definition for non-message types.
+template <typename T>
+class RepeatedFieldRef<
+    T, typename std::enable_if<!std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  T Get(int index) const { return accessor_->template Get<T>(data_, index); }
+
+  typedef IteratorType iterator;
+  typedef IteratorType const_iterator;
+  typedef T value_type;
+  typedef T& reference;
+  typedef const T& const_reference;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin() const { return iterator(data_, accessor_, true); }
+  iterator end() const { return iterator(data_, accessor_, false); }
+
+ private:
+  friend class Reflection;
+  RepeatedFieldRef(const Message& message, const FieldDescriptor* field) {
+    const Reflection* reflection = message.GetReflection();
+    data_ = reflection->RepeatedFieldData(const_cast<Message*>(&message), field,
+                                          internal::RefTypeTraits<T>::cpp_type,
+                                          nullptr);
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+  }
+
+  const void* data_;
+  const AccessorType* accessor_;
+};
+
+// MutableRepeatedFieldRef definition for non-message types.
+template <typename T>
+class MutableRepeatedFieldRef<
+    T, typename std::enable_if<!std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  T Get(int index) const { return accessor_->template Get<T>(data_, index); }
+
+  void Set(int index, const T& value) const {
+    accessor_->template Set<T>(data_, index, value);
+  }
+  void Add(const T& value) const { accessor_->template Add<T>(data_, value); }
+  void RemoveLast() const { accessor_->RemoveLast(data_); }
+  void SwapElements(int index1, int index2) const {
+    accessor_->SwapElements(data_, index1, index2);
+  }
+  void Clear() const { accessor_->Clear(data_); }
+
+  void Swap(const MutableRepeatedFieldRef& other) const {
+    accessor_->Swap(data_, other.accessor_, other.data_);
+  }
+
+  template <typename Container>
+  void MergeFrom(const Container& container) const {
+    typedef typename Container::const_iterator Iterator;
+    for (Iterator it = container.begin(); it != container.end(); ++it) {
+      Add(*it);
+    }
+  }
+  template <typename Container>
+  void CopyFrom(const Container& container) const {
+    Clear();
+    MergeFrom(container);
+  }
+
+ private:
+  friend class Reflection;
+  MutableRepeatedFieldRef(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        message, field, internal::RefTypeTraits<T>::cpp_type, nullptr);
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+  }
+
+  void* data_;
+  const AccessorType* accessor_;
+};
+
+// RepeatedFieldRef definition for message types.
+template <typename T>
+class RepeatedFieldRef<
+    T, typename std::enable_if<std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  // This method returns a reference to the underlying message object if it
+  // exists. If a message object doesn't exist (e.g., data stored in serialized
+  // form), scratch_space will be filled with the data and a reference to it
+  // will be returned.
+  //
+  // Example:
+  //   RepeatedFieldRef<Message> h = ...
+  //   unique_ptr<Message> scratch_space(h.NewMessage());
+  //   const Message& item = h.Get(index, scratch_space.get());
+  const T& Get(int index, T* scratch_space) const {
+    return *static_cast<const T*>(accessor_->Get(data_, index, scratch_space));
+  }
+  // Create a new message of the same type as the messages stored in this
+  // repeated field. Caller takes ownership of the returned object.
+  T* NewMessage() const { return static_cast<T*>(default_instance_->New()); }
+
+  typedef IteratorType iterator;
+  typedef IteratorType const_iterator;
+  typedef T value_type;
+  typedef T& reference;
+  typedef const T& const_reference;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin() const {
+    return iterator(data_, accessor_, true, NewMessage());
+  }
+  iterator end() const {
+    // The end iterator must not be dereferenced, no need for scratch space.
+    return iterator(data_, accessor_, false, nullptr);
+  }
+
+ private:
+  friend class Reflection;
+  RepeatedFieldRef(const Message& message, const FieldDescriptor* field) {
+    const Reflection* reflection = message.GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        const_cast<Message*>(&message), field,
+        internal::RefTypeTraits<T>::cpp_type,
+        internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+    default_instance_ =
+        reflection->GetMessageFactory()->GetPrototype(field->message_type());
+  }
+
+  const void* data_;
+  const AccessorType* accessor_;
+  const Message* default_instance_;
+};
+
+// MutableRepeatedFieldRef definition for message types.
+template <typename T>
+class MutableRepeatedFieldRef<
+    T, typename std::enable_if<std::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const { return accessor_->IsEmpty(data_); }
+  int size() const { return accessor_->Size(data_); }
+  // See comments for RepeatedFieldRef<Message>::Get()
+  const T& Get(int index, T* scratch_space) const {
+    return *static_cast<const T*>(accessor_->Get(data_, index, scratch_space));
+  }
+  // Create a new message of the same type as the messages stored in this
+  // repeated field. Caller takes ownership of the returned object.
+  T* NewMessage() const { return static_cast<T*>(default_instance_->New()); }
+
+  void Set(int index, const T& value) const {
+    accessor_->Set(data_, index, &value);
+  }
+  void Add(const T& value) const { accessor_->Add(data_, &value); }
+  void RemoveLast() const { accessor_->RemoveLast(data_); }
+  void SwapElements(int index1, int index2) const {
+    accessor_->SwapElements(data_, index1, index2);
+  }
+  void Clear() const { accessor_->Clear(data_); }
+
+  void Swap(const MutableRepeatedFieldRef& other) const {
+    accessor_->Swap(data_, other.accessor_, other.data_);
+  }
+
+  template <typename Container>
+  void MergeFrom(const Container& container) const {
+    typedef typename Container::const_iterator Iterator;
+    for (Iterator it = container.begin(); it != container.end(); ++it) {
+      Add(*it);
+    }
+  }
+  template <typename Container>
+  void CopyFrom(const Container& container) const {
+    Clear();
+    MergeFrom(container);
+  }
+
+ private:
+  friend class Reflection;
+  MutableRepeatedFieldRef(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        message, field, internal::RefTypeTraits<T>::cpp_type,
+        internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+    default_instance_ =
+        reflection->GetMessageFactory()->GetPrototype(field->message_type());
+  }
+
+  void* data_;
+  const AccessorType* accessor_;
+  const Message* default_instance_;
+};
+
+namespace internal {
+// Interfaces used to implement reflection RepeatedFieldRef API.
+// Reflection::GetRepeatedAccessor() should return a pointer to an singleton
+// object that implements the below interface.
+//
+// This interface passes/returns values using void pointers. The actual type
+// of the value depends on the field's cpp_type. Following is a mapping from
+// cpp_type to the type that should be used in this interface:
+//
+//   field->cpp_type()      T                Actual type of void*
+//   CPPTYPE_INT32        int32_t                 int32_t
+//   CPPTYPE_UINT32       uint32_t                uint32_t
+//   CPPTYPE_INT64        int64_t                 int64_t
+//   CPPTYPE_UINT64       uint64_t                uint64_t
+//   CPPTYPE_DOUBLE       double                  double
+//   CPPTYPE_FLOAT        float                   float
+//   CPPTYPE_BOOL         bool                    bool
+//   CPPTYPE_ENUM         generated enum type     int32_t
+//   CPPTYPE_STRING       string                  std::string
+//   CPPTYPE_MESSAGE      generated message type  google::protobuf::Message
+//                        or google::protobuf::Message
+//
+// Note that for enums we use int32_t in the interface.
+//
+// You can map from T to the actual type using RefTypeTraits:
+//   typedef RefTypeTraits<T>::AccessorValueType ActualType;
+class PROTOBUF_EXPORT RepeatedFieldAccessor {
+ public:
+  // Typedefs for clarity.
+  typedef void Field;
+  typedef void Value;
+  typedef void Iterator;
+
+  virtual bool IsEmpty(const Field* data) const = 0;
+  virtual int Size(const Field* data) const = 0;
+  // Depends on the underlying representation of the repeated field, this
+  // method can return a pointer to the underlying object if such an object
+  // exists, or fill the data into scratch_space and return scratch_space.
+  // Callers of this method must ensure scratch_space is a valid pointer
+  // to a mutable object of the correct type.
+  virtual const Value* Get(const Field* data, int index,
+                           Value* scratch_space) const = 0;
+
+  virtual void Clear(Field* data) const = 0;
+  virtual void Set(Field* data, int index, const Value* value) const = 0;
+  virtual void Add(Field* data, const Value* value) const = 0;
+  virtual void RemoveLast(Field* data) const = 0;
+  virtual void SwapElements(Field* data, int index1, int index2) const = 0;
+  virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator,
+                    Field* other_data) const = 0;
+
+  // Create an iterator that points at the beginning of the repeated field.
+  virtual Iterator* BeginIterator(const Field* data) const = 0;
+  // Create an iterator that points at the end of the repeated field.
+  virtual Iterator* EndIterator(const Field* data) const = 0;
+  // Make a copy of an iterator and return the new copy.
+  virtual Iterator* CopyIterator(const Field* data,
+                                 const Iterator* iterator) const = 0;
+  // Move an iterator to point to the next element.
+  virtual Iterator* AdvanceIterator(const Field* data,
+                                    Iterator* iterator) const = 0;
+  // Compare whether two iterators point to the same element.
+  virtual bool EqualsIterator(const Field* data, const Iterator* a,
+                              const Iterator* b) const = 0;
+  // Delete an iterator created by BeginIterator(), EndIterator() and
+  // CopyIterator().
+  virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0;
+  // Like Get() but for iterators.
+  virtual const Value* GetIteratorValue(const Field* data,
+                                        const Iterator* iterator,
+                                        Value* scratch_space) const = 0;
+
+  // Templated methods that make using this interface easier for non-message
+  // types.
+  template <typename T>
+  T Get(const Field* data, int index) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    ActualType scratch_space;
+    return static_cast<T>(*reinterpret_cast<const ActualType*>(
+        Get(data, index, static_cast<Value*>(&scratch_space))));
+  }
+
+  template <typename T, typename ValueType>
+  void Set(Field* data, int index, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32_t). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Set(data, index, static_cast<const Value*>(&tmp));
+  }
+
+  template <typename T, typename ValueType>
+  void Add(Field* data, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32_t). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Add(data, static_cast<const Value*>(&tmp));
+  }
+
+ protected:
+  // We want the destructor to be completely trivial as to allow it to be
+  // a function local static. Hence we make it non-virtual and protected,
+  // this class only live as part of a global singleton and should not be
+  // deleted.
+  ~RepeatedFieldAccessor() = default;
+};
+
+// Implement (Mutable)RepeatedFieldRef::iterator
+template <typename T>
+class RepeatedFieldRefIterator {
+  typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
+  typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
+  typedef typename RefTypeTraits<T>::IteratorPointerType IteratorPointerType;
+
+ public:
+  using iterator_category = std::forward_iterator_tag;
+  using value_type = T;
+  using pointer = T*;
+  using reference = T&;
+  using difference_type = std::ptrdiff_t;
+
+  // Constructor for non-message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor, bool begin)
+      : data_(data),
+        accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data)
+                        : accessor->EndIterator(data)),
+        // The end iterator must not be dereferenced, no need for scratch space.
+        scratch_space_(begin ? new AccessorValueType : nullptr) {}
+  // Constructor for message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor, bool begin,
+                           AccessorValueType* scratch_space)
+      : data_(data),
+        accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data)
+                        : accessor->EndIterator(data)),
+        scratch_space_(scratch_space) {}
+  ~RepeatedFieldRefIterator() { accessor_->DeleteIterator(data_, iterator_); }
+  RepeatedFieldRefIterator operator++(int) {
+    RepeatedFieldRefIterator tmp(*this);
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return tmp;
+  }
+  RepeatedFieldRefIterator& operator++() {
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return *this;
+  }
+  IteratorValueType operator*() const {
+    return static_cast<IteratorValueType>(
+        *static_cast<const AccessorValueType*>(accessor_->GetIteratorValue(
+            data_, iterator_, scratch_space_.get())));
+  }
+  IteratorPointerType operator->() const {
+    return static_cast<IteratorPointerType>(
+        accessor_->GetIteratorValue(data_, iterator_, scratch_space_.get()));
+  }
+  bool operator!=(const RepeatedFieldRefIterator& other) const {
+    assert(data_ == other.data_);
+    assert(accessor_ == other.accessor_);
+    return !accessor_->EqualsIterator(data_, iterator_, other.iterator_);
+  }
+  bool operator==(const RepeatedFieldRefIterator& other) const {
+    return !this->operator!=(other);
+  }
+
+  RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other)
+      : data_(other.data_),
+        accessor_(other.accessor_),
+        iterator_(accessor_->CopyIterator(data_, other.iterator_)) {}
+  RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) {
+    if (this != &other) {
+      accessor_->DeleteIterator(data_, iterator_);
+      data_ = other.data_;
+      accessor_ = other.accessor_;
+      iterator_ = accessor_->CopyIterator(data_, other.iterator_);
+    }
+    return *this;
+  }
+
+ protected:
+  const void* data_;
+  const RepeatedFieldAccessor* accessor_;
+  void* iterator_;
+  std::unique_ptr<AccessorValueType> scratch_space_;
+};
+
+// TypeTraits that maps the type parameter T of RepeatedFieldRef or
+// MutableRepeatedFieldRef to corresponding iterator type,
+// RepeatedFieldAccessor type, etc.
+template <typename T>
+struct PrimitiveTraits {
+  static constexpr bool is_primitive = false;
+};
+#define DEFINE_PRIMITIVE(TYPE, type)                 \
+  template <>                                        \
+  struct PrimitiveTraits<type> {                     \
+    static const bool is_primitive = true;           \
+    static const FieldDescriptor::CppType cpp_type = \
+        FieldDescriptor::CPPTYPE_##TYPE;             \
+  };
+DEFINE_PRIMITIVE(INT32, int32_t)
+DEFINE_PRIMITIVE(UINT32, uint32_t)
+DEFINE_PRIMITIVE(INT64, int64_t)
+DEFINE_PRIMITIVE(UINT64, uint64_t)
+DEFINE_PRIMITIVE(FLOAT, float)
+DEFINE_PRIMITIVE(DOUBLE, double)
+DEFINE_PRIMITIVE(BOOL, bool)
+#undef DEFINE_PRIMITIVE
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef T AccessorValueType;
+  typedef T IteratorValueType;
+  typedef T* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      PrimitiveTraits<T>::cpp_type;
+  static const Descriptor* GetMessageFieldDescriptor() { return nullptr; }
+};
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<is_proto_enum<T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  // We use int32_t for repeated enums in RepeatedFieldAccessor.
+  typedef int32_t AccessorValueType;
+  typedef T IteratorValueType;
+  typedef int32_t* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_ENUM;
+  static const Descriptor* GetMessageFieldDescriptor() { return nullptr; }
+};
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<std::is_same<std::string, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef std::string AccessorValueType;
+  typedef const std::string IteratorValueType;
+  typedef const std::string* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_STRING;
+  static const Descriptor* GetMessageFieldDescriptor() { return nullptr; }
+};
+
+template <typename T>
+struct MessageDescriptorGetter {
+  static const Descriptor* get() {
+    return T::default_instance().GetDescriptor();
+  }
+};
+template <>
+struct MessageDescriptorGetter<Message> {
+  static const Descriptor* get() { return nullptr; }
+};
+
+template <typename T>
+struct RefTypeTraits<
+    T, typename std::enable_if<std::is_base_of<Message, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef Message AccessorValueType;
+  typedef const T& IteratorValueType;
+  typedef const T* IteratorPointerType;
+  static constexpr FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_MESSAGE;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return MessageDescriptorGetter<T>::get();
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection_internal.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection_internal.h
new file mode 100644
index 0000000..f749c3e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection_internal.h
@@ -0,0 +1,364 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
+#define GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
+
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/repeated_field.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// A base class for RepeatedFieldAccessor implementations that can support
+// random-access efficiently. All iterator methods delegates the work to
+// corresponding random-access methods.
+class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor {
+ public:
+  Iterator* BeginIterator(const Field* /*data*/) const override {
+    return PositionToIterator(0);
+  }
+  Iterator* EndIterator(const Field* data) const override {
+    return PositionToIterator(this->Size(data));
+  }
+  Iterator* CopyIterator(const Field* /*data*/,
+                         const Iterator* iterator) const override {
+    return const_cast<Iterator*>(iterator);
+  }
+  Iterator* AdvanceIterator(const Field* /*data*/,
+                            Iterator* iterator) const override {
+    return PositionToIterator(IteratorToPosition(iterator) + 1);
+  }
+  bool EqualsIterator(const Field* /*data*/, const Iterator* a,
+                      const Iterator* b) const override {
+    return a == b;
+  }
+  void DeleteIterator(const Field* /*data*/,
+                      Iterator* /*iterator*/) const override {}
+  const Value* GetIteratorValue(const Field* data, const Iterator* iterator,
+                                Value* scratch_space) const override {
+    return Get(data, static_cast<int>(IteratorToPosition(iterator)),
+               scratch_space);
+  }
+
+ protected:
+  ~RandomAccessRepeatedFieldAccessor() = default;
+
+ private:
+  static intptr_t IteratorToPosition(const Iterator* iterator) {
+    return reinterpret_cast<intptr_t>(iterator);
+  }
+  static Iterator* PositionToIterator(intptr_t position) {
+    return reinterpret_cast<Iterator*>(position);
+  }
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedField<T>.
+template <typename T>
+class RepeatedFieldWrapper : public RandomAccessRepeatedFieldAccessor {
+ public:
+  RepeatedFieldWrapper() {}
+  bool IsEmpty(const Field* data) const override {
+    return GetRepeatedField(data)->empty();
+  }
+  int Size(const Field* data) const override {
+    return GetRepeatedField(data)->size();
+  }
+  const Value* Get(const Field* data, int index,
+                   Value* scratch_space) const override {
+    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  void Clear(Field* data) const override {
+    MutableRepeatedField(data)->Clear();
+  }
+  void Set(Field* data, int index, const Value* value) const override {
+    MutableRepeatedField(data)->Set(index, ConvertToT(value));
+  }
+  void Add(Field* data, const Value* value) const override {
+    MutableRepeatedField(data)->Add(ConvertToT(value));
+  }
+  void RemoveLast(Field* data) const override {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  void SwapElements(Field* data, int index1, int index2) const override {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+
+ protected:
+  ~RepeatedFieldWrapper() = default;
+  typedef RepeatedField<T> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(data);
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(data);
+  }
+
+  // Convert an object received by this accessor to an object to be stored in
+  // the underlying RepeatedField.
+  virtual T ConvertToT(const Value* value) const = 0;
+
+  // Convert an object stored in RepeatedPtrField to an object that will be
+  // returned by this accessor. If the two objects have the same type (true for
+  // string fields with ctype=STRING), a pointer to the source object can be
+  // returned directly. Otherwise, data should be copied from value to
+  // scratch_space and scratch_space should be returned.
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const = 0;
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedPtrField<T>.
+template <typename T>
+class RepeatedPtrFieldWrapper : public RandomAccessRepeatedFieldAccessor {
+ public:
+  bool IsEmpty(const Field* data) const override {
+    return GetRepeatedField(data)->empty();
+  }
+  int Size(const Field* data) const override {
+    return GetRepeatedField(data)->size();
+  }
+  const Value* Get(const Field* data, int index,
+                   Value* scratch_space) const override {
+    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  void Clear(Field* data) const override {
+    MutableRepeatedField(data)->Clear();
+  }
+  void Set(Field* data, int index, const Value* value) const override {
+    ConvertToT(value, MutableRepeatedField(data)->Mutable(index));
+  }
+  void Add(Field* data, const Value* value) const override {
+    T* allocated = New(value);
+    ConvertToT(value, allocated);
+    MutableRepeatedField(data)->AddAllocated(allocated);
+  }
+  void RemoveLast(Field* data) const override {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  void SwapElements(Field* data, int index1, int index2) const override {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+
+ protected:
+  ~RepeatedPtrFieldWrapper() = default;
+  typedef RepeatedPtrField<T> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(data);
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(data);
+  }
+
+  // Create a new T instance. For repeated message fields, T can be specified
+  // as google::protobuf::Message so we can't use "new T()" directly. In that case, value
+  // should be a message of the same type (it's ensured by the caller) and a
+  // new message object will be created using it.
+  virtual T* New(const Value* value) const = 0;
+
+  // Convert an object received by this accessor to an object that will be
+  // stored in the underlying RepeatedPtrField.
+  virtual void ConvertToT(const Value* value, T* result) const = 0;
+
+  // Convert an object stored in RepeatedPtrField to an object that will be
+  // returned by this accessor. If the two objects have the same type (true for
+  // string fields with ctype=STRING), a pointer to the source object can be
+  // returned directly. Otherwise, data should be copied from value to
+  // scratch_space and scratch_space should be returned.
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const = 0;
+};
+
+// An implementation of RandomAccessRepeatedFieldAccessor that manipulates
+// MapFieldBase.
+class MapFieldAccessor final : public RandomAccessRepeatedFieldAccessor {
+ public:
+  MapFieldAccessor() {}
+  virtual ~MapFieldAccessor() {}
+  bool IsEmpty(const Field* data) const override {
+    return GetRepeatedField(data)->empty();
+  }
+  int Size(const Field* data) const override {
+    return GetRepeatedField(data)->size();
+  }
+  const Value* Get(const Field* data, int index,
+                   Value* scratch_space) const override {
+    return ConvertFromEntry(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  void Clear(Field* data) const override {
+    MutableRepeatedField(data)->Clear();
+  }
+  void Set(Field* data, int index, const Value* value) const override {
+    ConvertToEntry(value, MutableRepeatedField(data)->Mutable(index));
+  }
+  void Add(Field* data, const Value* value) const override {
+    Message* allocated = New(value);
+    ConvertToEntry(value, allocated);
+    MutableRepeatedField(data)->AddAllocated(allocated);
+  }
+  void RemoveLast(Field* data) const override {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  void SwapElements(Field* data, int index1, int index2) const override {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  typedef RepeatedPtrField<Message> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(
+        (&reinterpret_cast<const MapFieldBase*>(data)->GetRepeatedField()));
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(
+        reinterpret_cast<MapFieldBase*>(data)->MutableRepeatedField());
+  }
+  virtual Message* New(const Value* value) const {
+    return static_cast<const Message*>(value)->New();
+  }
+  // Convert an object received by this accessor to an MapEntry message to be
+  // stored in the underlying MapFieldBase.
+  virtual void ConvertToEntry(const Value* value, Message* result) const {
+    result->CopyFrom(*static_cast<const Message*>(value));
+  }
+  // Convert a MapEntry message stored in the underlying MapFieldBase to an
+  // object that will be returned by this accessor.
+  virtual const Value* ConvertFromEntry(const Message& value,
+                                        Value* /*scratch_space*/) const {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+// Default implementations of RepeatedFieldAccessor for primitive types.
+template <typename T>
+class RepeatedFieldPrimitiveAccessor final : public RepeatedFieldWrapper<T> {
+  typedef void Field;
+  typedef void Value;
+  using RepeatedFieldWrapper<T>::MutableRepeatedField;
+
+ public:
+  RepeatedFieldPrimitiveAccessor() {}
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    // Currently RepeatedFieldPrimitiveAccessor is the only implementation of
+    // RepeatedFieldAccessor for primitive types. As we are using singletons
+    // for these accessors, here "other_mutator" must be "this".
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  T ConvertToT(const Value* value) const override {
+    return *static_cast<const T*>(value);
+  }
+  const Value* ConvertFromT(const T& value,
+                            Value* /*scratch_space*/) const override {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+// Default implementation of RepeatedFieldAccessor for string fields with
+// ctype=STRING.
+class RepeatedPtrFieldStringAccessor final
+    : public RepeatedPtrFieldWrapper<std::string> {
+  typedef void Field;
+  typedef void Value;
+  using RepeatedFieldAccessor::Add;
+
+ public:
+  RepeatedPtrFieldStringAccessor() {}
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    if (this == other_mutator) {
+      MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+    } else {
+      RepeatedPtrField<std::string> tmp;
+      tmp.Swap(MutableRepeatedField(data));
+      int other_size = other_mutator->Size(other_data);
+      for (int i = 0; i < other_size; ++i) {
+        Add<std::string>(data, other_mutator->Get<std::string>(other_data, i));
+      }
+      int size = Size(data);
+      other_mutator->Clear(other_data);
+      for (int i = 0; i < size; ++i) {
+        other_mutator->Add<std::string>(other_data, tmp.Get(i));
+      }
+    }
+  }
+
+ protected:
+  std::string* New(const Value*) const override { return new std::string(); }
+  void ConvertToT(const Value* value, std::string* result) const override {
+    *result = *static_cast<const std::string*>(value);
+  }
+  const Value* ConvertFromT(const std::string& value,
+                            Value* /*scratch_space*/) const override {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+
+class RepeatedPtrFieldMessageAccessor final
+    : public RepeatedPtrFieldWrapper<Message> {
+  typedef void Field;
+  typedef void Value;
+
+ public:
+  RepeatedPtrFieldMessageAccessor() {}
+  void Swap(Field* data, const internal::RepeatedFieldAccessor* other_mutator,
+            Field* other_data) const override {
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  Message* New(const Value* value) const override {
+    return static_cast<const Message*>(value)->New();
+  }
+  void ConvertToT(const Value* value, Message* result) const override {
+    result->CopyFrom(*static_cast<const Message*>(value));
+  }
+  const Value* ConvertFromT(const Message& value,
+                            Value* /*scratch_space*/) const override {
+    return static_cast<const Value*>(&value);
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection_ops.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection_ops.h
new file mode 100644
index 0000000..0a45702
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/reflection_ops.h
@@ -0,0 +1,92 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__
+#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Basic operations that can be performed using reflection.
+// These can be used as a cheap way to implement the corresponding
+// methods of the Message interface, though they are likely to be
+// slower than implementations tailored for the specific message type.
+//
+// This class should stay limited to operations needed to implement
+// the Message interface.
+//
+// This class is really a namespace that contains only static methods.
+class PROTOBUF_EXPORT ReflectionOps {
+ public:
+  static void Copy(const Message& from, Message* to);
+  static void Merge(const Message& from, Message* to);
+  static void Clear(Message* message);
+  static bool IsInitialized(const Message& message);
+  static bool IsInitialized(const Message& message, bool check_fields,
+                            bool check_descendants);
+  static void DiscardUnknownFields(Message* message);
+
+  // Finds all unset required fields in the message and adds their full
+  // paths (e.g. "foo.bar[5].baz") to *names.  "prefix" will be attached to
+  // the front of each name.
+  static void FindInitializationErrors(const Message& message,
+                                       const std::string& prefix,
+                                       std::vector<std::string>* errors);
+
+ private:
+  // All methods are static.  No need to construct.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_OPS_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/repeated_field.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/repeated_field.h
new file mode 100644
index 0000000..3fb734e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/repeated_field.h
@@ -0,0 +1,1219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// RepeatedField and RepeatedPtrField are used by generated protocol message
+// classes to manipulate repeated fields.  These classes are very similar to
+// STL's vector, but include a number of optimizations found to be useful
+// specifically in the case of Protocol Buffers.  RepeatedPtrField is
+// particularly different from STL vector as it manages ownership of the
+// pointers that it contains.
+//
+// This header covers RepeatedField.
+
+#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
+
+
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_ptr_field.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+namespace internal {
+
+template <typename T, int kRepHeaderSize>
+constexpr int RepeatedFieldLowerClampLimit() {
+  // The header is padded to be at least `sizeof(T)` when it would be smaller
+  // otherwise.
+  static_assert(sizeof(T) <= kRepHeaderSize, "");
+  // We want to pad the minimum size to be a power of two bytes, including the
+  // header.
+  // The first allocation is kRepHeaderSize bytes worth of elements for a total
+  // of 2*kRepHeaderSize bytes.
+  // For an 8-byte header, we allocate 8 bool, 2 ints, or 1 int64.
+  return kRepHeaderSize / sizeof(T);
+}
+
+// kRepeatedFieldUpperClampLimit is the lowest signed integer value that
+// overflows when multiplied by 2 (which is undefined behavior). Sizes above
+// this will clamp to the maximum int value instead of following exponential
+// growth when growing a repeated field.
+constexpr int kRepeatedFieldUpperClampLimit =
+    (std::numeric_limits<int>::max() / 2) + 1;
+
+template <typename Iter>
+inline int CalculateReserve(Iter begin, Iter end, std::forward_iterator_tag) {
+  return static_cast<int>(std::distance(begin, end));
+}
+
+template <typename Iter>
+inline int CalculateReserve(Iter /*begin*/, Iter /*end*/,
+                            std::input_iterator_tag /*unused*/) {
+  return -1;
+}
+
+template <typename Iter>
+inline int CalculateReserve(Iter begin, Iter end) {
+  typedef typename std::iterator_traits<Iter>::iterator_category Category;
+  return CalculateReserve(begin, end, Category());
+}
+
+// Swaps two blocks of memory of size sizeof(T).
+template <typename T>
+inline void SwapBlock(char* p, char* q) {
+  T tmp;
+  memcpy(&tmp, p, sizeof(T));
+  memcpy(p, q, sizeof(T));
+  memcpy(q, &tmp, sizeof(T));
+}
+
+// Swaps two blocks of memory of size kSize:
+//  template <int kSize> void memswap(char* p, char* q);
+template <int kSize>
+inline typename std::enable_if<(kSize == 0), void>::type memswap(char*, char*) {
+}
+
+#define PROTO_MEMSWAP_DEF_SIZE(reg_type, max_size)                           \
+  template <int kSize>                                                       \
+  typename std::enable_if<(kSize >= sizeof(reg_type) && kSize < (max_size)), \
+                          void>::type                                        \
+  memswap(char* p, char* q) {                                                \
+    SwapBlock<reg_type>(p, q);                                               \
+    memswap<kSize - sizeof(reg_type)>(p + sizeof(reg_type),                  \
+                                      q + sizeof(reg_type));                 \
+  }
+
+PROTO_MEMSWAP_DEF_SIZE(uint8_t, 2)
+PROTO_MEMSWAP_DEF_SIZE(uint16_t, 4)
+PROTO_MEMSWAP_DEF_SIZE(uint32_t, 8)
+
+#ifdef __SIZEOF_INT128__
+PROTO_MEMSWAP_DEF_SIZE(uint64_t, 16)
+PROTO_MEMSWAP_DEF_SIZE(__uint128_t, (1u << 31))
+#else
+PROTO_MEMSWAP_DEF_SIZE(uint64_t, (1u << 31))
+#endif
+
+#undef PROTO_MEMSWAP_DEF_SIZE
+
+template <typename Element>
+class RepeatedIterator;
+
+}  // namespace internal
+
+// RepeatedField is used to represent repeated fields of a primitive type (in
+// other words, everything except strings and nested Messages).  Most users will
+// not ever use a RepeatedField directly; they will use the get-by-index,
+// set-by-index, and add accessors that are generated for all repeated fields.
+template <typename Element>
+class RepeatedField final {
+  static_assert(
+      alignof(Arena) >= alignof(Element),
+      "We only support types that have an alignment smaller than Arena");
+
+ public:
+  constexpr RepeatedField();
+  explicit RepeatedField(Arena* arena);
+
+  RepeatedField(const RepeatedField& other);
+
+  template <typename Iter,
+            typename = typename std::enable_if<std::is_constructible<
+                Element, decltype(*std::declval<Iter>())>::value>::type>
+  RepeatedField(Iter begin, Iter end);
+
+  ~RepeatedField();
+
+  RepeatedField& operator=(const RepeatedField& other);
+
+  RepeatedField(RepeatedField&& other) noexcept;
+  RepeatedField& operator=(RepeatedField&& other) noexcept;
+
+  bool empty() const;
+  int size() const;
+
+  const Element& Get(int index) const;
+  Element* Mutable(int index);
+
+  const Element& operator[](int index) const { return Get(index); }
+  Element& operator[](int index) { return *Mutable(index); }
+
+  const Element& at(int index) const;
+  Element& at(int index);
+
+  void Set(int index, const Element& value);
+  void Add(const Element& value);
+  // Appends a new element and returns a pointer to it.
+  // The new element is uninitialized if |Element| is a POD type.
+  Element* Add();
+  // Appends elements in the range [begin, end) after reserving
+  // the appropriate number of elements.
+  template <typename Iter>
+  void Add(Iter begin, Iter end);
+
+  // Removes the last element in the array.
+  void RemoveLast();
+
+  // Extracts elements with indices in "[start .. start+num-1]".
+  // Copies them into "elements[0 .. num-1]" if "elements" is not nullptr.
+  // Caution: also moves elements with indices [start+num ..].
+  // Calling this routine inside a loop can cause quadratic behavior.
+  void ExtractSubrange(int start, int num, Element* elements);
+
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear();
+  void MergeFrom(const RepeatedField& other);
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void CopyFrom(const RepeatedField& other);
+
+  // Replaces the contents with RepeatedField(begin, end).
+  template <typename Iter>
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end);
+
+  // Reserves space to expand the field to at least the given size.  If the
+  // array is grown, it will always be at least doubled in size.
+  void Reserve(int new_size);
+
+  // Resizes the RepeatedField to a new, smaller size.  This is O(1).
+  void Truncate(int new_size);
+
+  void AddAlreadyReserved(const Element& value);
+  // Appends a new element and return a pointer to it.
+  // The new element is uninitialized if |Element| is a POD type.
+  // Should be called only if Capacity() > Size().
+  Element* AddAlreadyReserved();
+  Element* AddNAlreadyReserved(int elements);
+  int Capacity() const;
+
+  // Like STL resize.  Uses value to fill appended elements.
+  // Like Truncate() if new_size <= size(), otherwise this is
+  // O(new_size - size()).
+  void Resize(int new_size, const Element& value);
+
+  // Gets the underlying array.  This pointer is possibly invalidated by
+  // any add or remove operation.
+  Element* mutable_data();
+  const Element* data() const;
+
+  // Swaps entire contents with "other". If they are separate arenas then,
+  // copies data between each other.
+  void Swap(RepeatedField* other);
+
+  // Swaps entire contents with "other". Should be called only if the caller can
+  // guarantee that both repeated fields are on the same arena or are on the
+  // heap. Swapping between different arenas is disallowed and caught by a
+  // GOOGLE_DCHECK (see API docs for details).
+  void UnsafeArenaSwap(RepeatedField* other);
+
+  // Swaps two elements.
+  void SwapElements(int index1, int index2);
+
+  // STL-like iterator support
+  typedef internal::RepeatedIterator<Element> iterator;
+  typedef internal::RepeatedIterator<const Element> const_iterator;
+  typedef Element value_type;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin();
+  const_iterator begin() const;
+  const_iterator cbegin() const;
+  iterator end();
+  const_iterator end() const;
+  const_iterator cend() const;
+
+  // Reverse iterator support
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef std::reverse_iterator<iterator> reverse_iterator;
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // Returns the number of bytes used by the repeated field, excluding
+  // sizeof(*this)
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+  // Removes the element referenced by position.
+  //
+  // Returns an iterator to the element immediately following the removed
+  // element.
+  //
+  // Invalidates all iterators at or after the removed element, including end().
+  iterator erase(const_iterator position);
+
+  // Removes the elements in the range [first, last).
+  //
+  // Returns an iterator to the element immediately following the removed range.
+  //
+  // Invalidates all iterators at or after the removed range, including end().
+  iterator erase(const_iterator first, const_iterator last);
+
+  // Gets the Arena on which this RepeatedField stores its elements.
+  inline Arena* GetArena() const {
+    return GetOwningArena();
+  }
+
+  // For internal use only.
+  //
+  // This is public due to it being called by generated code.
+  inline void InternalSwap(RepeatedField* other);
+
+ private:
+  template <typename T> friend class Arena::InternalHelper;
+
+  // Gets the Arena on which this RepeatedField stores its elements.
+  inline Arena* GetOwningArena() const {
+    return (total_size_ == 0) ? static_cast<Arena*>(arena_or_elements_)
+                              : rep()->arena;
+  }
+
+  static constexpr int kInitialSize = 0;
+  // A note on the representation here (see also comment below for
+  // RepeatedPtrFieldBase's struct Rep):
+  //
+  // We maintain the same sizeof(RepeatedField) as before we added arena support
+  // so that we do not degrade performance by bloating memory usage. Directly
+  // adding an arena_ element to RepeatedField is quite costly. By using
+  // indirection in this way, we keep the same size when the RepeatedField is
+  // empty (common case), and add only an 8-byte header to the elements array
+  // when non-empty. We make sure to place the size fields directly in the
+  // RepeatedField class to avoid costly cache misses due to the indirection.
+  int current_size_;
+  int total_size_;
+  // Pad the Rep after arena allow for power-of-two byte sizes when
+  // sizeof(Element) > sizeof(Arena*). eg for 16-byte objects.
+  static PROTOBUF_CONSTEXPR const size_t kRepHeaderSize =
+      sizeof(Arena*) < sizeof(Element) ? sizeof(Element) : sizeof(Arena*);
+  struct Rep {
+    Arena* arena;
+    Element* elements() {
+      return reinterpret_cast<Element*>(reinterpret_cast<char*>(this) +
+                                        kRepHeaderSize);
+    }
+  };
+
+  // If total_size_ == 0 this points to an Arena otherwise it points to the
+  // elements member of a Rep struct. Using this invariant allows the storage of
+  // the arena pointer without an extra allocation in the constructor.
+  void* arena_or_elements_;
+
+  // Returns a pointer to elements array.
+  // pre-condition: the array must have been allocated.
+  Element* elements() const {
+    GOOGLE_DCHECK_GT(total_size_, 0);
+    // Because of above pre-condition this cast is safe.
+    return unsafe_elements();
+  }
+
+  // Returns a pointer to elements array if it exists; otherwise either null or
+  // an invalid pointer is returned. This only happens for empty repeated
+  // fields, where you can't dereference this pointer anyway (it's empty).
+  Element* unsafe_elements() const {
+    return static_cast<Element*>(arena_or_elements_);
+  }
+
+  // Returns a pointer to the Rep struct.
+  // pre-condition: the Rep must have been allocated, ie elements() is safe.
+  Rep* rep() const {
+    return reinterpret_cast<Rep*>(reinterpret_cast<char*>(elements()) -
+                                  kRepHeaderSize);
+  }
+
+  friend class Arena;
+  typedef void InternalArenaConstructable_;
+
+  // Moves the contents of |from| into |to|, possibly clobbering |from| in the
+  // process.  For primitive types this is just a memcpy(), but it could be
+  // specialized for non-primitive types to, say, swap each element instead.
+  void MoveArray(Element* to, Element* from, int size);
+
+  // Copies the elements of |from| into |to|.
+  void CopyArray(Element* to, const Element* from, int size);
+
+  // Internal helper to delete all elements and deallocate the storage.
+  void InternalDeallocate(Rep* rep, int size, bool in_destructor) {
+    if (rep != nullptr) {
+      Element* e = &rep->elements()[0];
+      if (!std::is_trivial<Element>::value) {
+        Element* limit = &rep->elements()[size];
+        for (; e < limit; e++) {
+          e->~Element();
+        }
+      }
+      const size_t bytes = size * sizeof(*e) + kRepHeaderSize;
+      if (rep->arena == nullptr) {
+        internal::SizedDelete(rep, bytes);
+      } else if (!in_destructor) {
+        // If we are in the destructor, we might be being destroyed as part of
+        // the arena teardown. We can't try and return blocks to the arena then.
+        rep->arena->ReturnArrayMemory(rep, bytes);
+      }
+    }
+  }
+
+  // This class is a performance wrapper around RepeatedField::Add(const T&)
+  // function. In general unless a RepeatedField is a local stack variable LLVM
+  // has a hard time optimizing Add. The machine code tends to be
+  // loop:
+  // mov %size, dword ptr [%repeated_field]       // load
+  // cmp %size, dword ptr [%repeated_field + 4]
+  // jae fallback
+  // mov %buffer, qword ptr [%repeated_field + 8]
+  // mov dword [%buffer + %size * 4], %value
+  // inc %size                                    // increment
+  // mov dword ptr [%repeated_field], %size       // store
+  // jmp loop
+  //
+  // This puts a load/store in each iteration of the important loop variable
+  // size. It's a pretty bad compile that happens even in simple cases, but
+  // largely the presence of the fallback path disturbs the compilers mem-to-reg
+  // analysis.
+  //
+  // This class takes ownership of a repeated field for the duration of its
+  // lifetime. The repeated field should not be accessed during this time, ie.
+  // only access through this class is allowed. This class should always be a
+  // function local stack variable. Intended use
+  //
+  // void AddSequence(const int* begin, const int* end, RepeatedField<int>* out)
+  // {
+  //   RepeatedFieldAdder<int> adder(out);  // Take ownership of out
+  //   for (auto it = begin; it != end; ++it) {
+  //     adder.Add(*it);
+  //   }
+  // }
+  //
+  // Typically, due to the fact that adder is a local stack variable, the
+  // compiler will be successful in mem-to-reg transformation and the machine
+  // code will be loop: cmp %size, %capacity jae fallback mov dword ptr [%buffer
+  // + %size * 4], %val inc %size jmp loop
+  //
+  // The first version executes at 7 cycles per iteration while the second
+  // version executes at only 1 or 2 cycles.
+  template <int = 0, bool = std::is_trivial<Element>::value>
+  class FastAdderImpl {
+   public:
+    explicit FastAdderImpl(RepeatedField* rf) : repeated_field_(rf) {
+      index_ = repeated_field_->current_size_;
+      capacity_ = repeated_field_->total_size_;
+      buffer_ = repeated_field_->unsafe_elements();
+    }
+    ~FastAdderImpl() { repeated_field_->current_size_ = index_; }
+
+    void Add(Element val) {
+      if (index_ == capacity_) {
+        repeated_field_->current_size_ = index_;
+        repeated_field_->Reserve(index_ + 1);
+        capacity_ = repeated_field_->total_size_;
+        buffer_ = repeated_field_->unsafe_elements();
+      }
+      buffer_[index_++] = val;
+    }
+
+   private:
+    RepeatedField* repeated_field_;
+    int index_;
+    int capacity_;
+    Element* buffer_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastAdderImpl);
+  };
+
+  // FastAdder is a wrapper for adding fields. The specialization above handles
+  // POD types more efficiently than RepeatedField.
+  template <int I>
+  class FastAdderImpl<I, false> {
+   public:
+    explicit FastAdderImpl(RepeatedField* rf) : repeated_field_(rf) {}
+    void Add(const Element& val) { repeated_field_->Add(val); }
+
+   private:
+    RepeatedField* repeated_field_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastAdderImpl);
+  };
+
+  using FastAdder = FastAdderImpl<>;
+
+  friend class TestRepeatedFieldHelper;
+  friend class ::google::protobuf::internal::ParseContext;
+};
+
+namespace internal {
+
+// This is a helper template to copy an array of elements efficiently when they
+// have a trivial copy constructor, and correctly otherwise. This really
+// shouldn't be necessary, but our compiler doesn't optimize std::copy very
+// effectively.
+template <typename Element,
+          bool HasTrivialCopy = std::is_trivial<Element>::value>
+struct ElementCopier {
+  void operator()(Element* to, const Element* from, int array_size);
+};
+
+}  // namespace internal
+
+// implementation ====================================================
+
+template <typename Element>
+constexpr RepeatedField<Element>::RepeatedField()
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(Arena* arena)
+    : current_size_(0), total_size_(0), arena_or_elements_(arena) {}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
+  if (other.current_size_ != 0) {
+    Reserve(other.size());
+    AddNAlreadyReserved(other.size());
+    CopyArray(Mutable(0), &other.Get(0), other.size());
+  }
+}
+
+template <typename Element>
+template <typename Iter, typename>
+RepeatedField<Element>::RepeatedField(Iter begin, Iter end)
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
+  Add(begin, end);
+}
+
+template <typename Element>
+RepeatedField<Element>::~RepeatedField() {
+#ifndef NDEBUG
+  // Try to trigger segfault / asan failure in non-opt builds if arena_
+  // lifetime has ended before the destructor.
+  auto arena = GetOwningArena();
+  if (arena) (void)arena->SpaceAllocated();
+#endif
+  if (total_size_ > 0) {
+    InternalDeallocate(rep(), total_size_, true);
+  }
+}
+
+template <typename Element>
+inline RepeatedField<Element>& RepeatedField<Element>::operator=(
+    const RepeatedField& other) {
+  if (this != &other) CopyFrom(other);
+  return *this;
+}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(RepeatedField&& other) noexcept
+    : RepeatedField() {
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+  CopyFrom(other);
+#else   // PROTOBUF_FORCE_COPY_IN_MOVE
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // other is on an arena. This field can't be on an arena because arena
+  // construction always uses the Arena* accepting constructor.
+  if (other.GetOwningArena()) {
+    CopyFrom(other);
+  } else {
+    InternalSwap(&other);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+}
+
+template <typename Element>
+inline RepeatedField<Element>& RepeatedField<Element>::operator=(
+    RepeatedField&& other) noexcept {
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // the two fields are on different arenas.
+  if (this != &other) {
+    if (GetOwningArena() != other.GetOwningArena()
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        || GetOwningArena() == nullptr
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      CopyFrom(other);
+    } else {
+      InternalSwap(&other);
+    }
+  }
+  return *this;
+}
+
+template <typename Element>
+inline bool RepeatedField<Element>::empty() const {
+  return current_size_ == 0;
+}
+
+template <typename Element>
+inline int RepeatedField<Element>::size() const {
+  return current_size_;
+}
+
+template <typename Element>
+inline int RepeatedField<Element>::Capacity() const {
+  return total_size_;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::AddAlreadyReserved(const Element& value) {
+  GOOGLE_DCHECK_LT(current_size_, total_size_);
+  elements()[current_size_++] = value;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::AddAlreadyReserved() {
+  GOOGLE_DCHECK_LT(current_size_, total_size_);
+  return &elements()[current_size_++];
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::AddNAlreadyReserved(int elements) {
+  GOOGLE_DCHECK_GE(total_size_ - current_size_, elements)
+      << total_size_ << ", " << current_size_;
+  // Warning: sometimes people call this when elements == 0 and
+  // total_size_ == 0. In this case the return pointer points to a zero size
+  // array (n == 0). Hence we can just use unsafe_elements(), because the user
+  // cannot dereference the pointer anyway.
+  Element* ret = unsafe_elements() + current_size_;
+  current_size_ += elements;
+  return ret;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Resize(int new_size, const Element& value) {
+  GOOGLE_DCHECK_GE(new_size, 0);
+  if (new_size > current_size_) {
+    Reserve(new_size);
+    std::fill(&elements()[current_size_], &elements()[new_size], value);
+  }
+  current_size_ = new_size;
+}
+
+template <typename Element>
+inline const Element& RepeatedField<Element>::Get(int index) const {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline const Element& RepeatedField<Element>::at(int index) const {
+  GOOGLE_CHECK_GE(index, 0);
+  GOOGLE_CHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline Element& RepeatedField<Element>::at(int index) {
+  GOOGLE_CHECK_GE(index, 0);
+  GOOGLE_CHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::Mutable(int index) {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return &elements()[index];
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Set(int index, const Element& value) {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  elements()[index] = value;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Add(const Element& value) {
+  uint32_t size = current_size_;
+  if (static_cast<int>(size) == total_size_) {
+    // value could reference an element of the array. Reserving new space will
+    // invalidate the reference. So we must make a copy first.
+    auto tmp = value;
+    Reserve(total_size_ + 1);
+    elements()[size] = std::move(tmp);
+  } else {
+    elements()[size] = value;
+  }
+  current_size_ = size + 1;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::Add() {
+  uint32_t size = current_size_;
+  if (static_cast<int>(size) == total_size_) Reserve(total_size_ + 1);
+  auto ptr = &elements()[size];
+  current_size_ = size + 1;
+  return ptr;
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedField<Element>::Add(Iter begin, Iter end) {
+  int reserve = internal::CalculateReserve(begin, end);
+  if (reserve != -1) {
+    if (reserve == 0) {
+      return;
+    }
+
+    Reserve(reserve + size());
+    // TODO(ckennelly):  The compiler loses track of the buffer freshly
+    // allocated by Reserve() by the time we call elements, so it cannot
+    // guarantee that elements does not alias [begin(), end()).
+    //
+    // If restrict is available, annotating the pointer obtained from elements()
+    // causes this to lower to memcpy instead of memmove.
+    std::copy(begin, end, elements() + size());
+    current_size_ = reserve + size();
+  } else {
+    FastAdder fast_adder(this);
+    for (; begin != end; ++begin) fast_adder.Add(*begin);
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::RemoveLast() {
+  GOOGLE_DCHECK_GT(current_size_, 0);
+  current_size_--;
+}
+
+template <typename Element>
+void RepeatedField<Element>::ExtractSubrange(int start, int num,
+                                             Element* elements) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, this->current_size_);
+
+  // Save the values of the removed elements if requested.
+  if (elements != nullptr) {
+    for (int i = 0; i < num; ++i) elements[i] = this->Get(i + start);
+  }
+
+  // Slide remaining elements down to fill the gap.
+  if (num > 0) {
+    for (int i = start + num; i < this->current_size_; ++i)
+      this->Set(i - num, this->Get(i));
+    this->Truncate(this->current_size_ - num);
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Clear() {
+  current_size_ = 0;
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::MergeFrom(const RepeatedField& other) {
+  GOOGLE_DCHECK_NE(&other, this);
+  if (other.current_size_ != 0) {
+    int existing_size = size();
+    Reserve(existing_size + other.size());
+    AddNAlreadyReserved(other.size());
+    CopyArray(Mutable(existing_size), &other.Get(0), other.size());
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::CopyFrom(const RepeatedField& other) {
+  if (&other == this) return;
+  Clear();
+  MergeFrom(other);
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedField<Element>::Assign(Iter begin, Iter end) {
+  Clear();
+  Add(begin, end);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+    const_iterator position) {
+  return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+    const_iterator first, const_iterator last) {
+  size_type first_offset = first - cbegin();
+  if (first != last) {
+    Truncate(std::copy(last, cend(), begin() + first_offset) - cbegin());
+  }
+  return begin() + first_offset;
+}
+
+template <typename Element>
+inline Element* RepeatedField<Element>::mutable_data() {
+  return unsafe_elements();
+}
+
+template <typename Element>
+inline const Element* RepeatedField<Element>::data() const {
+  return unsafe_elements();
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::InternalSwap(RepeatedField* other) {
+  GOOGLE_DCHECK(this != other);
+
+  // Swap all fields at once.
+  static_assert(std::is_standard_layout<RepeatedField<Element>>::value,
+                "offsetof() requires standard layout before c++17");
+  internal::memswap<offsetof(RepeatedField, arena_or_elements_) +
+                    sizeof(this->arena_or_elements_) -
+                    offsetof(RepeatedField, current_size_)>(
+      reinterpret_cast<char*>(this) + offsetof(RepeatedField, current_size_),
+      reinterpret_cast<char*>(other) + offsetof(RepeatedField, current_size_));
+}
+
+template <typename Element>
+void RepeatedField<Element>::Swap(RepeatedField* other) {
+  if (this == other) return;
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetOwningArena() != nullptr &&
+      GetOwningArena() == other->GetOwningArena()) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetOwningArena() == other->GetOwningArena()) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    InternalSwap(other);
+  } else {
+    RepeatedField<Element> temp(other->GetOwningArena());
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->UnsafeArenaSwap(&temp);
+  }
+}
+
+template <typename Element>
+void RepeatedField<Element>::UnsafeArenaSwap(RepeatedField* other) {
+  if (this == other) return;
+  GOOGLE_DCHECK_EQ(GetOwningArena(), other->GetOwningArena());
+  InternalSwap(other);
+}
+
+template <typename Element>
+void RepeatedField<Element>::SwapElements(int index1, int index2) {
+  using std::swap;  // enable ADL with fallback
+  swap(elements()[index1], elements()[index2]);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator
+RepeatedField<Element>::begin() {
+  return iterator(unsafe_elements());
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::begin() const {
+  return const_iterator(unsafe_elements());
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cbegin() const {
+  return const_iterator(unsafe_elements());
+}
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::end() {
+  return iterator(unsafe_elements() + current_size_);
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::end() const {
+  return const_iterator(unsafe_elements() + current_size_);
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cend() const {
+  return const_iterator(unsafe_elements() + current_size_);
+}
+
+template <typename Element>
+inline size_t RepeatedField<Element>::SpaceUsedExcludingSelfLong() const {
+  return total_size_ > 0 ? (total_size_ * sizeof(Element) + kRepHeaderSize) : 0;
+}
+
+namespace internal {
+// Returns the new size for a reserved field based on its 'total_size' and the
+// requested 'new_size'. The result is clamped to the closed interval:
+//   [internal::kMinRepeatedFieldAllocationSize,
+//    std::numeric_limits<int>::max()]
+// Requires:
+//     new_size > total_size &&
+//     (total_size == 0 ||
+//      total_size >= kRepeatedFieldLowerClampLimit)
+template <typename T, int kRepHeaderSize>
+inline int CalculateReserveSize(int total_size, int new_size) {
+  constexpr int lower_limit = RepeatedFieldLowerClampLimit<T, kRepHeaderSize>();
+  if (new_size < lower_limit) {
+    // Clamp to smallest allowed size.
+    return lower_limit;
+  }
+  constexpr int kMaxSizeBeforeClamp =
+      (std::numeric_limits<int>::max() - kRepHeaderSize) / 2;
+  if (PROTOBUF_PREDICT_FALSE(total_size > kMaxSizeBeforeClamp)) {
+    return std::numeric_limits<int>::max();
+  }
+  // We want to double the number of bytes, not the number of elements, to try
+  // to stay within power-of-two allocations.
+  // The allocation has kRepHeaderSize + sizeof(T) * capacity.
+  int doubled_size = 2 * total_size + kRepHeaderSize / sizeof(T);
+  return std::max(doubled_size, new_size);
+}
+}  // namespace internal
+
+// Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant
+// amount of code bloat.
+template <typename Element>
+void RepeatedField<Element>::Reserve(int new_size) {
+  if (total_size_ >= new_size) return;
+  Rep* old_rep = total_size_ > 0 ? rep() : nullptr;
+  Rep* new_rep;
+  Arena* arena = GetOwningArena();
+
+  new_size = internal::CalculateReserveSize<Element, kRepHeaderSize>(
+      total_size_, new_size);
+
+  GOOGLE_DCHECK_LE(
+      static_cast<size_t>(new_size),
+      (std::numeric_limits<size_t>::max() - kRepHeaderSize) / sizeof(Element))
+      << "Requested size is too large to fit into size_t.";
+  size_t bytes =
+      kRepHeaderSize + sizeof(Element) * static_cast<size_t>(new_size);
+  if (arena == nullptr) {
+    new_rep = static_cast<Rep*>(::operator new(bytes));
+  } else {
+    new_rep = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
+  }
+  new_rep->arena = arena;
+  int old_total_size = total_size_;
+  // Already known: new_size >= internal::kMinRepeatedFieldAllocationSize
+  // Maintain invariant:
+  //     total_size_ == 0 ||
+  //     total_size_ >= internal::kMinRepeatedFieldAllocationSize
+  total_size_ = new_size;
+  arena_or_elements_ = new_rep->elements();
+  // Invoke placement-new on newly allocated elements. We shouldn't have to do
+  // this, since Element is supposed to be POD, but a previous version of this
+  // code allocated storage with "new Element[size]" and some code uses
+  // RepeatedField with non-POD types, relying on constructor invocation. If
+  // Element has a trivial constructor (e.g., int32_t), gcc (tested with -O2)
+  // completely removes this loop because the loop body is empty, so this has no
+  // effect unless its side-effects are required for correctness.
+  // Note that we do this before MoveArray() below because Element's copy
+  // assignment implementation will want an initialized instance first.
+  Element* e = &elements()[0];
+  Element* limit = e + total_size_;
+  for (; e < limit; e++) {
+    new (e) Element;
+  }
+  if (current_size_ > 0) {
+    MoveArray(&elements()[0], old_rep->elements(), current_size_);
+  }
+
+  // Likewise, we need to invoke destructors on the old array.
+  InternalDeallocate(old_rep, old_total_size, false);
+
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::Truncate(int new_size) {
+  GOOGLE_DCHECK_LE(new_size, current_size_);
+  if (current_size_ > 0) {
+    current_size_ = new_size;
+  }
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::MoveArray(Element* to, Element* from,
+                                              int array_size) {
+  CopyArray(to, from, array_size);
+}
+
+template <typename Element>
+inline void RepeatedField<Element>::CopyArray(Element* to, const Element* from,
+                                              int array_size) {
+  internal::ElementCopier<Element>()(to, from, array_size);
+}
+
+namespace internal {
+
+template <typename Element, bool HasTrivialCopy>
+void ElementCopier<Element, HasTrivialCopy>::operator()(Element* to,
+                                                        const Element* from,
+                                                        int array_size) {
+  std::copy(from, from + array_size, to);
+}
+
+template <typename Element>
+struct ElementCopier<Element, true> {
+  void operator()(Element* to, const Element* from, int array_size) {
+    memcpy(to, from, static_cast<size_t>(array_size) * sizeof(Element));
+  }
+};
+
+}  // namespace internal
+
+
+// -------------------------------------------------------------------
+
+// Iterators and helper functions that follow the spirit of the STL
+// std::back_insert_iterator and std::back_inserter but are tailor-made
+// for RepeatedField and RepeatedPtrField. Typical usage would be:
+//
+//   std::copy(some_sequence.begin(), some_sequence.end(),
+//             RepeatedFieldBackInserter(proto.mutable_sequence()));
+//
+// Ported by johannes from util/gtl/proto-array-iterators.h
+
+namespace internal {
+
+// STL-like iterator implementation for RepeatedField.  You should not
+// refer to this class directly; use RepeatedField<T>::iterator instead.
+//
+// Note: All of the iterator operators *must* be inlined to avoid performance
+// regressions.  This is caused by the extern template declarations below (which
+// are required because of the RepeatedField extern template declarations).  If
+// any of these functions aren't explicitly inlined (e.g. defined in the class),
+// the compiler isn't allowed to inline them.
+template <typename Element>
+class RepeatedIterator {
+ public:
+  using iterator_category = std::random_access_iterator_tag;
+  // Note: remove_const is necessary for std::partial_sum, which uses value_type
+  // to determine the summation variable type.
+  using value_type = typename std::remove_const<Element>::type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = Element*;
+  using reference = Element&;
+
+  constexpr RepeatedIterator() noexcept : it_(nullptr) {}
+
+  // Allows "upcasting" from RepeatedIterator<T**> to
+  // RepeatedIterator<const T*const*>.
+  template <typename OtherElement,
+            typename std::enable_if<std::is_convertible<
+                OtherElement*, pointer>::value>::type* = nullptr>
+  constexpr RepeatedIterator(
+      const RepeatedIterator<OtherElement>& other) noexcept
+      : it_(other.it_) {}
+
+  // dereferenceable
+  constexpr reference operator*() const noexcept { return *it_; }
+  constexpr pointer operator->() const noexcept { return it_; }
+
+ private:
+  // Helper alias to hide the internal type.
+  using iterator = RepeatedIterator<Element>;
+
+ public:
+  // {inc,dec}rementable
+  iterator& operator++() noexcept {
+    ++it_;
+    return *this;
+  }
+  iterator operator++(int) noexcept { return iterator(it_++); }
+  iterator& operator--() noexcept {
+    --it_;
+    return *this;
+  }
+  iterator operator--(int) noexcept { return iterator(it_--); }
+
+  // equality_comparable
+  friend constexpr bool operator==(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ == y.it_;
+  }
+  friend constexpr bool operator!=(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ != y.it_;
+  }
+
+  // less_than_comparable
+  friend constexpr bool operator<(const iterator& x,
+                                  const iterator& y) noexcept {
+    return x.it_ < y.it_;
+  }
+  friend constexpr bool operator<=(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ <= y.it_;
+  }
+  friend constexpr bool operator>(const iterator& x,
+                                  const iterator& y) noexcept {
+    return x.it_ > y.it_;
+  }
+  friend constexpr bool operator>=(const iterator& x,
+                                   const iterator& y) noexcept {
+    return x.it_ >= y.it_;
+  }
+
+  // addable, subtractable
+  iterator& operator+=(difference_type d) noexcept {
+    it_ += d;
+    return *this;
+  }
+  constexpr iterator operator+(difference_type d) const noexcept {
+    return iterator(it_ + d);
+  }
+  friend constexpr iterator operator+(const difference_type d,
+                                      iterator it) noexcept {
+    return it + d;
+  }
+
+  iterator& operator-=(difference_type d) noexcept {
+    it_ -= d;
+    return *this;
+  }
+  iterator constexpr operator-(difference_type d) const noexcept {
+    return iterator(it_ - d);
+  }
+
+  // indexable
+  constexpr reference operator[](difference_type d) const noexcept {
+    return it_[d];
+  }
+
+  // random access iterator
+  friend constexpr difference_type operator-(iterator it1,
+                                             iterator it2) noexcept {
+    return it1.it_ - it2.it_;
+  }
+
+ private:
+  template <typename OtherElement>
+  friend class RepeatedIterator;
+
+  // Allow construction from RepeatedField.
+  friend class RepeatedField<value_type>;
+  explicit RepeatedIterator(Element* it) noexcept : it_(it) {}
+
+  // The internal iterator.
+  Element* it_;
+};
+
+// A back inserter for RepeatedField objects.
+template <typename T>
+class RepeatedFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  explicit RepeatedFieldBackInsertIterator(
+      RepeatedField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  RepeatedFieldBackInsertIterator<T>& operator=(const T& value) {
+    field_->Add(value);
+    return *this;
+  }
+  RepeatedFieldBackInsertIterator<T>& operator*() { return *this; }
+  RepeatedFieldBackInsertIterator<T>& operator++() { return *this; }
+  RepeatedFieldBackInsertIterator<T>& operator++(int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedField<T>* field_;
+};
+
+}  // namespace internal
+
+// Provides a back insert iterator for RepeatedField instances,
+// similar to std::back_inserter().
+template <typename T>
+internal::RepeatedFieldBackInsertIterator<T> RepeatedFieldBackInserter(
+    RepeatedField<T>* const mutable_field) {
+  return internal::RepeatedFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Extern declarations of common instantiations to reduce library bloat.
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<bool>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<int64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<uint64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<float>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField<double>;
+
+namespace internal {
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedIterator<bool>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<int32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<uint32_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<int64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedIterator<uint64_t>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedIterator<float>;
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedIterator<double>;
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REPEATED_FIELD_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/repeated_ptr_field.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/repeated_ptr_field.h
new file mode 100644
index 0000000..401230b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/repeated_ptr_field.h
@@ -0,0 +1,1970 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// RepeatedField and RepeatedPtrField are used by generated protocol message
+// classes to manipulate repeated fields.  These classes are very similar to
+// STL's vector, but include a number of optimizations found to be useful
+// specifically in the case of Protocol Buffers.  RepeatedPtrField is
+// particularly different from STL vector as it manages ownership of the
+// pointers that it contains.
+//
+// This header covers RepeatedPtrField.
+
+// IWYU pragma: private, include "net/proto2/public/repeated_field.h"
+
+#ifndef GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
+#define GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
+
+#include <utility>
+
+#ifdef _MSC_VER
+// This is required for min/max on VS2013 only.
+#include <algorithm>
+#endif
+
+#include <iterator>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class Reflection;
+
+template <typename T>
+struct WeakRepeatedPtrField;
+
+namespace internal {
+
+class MergePartialFromCodedStreamHelper;
+class SwapFieldHelper;
+
+
+}  // namespace internal
+
+namespace internal {
+template <typename It>
+class RepeatedPtrIterator;
+template <typename It, typename VoidPtr>
+class RepeatedPtrOverPtrsIterator;
+}  // namespace internal
+
+namespace internal {
+
+// type-traits helper for RepeatedPtrFieldBase: we only want to invoke
+// arena-related "copy if on different arena" behavior if the necessary methods
+// exist on the contained type. In particular, we rely on MergeFrom() existing
+// as a general proxy for the fact that a copy will work, and we also provide a
+// specific override for std::string*.
+template <typename T>
+struct TypeImplementsMergeBehaviorProbeForMergeFrom {
+  typedef char HasMerge;
+  typedef long HasNoMerge;
+
+  // We accept either of:
+  // - void MergeFrom(const T& other)
+  // - bool MergeFrom(const T& other)
+  //
+  // We mangle these names a bit to avoid compatibility issues in 'unclean'
+  // include environments that may have, e.g., "#define test ..." (yes, this
+  // exists).
+  template <typename U, typename RetType, RetType (U::*)(const U& arg)>
+  struct CheckType;
+  template <typename U>
+  static HasMerge Check(CheckType<U, void, &U::MergeFrom>*);
+  template <typename U>
+  static HasMerge Check(CheckType<U, bool, &U::MergeFrom>*);
+  template <typename U>
+  static HasNoMerge Check(...);
+
+  // Resolves to either std::true_type or std::false_type.
+  typedef std::integral_constant<bool,
+                                 (sizeof(Check<T>(0)) == sizeof(HasMerge))>
+      type;
+};
+
+template <typename T, typename = void>
+struct TypeImplementsMergeBehavior
+    : TypeImplementsMergeBehaviorProbeForMergeFrom<T> {};
+
+
+template <>
+struct TypeImplementsMergeBehavior<std::string> {
+  typedef std::true_type type;
+};
+
+template <typename T>
+struct IsMovable
+    : std::integral_constant<bool, std::is_move_constructible<T>::value &&
+                                       std::is_move_assignable<T>::value> {};
+
+// This is the common base class for RepeatedPtrFields.  It deals only in void*
+// pointers.  Users should not use this interface directly.
+//
+// The methods of this interface correspond to the methods of RepeatedPtrField,
+// but may have a template argument called TypeHandler.  Its signature is:
+//   class TypeHandler {
+//    public:
+//     typedef MyType Type;
+//     static Type* New();
+//     static Type* NewFromPrototype(const Type* prototype,
+//                                       Arena* arena);
+//     static void Delete(Type*);
+//     static void Clear(Type*);
+//     static void Merge(const Type& from, Type* to);
+//
+//     // Only needs to be implemented if SpaceUsedExcludingSelf() is called.
+//     static int SpaceUsedLong(const Type&);
+//   };
+class PROTOBUF_EXPORT RepeatedPtrFieldBase {
+ protected:
+  constexpr RepeatedPtrFieldBase()
+      : arena_(nullptr), current_size_(0), total_size_(0), rep_(nullptr) {}
+  explicit RepeatedPtrFieldBase(Arena* arena)
+      : arena_(arena), current_size_(0), total_size_(0), rep_(nullptr) {}
+
+  RepeatedPtrFieldBase(const RepeatedPtrFieldBase&) = delete;
+  RepeatedPtrFieldBase& operator=(const RepeatedPtrFieldBase&) = delete;
+
+  ~RepeatedPtrFieldBase() {
+#ifndef NDEBUG
+    // Try to trigger segfault / asan failure in non-opt builds. If arena_
+    // lifetime has ended before the destructor.
+    if (arena_) (void)arena_->SpaceAllocated();
+#endif
+  }
+
+  bool empty() const { return current_size_ == 0; }
+  int size() const { return current_size_; }
+  int Capacity() const { return total_size_; }
+
+  template <typename TypeHandler>
+  const typename TypeHandler::Type& at(int index) const {
+    GOOGLE_CHECK_GE(index, 0);
+    GOOGLE_CHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type& at(int index) {
+    GOOGLE_CHECK_GE(index, 0);
+    GOOGLE_CHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* Mutable(int index) {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    return cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* Add(
+      const typename TypeHandler::Type* prototype = nullptr) {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      return cast<TypeHandler>(rep_->elements[current_size_++]);
+    }
+    typename TypeHandler::Type* result =
+        TypeHandler::NewFromPrototype(prototype, arena_);
+    return reinterpret_cast<typename TypeHandler::Type*>(
+        AddOutOfLineHelper(result));
+  }
+
+  template <
+      typename TypeHandler,
+      typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr>
+  inline void Add(typename TypeHandler::Type&& value) {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      *cast<TypeHandler>(rep_->elements[current_size_++]) = std::move(value);
+      return;
+    }
+    if (!rep_ || rep_->allocated_size == total_size_) {
+      Reserve(total_size_ + 1);
+    }
+    ++rep_->allocated_size;
+    typename TypeHandler::Type* result =
+        TypeHandler::New(arena_, std::move(value));
+    rep_->elements[current_size_++] = result;
+  }
+
+  template <typename TypeHandler>
+  void Delete(int index) {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    TypeHandler::Delete(cast<TypeHandler>(rep_->elements[index]), arena_);
+  }
+
+  // Must be called from destructor.
+  template <typename TypeHandler>
+  void Destroy() {
+    if (rep_ != nullptr && arena_ == nullptr) {
+      int n = rep_->allocated_size;
+      void* const* elements = rep_->elements;
+      for (int i = 0; i < n; i++) {
+        TypeHandler::Delete(cast<TypeHandler>(elements[i]), nullptr);
+      }
+      const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
+      internal::SizedDelete(rep_, size);
+    }
+    rep_ = nullptr;
+  }
+
+  bool NeedsDestroy() const { return rep_ != nullptr && arena_ == nullptr; }
+  void DestroyProtos();  // implemented in the cc file
+
+ public:
+  // The next few methods are public so that they can be called from generated
+  // code when implicit weak fields are used, but they should never be called by
+  // application code.
+
+  template <typename TypeHandler>
+  const typename TypeHandler::Type& Get(int index) const {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
+  // Creates and adds an element using the given prototype, without introducing
+  // a link-time dependency on the concrete message type. This method is used to
+  // implement implicit weak fields. The prototype may be nullptr, in which case
+  // an ImplicitWeakMessage will be used as a placeholder.
+  MessageLite* AddWeak(const MessageLite* prototype);
+
+  template <typename TypeHandler>
+  void Clear() {
+    const int n = current_size_;
+    GOOGLE_DCHECK_GE(n, 0);
+    if (n > 0) {
+      void* const* elements = rep_->elements;
+      int i = 0;
+      do {
+        TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
+      } while (i < n);
+      current_size_ = 0;
+    }
+  }
+
+  template <typename TypeHandler>
+  void MergeFrom(const RepeatedPtrFieldBase& other) {
+    // To avoid unnecessary code duplication and reduce binary size, we use a
+    // layered approach to implementing MergeFrom(). The toplevel method is
+    // templated, so we get a small thunk per concrete message type in the
+    // binary. This calls a shared implementation with most of the logic,
+    // passing a function pointer to another type-specific piece of code that
+    // calls the object-allocate and merge handlers.
+    GOOGLE_DCHECK_NE(&other, this);
+    if (other.current_size_ == 0) return;
+    MergeFromInternal(other,
+                      &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
+  }
+
+  inline void InternalSwap(RepeatedPtrFieldBase* rhs) {
+    GOOGLE_DCHECK(this != rhs);
+
+    // Swap all fields at once.
+    auto temp = std::make_tuple(rhs->arena_, rhs->current_size_,
+                                rhs->total_size_, rhs->rep_);
+    std::tie(rhs->arena_, rhs->current_size_, rhs->total_size_, rhs->rep_) =
+        std::make_tuple(arena_, current_size_, total_size_, rep_);
+    std::tie(arena_, current_size_, total_size_, rep_) = temp;
+  }
+
+ protected:
+  template <typename TypeHandler>
+  void RemoveLast() {
+    GOOGLE_DCHECK_GT(current_size_, 0);
+    TypeHandler::Clear(cast<TypeHandler>(rep_->elements[--current_size_]));
+  }
+
+  template <typename TypeHandler>
+  void CopyFrom(const RepeatedPtrFieldBase& other) {
+    if (&other == this) return;
+    RepeatedPtrFieldBase::Clear<TypeHandler>();
+    RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
+  }
+
+  void CloseGap(int start, int num);  // implemented in the cc file
+
+  void Reserve(int new_size);  // implemented in the cc file
+
+  template <typename TypeHandler>
+  static inline typename TypeHandler::Type* copy(
+      typename TypeHandler::Type* value) {
+    auto* new_value = TypeHandler::NewFromPrototype(value, nullptr);
+    TypeHandler::Merge(*value, new_value);
+    return new_value;
+  }
+
+  // Used for constructing iterators.
+  void* const* raw_data() const { return rep_ ? rep_->elements : nullptr; }
+  void** raw_mutable_data() const {
+    return rep_ ? const_cast<void**>(rep_->elements) : nullptr;
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type** mutable_data() {
+    // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
+    //   method entirely.
+    return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
+  }
+
+  template <typename TypeHandler>
+  const typename TypeHandler::Type* const* data() const {
+    // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
+    //   method entirely.
+    return reinterpret_cast<const typename TypeHandler::Type* const*>(
+        raw_data());
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NDEBUG_INLINE void Swap(RepeatedPtrFieldBase* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena())
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena())
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    {
+      InternalSwap(other);
+    } else {
+      SwapFallback<TypeHandler>(other);
+    }
+  }
+
+  void SwapElements(int index1, int index2) {
+    using std::swap;  // enable ADL with fallback
+    swap(rep_->elements[index1], rep_->elements[index2]);
+  }
+
+  template <typename TypeHandler>
+  size_t SpaceUsedExcludingSelfLong() const {
+    size_t allocated_bytes = static_cast<size_t>(total_size_) * sizeof(void*);
+    if (rep_ != nullptr) {
+      for (int i = 0; i < rep_->allocated_size; ++i) {
+        allocated_bytes +=
+            TypeHandler::SpaceUsedLong(*cast<TypeHandler>(rep_->elements[i]));
+      }
+      allocated_bytes += kRepHeaderSize;
+    }
+    return allocated_bytes;
+  }
+
+  // Advanced memory management --------------------------------------
+
+  // Like Add(), but if there are no cleared objects to use, returns nullptr.
+  template <typename TypeHandler>
+  typename TypeHandler::Type* AddFromCleared() {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      return cast<TypeHandler>(rep_->elements[current_size_++]);
+    } else {
+      return nullptr;
+    }
+  }
+
+  template <typename TypeHandler>
+  void AddAllocated(typename TypeHandler::Type* value) {
+    typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+    AddAllocatedInternal<TypeHandler>(value, t);
+  }
+
+  template <typename TypeHandler>
+  void UnsafeArenaAddAllocated(typename TypeHandler::Type* value) {
+    // Make room for the new pointer.
+    if (!rep_ || current_size_ == total_size_) {
+      // The array is completely full with no cleared objects, so grow it.
+      Reserve(total_size_ + 1);
+      ++rep_->allocated_size;
+    } else if (rep_->allocated_size == total_size_) {
+      // There is no more space in the pointer array because it contains some
+      // cleared objects awaiting reuse.  We don't want to grow the array in
+      // this case because otherwise a loop calling AddAllocated() followed by
+      // Clear() would leak memory.
+      TypeHandler::Delete(cast<TypeHandler>(rep_->elements[current_size_]),
+                          arena_);
+    } else if (current_size_ < rep_->allocated_size) {
+      // We have some cleared objects.  We don't care about their order, so we
+      // can just move the first one to the end to make space.
+      rep_->elements[rep_->allocated_size] = rep_->elements[current_size_];
+      ++rep_->allocated_size;
+    } else {
+      // There are no cleared objects.
+      ++rep_->allocated_size;
+    }
+
+    rep_->elements[current_size_++] = value;
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseLast() {
+    typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+    return ReleaseLastInternal<TypeHandler>(t);
+  }
+
+  // Releases and returns the last element, but does not do out-of-arena copy.
+  // Instead, just returns the raw pointer to the contained element in the
+  // arena.
+  template <typename TypeHandler>
+  typename TypeHandler::Type* UnsafeArenaReleaseLast() {
+    GOOGLE_DCHECK_GT(current_size_, 0);
+    typename TypeHandler::Type* result =
+        cast<TypeHandler>(rep_->elements[--current_size_]);
+    --rep_->allocated_size;
+    if (current_size_ < rep_->allocated_size) {
+      // There are cleared elements on the end; replace the removed element
+      // with the last allocated element.
+      rep_->elements[current_size_] = rep_->elements[rep_->allocated_size];
+    }
+    return result;
+  }
+
+  int ClearedCount() const {
+    return rep_ ? (rep_->allocated_size - current_size_) : 0;
+  }
+
+  template <typename TypeHandler>
+  void AddCleared(typename TypeHandler::Type* value) {
+    GOOGLE_DCHECK(GetOwningArena() == nullptr) << "AddCleared() can only be used on a "
+                                           "RepeatedPtrField not on an arena.";
+    GOOGLE_DCHECK(TypeHandler::GetOwningArena(value) == nullptr)
+        << "AddCleared() can only accept values not on an arena.";
+    if (!rep_ || rep_->allocated_size == total_size_) {
+      Reserve(total_size_ + 1);
+    }
+    rep_->elements[rep_->allocated_size++] = value;
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared() {
+    GOOGLE_DCHECK(GetOwningArena() == nullptr)
+        << "ReleaseCleared() can only be used on a RepeatedPtrField not on "
+        << "an arena.";
+    GOOGLE_DCHECK(GetOwningArena() == nullptr);
+    GOOGLE_DCHECK(rep_ != nullptr);
+    GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_);
+    return cast<TypeHandler>(rep_->elements[--rep_->allocated_size]);
+  }
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type) {
+    // AddAllocated version that implements arena-safe copying behavior.
+    Arena* element_arena =
+        reinterpret_cast<Arena*>(TypeHandler::GetOwningArena(value));
+    Arena* arena = GetOwningArena();
+    if (arena == element_arena && rep_ && rep_->allocated_size < total_size_) {
+      // Fast path: underlying arena representation (tagged pointer) is equal to
+      // our arena pointer, and we can add to array without resizing it (at
+      // least one slot that is not allocated).
+      void** elems = rep_->elements;
+      if (current_size_ < rep_->allocated_size) {
+        // Make space at [current] by moving first allocated element to end of
+        // allocated list.
+        elems[rep_->allocated_size] = elems[current_size_];
+      }
+      elems[current_size_] = value;
+      current_size_ = current_size_ + 1;
+      rep_->allocated_size = rep_->allocated_size + 1;
+    } else {
+      AddAllocatedSlowWithCopy<TypeHandler>(value, element_arena, arena);
+    }
+  }
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(
+      // AddAllocated version that does not implement arena-safe copying
+      // behavior.
+      typename TypeHandler::Type* value, std::false_type) {
+    if (rep_ && rep_->allocated_size < total_size_) {
+      // Fast path: underlying arena representation (tagged pointer) is equal to
+      // our arena pointer, and we can add to array without resizing it (at
+      // least one slot that is not allocated).
+      void** elems = rep_->elements;
+      if (current_size_ < rep_->allocated_size) {
+        // Make space at [current] by moving first allocated element to end of
+        // allocated list.
+        elems[rep_->allocated_size] = elems[current_size_];
+      }
+      elems[current_size_] = value;
+      current_size_ = current_size_ + 1;
+      ++rep_->allocated_size;
+    } else {
+      UnsafeArenaAddAllocated<TypeHandler>(value);
+    }
+  }
+
+  // Slowpath handles all cases, copying if necessary.
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy(
+      // Pass value_arena and my_arena to avoid duplicate virtual call (value)
+      // or load (mine).
+      typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
+    // Ensure that either the value is in the same arena, or if not, we do the
+    // appropriate thing: Own() it (if it's on heap and we're in an arena) or
+    // copy it to our arena/heap (otherwise).
+    if (my_arena != nullptr && value_arena == nullptr) {
+      my_arena->Own(value);
+    } else if (my_arena != value_arena) {
+      typename TypeHandler::Type* new_value =
+          TypeHandler::NewFromPrototype(value, my_arena);
+      TypeHandler::Merge(*value, new_value);
+      TypeHandler::Delete(value, value_arena);
+      value = new_value;
+    }
+
+    UnsafeArenaAddAllocated<TypeHandler>(value);
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* ReleaseLastInternal(std::true_type) {
+    // ReleaseLast() for types that implement merge/copy behavior.
+    // First, release an element.
+    typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
+    // Now perform a copy if we're on an arena.
+    Arena* arena = GetOwningArena();
+
+    typename TypeHandler::Type* new_result;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+    new_result = copy<TypeHandler>(result);
+    if (arena == nullptr) delete result;
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+    new_result = (arena == nullptr) ? result : copy<TypeHandler>(result);
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+    return new_result;
+  }
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* ReleaseLastInternal(std::false_type) {
+    // ReleaseLast() for types that *do not* implement merge/copy behavior --
+    // this is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if
+    // we're on an arena, since the user really should implement the copy
+    // operation in this case.
+    GOOGLE_DCHECK(GetOwningArena() == nullptr)
+        << "ReleaseLast() called on a RepeatedPtrField that is on an arena, "
+        << "with a type that does not implement MergeFrom. This is unsafe; "
+        << "please implement MergeFrom for your type.";
+    return UnsafeArenaReleaseLast<TypeHandler>();
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    GOOGLE_DCHECK(GetOwningArena() == nullptr ||
+           other->GetOwningArena() != GetOwningArena());
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    GOOGLE_DCHECK(other->GetOwningArena() != GetOwningArena());
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+
+    // Copy semantics in this case. We try to improve efficiency by placing the
+    // temporary on |other|'s arena so that messages are copied twice rather
+    // than three times.
+    RepeatedPtrFieldBase temp(other->GetOwningArena());
+    temp.MergeFrom<TypeHandler>(*this);
+    this->Clear<TypeHandler>();
+    this->MergeFrom<TypeHandler>(*other);
+    other->InternalSwap(&temp);
+    temp.Destroy<TypeHandler>();  // Frees rep_ if `other` had no arena.
+  }
+
+  inline Arena* GetArena() const { return arena_; }
+
+ protected:
+  inline Arena* GetOwningArena() const { return arena_; }
+
+ private:
+  template <typename T> friend class Arena::InternalHelper;
+
+  static constexpr int kInitialSize = 0;
+  // A few notes on internal representation:
+  //
+  // We use an indirected approach, with struct Rep, to keep
+  // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support
+  // was added; namely, 3 8-byte machine words on x86-64. An instance of Rep is
+  // allocated only when the repeated field is non-empty, and it is a
+  // dynamically-sized struct (the header is directly followed by elements[]).
+  // We place arena_ and current_size_ directly in the object to avoid cache
+  // misses due to the indirection, because these fields are checked frequently.
+  // Placing all fields directly in the RepeatedPtrFieldBase instance would cost
+  // significant performance for memory-sensitive workloads.
+  Arena* arena_;
+  int current_size_;
+  int total_size_;
+  struct Rep {
+    int allocated_size;
+    // Here we declare a huge array as a way of approximating C's "flexible
+    // array member" feature without relying on undefined behavior.
+    void* elements[(std::numeric_limits<int>::max() - 2 * sizeof(int)) /
+                   sizeof(void*)];
+  };
+  static constexpr size_t kRepHeaderSize = offsetof(Rep, elements);
+  Rep* rep_;
+
+  template <typename TypeHandler>
+  static inline typename TypeHandler::Type* cast(void* element) {
+    return reinterpret_cast<typename TypeHandler::Type*>(element);
+  }
+  template <typename TypeHandler>
+  static inline const typename TypeHandler::Type* cast(const void* element) {
+    return reinterpret_cast<const typename TypeHandler::Type*>(element);
+  }
+
+  // Non-templated inner function to avoid code duplication. Takes a function
+  // pointer to the type-specific (templated) inner allocate/merge loop.
+  void MergeFromInternal(const RepeatedPtrFieldBase& other,
+                         void (RepeatedPtrFieldBase::*inner_loop)(void**,
+                                                                  void**, int,
+                                                                  int)) {
+    // Note: wrapper has already guaranteed that other.rep_ != nullptr here.
+    int other_size = other.current_size_;
+    void** other_elements = other.rep_->elements;
+    void** new_elements = InternalExtend(other_size);
+    int allocated_elems = rep_->allocated_size - current_size_;
+    (this->*inner_loop)(new_elements, other_elements, other_size,
+                        allocated_elems);
+    current_size_ += other_size;
+    if (rep_->allocated_size < current_size_) {
+      rep_->allocated_size = current_size_;
+    }
+  }
+
+  // Merges other_elems to our_elems.
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void MergeFromInnerLoop(void** our_elems,
+                                            void** other_elems, int length,
+                                            int already_allocated) {
+    if (already_allocated < length) {
+      Arena* arena = GetOwningArena();
+      typename TypeHandler::Type* elem_prototype =
+          reinterpret_cast<typename TypeHandler::Type*>(other_elems[0]);
+      for (int i = already_allocated; i < length; i++) {
+        // Allocate a new empty element that we'll merge into below
+        typename TypeHandler::Type* new_elem =
+            TypeHandler::NewFromPrototype(elem_prototype, arena);
+        our_elems[i] = new_elem;
+      }
+    }
+    // Main loop that does the actual merging
+    for (int i = 0; i < length; i++) {
+      // Already allocated: use existing element.
+      typename TypeHandler::Type* other_elem =
+          reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
+      typename TypeHandler::Type* new_elem =
+          reinterpret_cast<typename TypeHandler::Type*>(our_elems[i]);
+      TypeHandler::Merge(*other_elem, new_elem);
+    }
+  }
+
+  // Internal helper: extends array space if necessary to contain
+  // |extend_amount| more elements, and returns a pointer to the element
+  // immediately following the old list of elements.  This interface factors out
+  // common behavior from Reserve() and MergeFrom() to reduce code size.
+  // |extend_amount| must be > 0.
+  void** InternalExtend(int extend_amount);
+
+  // Internal helper for Add: adds "obj" as the next element in the
+  // array, including potentially resizing the array with Reserve if
+  // needed
+  void* AddOutOfLineHelper(void* obj);
+
+  // The reflection implementation needs to call protected methods directly,
+  // reinterpreting pointers as being to Message instead of a specific Message
+  // subclass.
+  friend class ::PROTOBUF_NAMESPACE_ID::Reflection;
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::SwapFieldHelper;
+
+  // ExtensionSet stores repeated message extensions as
+  // RepeatedPtrField<MessageLite>, but non-lite ExtensionSets need to implement
+  // SpaceUsedLong(), and thus need to call SpaceUsedExcludingSelfLong()
+  // reinterpreting MessageLite as Message.  ExtensionSet also needs to make use
+  // of AddFromCleared(), which is not part of the public interface.
+  friend class ExtensionSet;
+
+  // The MapFieldBase implementation needs to call protected methods directly,
+  // reinterpreting pointers as being to Message instead of a specific Message
+  // subclass.
+  friend class MapFieldBase;
+  friend class MapFieldBaseStub;
+
+  // The table-driven MergePartialFromCodedStream implementation needs to
+  // operate on RepeatedPtrField<MessageLite>.
+  friend class MergePartialFromCodedStreamHelper;
+  friend class AccessorHelper;
+  template <typename T>
+  friend struct google::protobuf::WeakRepeatedPtrField;
+  friend class internal::TcParser;  // TODO(jorg): Remove this friend.
+};
+
+template <typename GenericType>
+class GenericTypeHandler {
+ public:
+  typedef GenericType Type;
+  using Movable = IsMovable<GenericType>;
+
+  static inline GenericType* New(Arena* arena) {
+    return Arena::CreateMaybeMessage<Type>(arena);
+  }
+  static inline GenericType* New(Arena* arena, GenericType&& value) {
+    return Arena::Create<GenericType>(arena, std::move(value));
+  }
+  static inline GenericType* NewFromPrototype(const GenericType* /*prototype*/,
+                                              Arena* arena = nullptr) {
+    return New(arena);
+  }
+  static inline void Delete(GenericType* value, Arena* arena) {
+    if (arena == nullptr) {
+      delete value;
+    }
+  }
+  static inline Arena* GetOwningArena(GenericType* value) {
+    return Arena::GetOwningArena<Type>(value);
+  }
+
+  static inline void Clear(GenericType* value) { value->Clear(); }
+  static void Merge(const GenericType& from, GenericType* to);
+  static inline size_t SpaceUsedLong(const GenericType& value) {
+    return value.SpaceUsedLong();
+  }
+};
+
+// NewFromPrototypeHelper() is not defined inline here, as we will need to do a
+// virtual function dispatch anyways to go from Message* to call New/Merge. (The
+// additional helper is needed as a workaround for MSVC.)
+MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, Arena* arena);
+
+template <>
+inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
+    const MessageLite* prototype, Arena* arena) {
+  return NewFromPrototypeHelper(prototype, arena);
+}
+template <>
+inline Arena* GenericTypeHandler<MessageLite>::GetOwningArena(
+    MessageLite* value) {
+  return value->GetOwningArena();
+}
+
+template <typename GenericType>
+PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
+    const GenericType& from, GenericType* to) {
+  to->MergeFrom(from);
+}
+template <>
+void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
+                                            MessageLite* to);
+
+template <>
+inline void GenericTypeHandler<std::string>::Clear(std::string* value) {
+  value->clear();
+}
+template <>
+void GenericTypeHandler<std::string>::Merge(const std::string& from,
+                                            std::string* to);
+
+// Message specialization bodies defined in message.cc. This split is necessary
+// to allow proto2-lite (which includes this header) to be independent of
+// Message.
+template <>
+PROTOBUF_EXPORT Message* GenericTypeHandler<Message>::NewFromPrototype(
+    const Message* prototype, Arena* arena);
+template <>
+PROTOBUF_EXPORT Arena* GenericTypeHandler<Message>::GetOwningArena(
+    Message* value);
+
+class StringTypeHandler {
+ public:
+  typedef std::string Type;
+  using Movable = IsMovable<Type>;
+
+  static inline std::string* New(Arena* arena) {
+    return Arena::Create<std::string>(arena);
+  }
+  static inline std::string* New(Arena* arena, std::string&& value) {
+    return Arena::Create<std::string>(arena, std::move(value));
+  }
+  static inline std::string* NewFromPrototype(const std::string*,
+                                              Arena* arena) {
+    return New(arena);
+  }
+  static inline Arena* GetOwningArena(std::string*) { return nullptr; }
+  static inline void Delete(std::string* value, Arena* arena) {
+    if (arena == nullptr) {
+      delete value;
+    }
+  }
+  static inline void Clear(std::string* value) { value->clear(); }
+  static inline void Merge(const std::string& from, std::string* to) {
+    *to = from;
+  }
+  static size_t SpaceUsedLong(const std::string& value) {
+    return sizeof(value) + StringSpaceUsedExcludingSelfLong(value);
+  }
+};
+
+}  // namespace internal
+
+// RepeatedPtrField is like RepeatedField, but used for repeated strings or
+// Messages.
+template <typename Element>
+class RepeatedPtrField final : private internal::RepeatedPtrFieldBase {
+
+ public:
+  constexpr RepeatedPtrField();
+  explicit RepeatedPtrField(Arena* arena);
+
+  RepeatedPtrField(const RepeatedPtrField& other);
+
+  template <typename Iter,
+            typename = typename std::enable_if<std::is_constructible<
+                Element, decltype(*std::declval<Iter>())>::value>::type>
+  RepeatedPtrField(Iter begin, Iter end);
+
+  ~RepeatedPtrField();
+
+  RepeatedPtrField& operator=(const RepeatedPtrField& other);
+
+  RepeatedPtrField(RepeatedPtrField&& other) noexcept;
+  RepeatedPtrField& operator=(RepeatedPtrField&& other) noexcept;
+
+  bool empty() const;
+  int size() const;
+
+  const Element& Get(int index) const;
+  Element* Mutable(int index);
+
+  // Unlike std::vector, adding an element to a RepeatedPtrField doesn't always
+  // make a new element; it might re-use an element left over from when the
+  // field was Clear()'d or reize()'d smaller.  For this reason, Add() is the
+  // fastest API for adding a new element.
+  Element* Add();
+
+  // `Add(std::move(value));` is equivalent to `*Add() = std::move(value);`
+  // It will either move-construct to the end of this field, or swap value
+  // with the new-or-recycled element at the end of this field.  Note that
+  // this operation is very slow if this RepeatedPtrField is not on the
+  // same Arena, if any, as `value`.
+  void Add(Element&& value);
+
+  // Copying to the end of this RepeatedPtrField is slowest of all; it can't
+  // reliably copy-construct to the last element of this RepeatedPtrField, for
+  // example (unlike std::vector).
+  // We currently block this API.  The right way to add to the end is to call
+  // Add() and modify the element it points to.
+  // If you must add an existing value, call `*Add() = value;`
+  void Add(const Element& value) = delete;
+
+  // Append elements in the range [begin, end) after reserving
+  // the appropriate number of elements.
+  template <typename Iter>
+  void Add(Iter begin, Iter end);
+
+  const Element& operator[](int index) const { return Get(index); }
+  Element& operator[](int index) { return *Mutable(index); }
+
+  const Element& at(int index) const;
+  Element& at(int index);
+
+  // Removes the last element in the array.
+  // Ownership of the element is retained by the array.
+  void RemoveLast();
+
+  // Deletes elements with indices in the range [start .. start+num-1].
+  // Caution: moves all elements with indices [start+num .. ].
+  // Calling this routine inside a loop can cause quadratic behavior.
+  void DeleteSubrange(int start, int num);
+
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear();
+  void MergeFrom(const RepeatedPtrField& other);
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void CopyFrom(const RepeatedPtrField& other);
+
+  // Replaces the contents with RepeatedPtrField(begin, end).
+  template <typename Iter>
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end);
+
+  // Reserves space to expand the field to at least the given size.  This only
+  // resizes the pointer array; it doesn't allocate any objects.  If the
+  // array is grown, it will always be at least doubled in size.
+  void Reserve(int new_size);
+
+  int Capacity() const;
+
+  // Gets the underlying array.  This pointer is possibly invalidated by
+  // any add or remove operation.
+  //
+  // This API is deprecated. Instead of directly working with element array,
+  // use APIs in repeated_field_util.h; e.g. sorting, etc.
+  PROTOBUF_DEPRECATED_MSG("Use APIs in repeated_field_util.h")
+  Element** mutable_data();
+  const Element* const* data() const;
+
+  // Swaps entire contents with "other". If they are on separate arenas, then
+  // copies data.
+  void Swap(RepeatedPtrField* other);
+
+  // Swaps entire contents with "other". Caller should guarantee that either
+  // both fields are on the same arena or both are on the heap. Swapping between
+  // different arenas with this function is disallowed and is caught via
+  // GOOGLE_DCHECK.
+  void UnsafeArenaSwap(RepeatedPtrField* other);
+
+  // Swaps two elements.
+  void SwapElements(int index1, int index2);
+
+  // STL-like iterator support
+  typedef internal::RepeatedPtrIterator<Element> iterator;
+  typedef internal::RepeatedPtrIterator<const Element> const_iterator;
+  typedef Element value_type;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef int size_type;
+  typedef ptrdiff_t difference_type;
+
+  iterator begin();
+  const_iterator begin() const;
+  const_iterator cbegin() const;
+  iterator end();
+  const_iterator end() const;
+  const_iterator cend() const;
+
+  // Reverse iterator support
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef std::reverse_iterator<iterator> reverse_iterator;
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // Custom STL-like iterator that iterates over and returns the underlying
+  // pointers to Element rather than Element itself.
+  typedef internal::RepeatedPtrOverPtrsIterator<Element*, void*>
+      pointer_iterator;
+  typedef internal::RepeatedPtrOverPtrsIterator<const Element* const,
+                                                const void* const>
+      const_pointer_iterator;
+  pointer_iterator pointer_begin();
+  const_pointer_iterator pointer_begin() const;
+  pointer_iterator pointer_end();
+  const_pointer_iterator pointer_end() const;
+
+  // Returns (an estimate of) the number of bytes used by the repeated field,
+  // excluding sizeof(*this).
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+  // Advanced memory management --------------------------------------
+  // When hardcore memory management becomes necessary -- as it sometimes
+  // does here at Google -- the following methods may be useful.
+
+  // Adds an already-allocated object, passing ownership to the
+  // RepeatedPtrField.
+  //
+  // Note that some special behavior occurs with respect to arenas:
+  //
+  //   (i) if this field holds submessages, the new submessage will be copied if
+  //   the original is in an arena and this RepeatedPtrField is either in a
+  //   different arena, or on the heap.
+  //   (ii) if this field holds strings, the passed-in string *must* be
+  //   heap-allocated, not arena-allocated. There is no way to dynamically check
+  //   this at runtime, so User Beware.
+  void AddAllocated(Element* value);
+
+  // Removes and returns the last element, passing ownership to the caller.
+  // Requires:  size() > 0
+  //
+  // If this RepeatedPtrField is on an arena, an object copy is required to pass
+  // ownership back to the user (for compatible semantics). Use
+  // UnsafeArenaReleaseLast() if this behavior is undesired.
+  PROTOBUF_NODISCARD Element* ReleaseLast();
+
+  // Adds an already-allocated object, skipping arena-ownership checks. The user
+  // must guarantee that the given object is in the same arena as this
+  // RepeatedPtrField.
+  // It is also useful in legacy code that uses temporary ownership to avoid
+  // copies. Example:
+  //   RepeatedPtrField<T> temp_field;
+  //   temp_field.UnsafeArenaAddAllocated(new T);
+  //   ... // Do something with temp_field
+  //   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
+  // If you put temp_field on the arena this fails, because the ownership
+  // transfers to the arena at the "AddAllocated" call and is not released
+  // anymore, causing a double delete. UnsafeArenaAddAllocated prevents this.
+  void UnsafeArenaAddAllocated(Element* value);
+
+  // Removes and returns the last element.  Unlike ReleaseLast, the returned
+  // pointer is always to the original object.  This may be in an arena, in
+  // which case it would have the arena's lifetime.
+  // Requires: current_size_ > 0
+  Element* UnsafeArenaReleaseLast();
+
+  // Extracts elements with indices in the range "[start .. start+num-1]".
+  // The caller assumes ownership of the extracted elements and is responsible
+  // for deleting them when they are no longer needed.
+  // If "elements" is non-nullptr, then pointers to the extracted elements
+  // are stored in "elements[0 .. num-1]" for the convenience of the caller.
+  // If "elements" is nullptr, then the caller must use some other mechanism
+  // to perform any further operations (like deletion) on these elements.
+  // Caution: implementation also moves elements with indices [start+num ..].
+  // Calling this routine inside a loop can cause quadratic behavior.
+  //
+  // Memory copying behavior is identical to ReleaseLast(), described above: if
+  // this RepeatedPtrField is on an arena, an object copy is performed for each
+  // returned element, so that all returned element pointers are to
+  // heap-allocated copies. If this copy is not desired, the user should call
+  // UnsafeArenaExtractSubrange().
+  void ExtractSubrange(int start, int num, Element** elements);
+
+  // Identical to ExtractSubrange() described above, except that no object
+  // copies are ever performed. Instead, the raw object pointers are returned.
+  // Thus, if on an arena, the returned objects must not be freed, because they
+  // will not be heap-allocated objects.
+  void UnsafeArenaExtractSubrange(int start, int num, Element** elements);
+
+  // When elements are removed by calls to RemoveLast() or Clear(), they
+  // are not actually freed.  Instead, they are cleared and kept so that
+  // they can be reused later.  This can save lots of CPU time when
+  // repeatedly reusing a protocol message for similar purposes.
+  //
+  // Hardcore programs may choose to manipulate these cleared objects
+  // to better optimize memory management using the following routines.
+
+  // Gets the number of cleared objects that are currently being kept
+  // around for reuse.
+  int ClearedCount() const;
+#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
+  // Adds an element to the pool of cleared objects, passing ownership to
+  // the RepeatedPtrField.  The element must be cleared prior to calling
+  // this method.
+  //
+  // This method cannot be called when either the repeated field or |value| is
+  // on an arena; both cases will trigger a GOOGLE_DCHECK-failure.
+  void AddCleared(Element* value);
+  // Removes and returns a single element from the cleared pool, passing
+  // ownership to the caller.  The element is guaranteed to be cleared.
+  // Requires:  ClearedCount() > 0
+  //
+  // This method cannot be called when the repeated field is on an arena; doing
+  // so will trigger a GOOGLE_DCHECK-failure.
+  PROTOBUF_NODISCARD Element* ReleaseCleared();
+#endif  // !PROTOBUF_FUTURE_BREAKING_CHANGES
+
+  // Removes the element referenced by position.
+  //
+  // Returns an iterator to the element immediately following the removed
+  // element.
+  //
+  // Invalidates all iterators at or after the removed element, including end().
+  iterator erase(const_iterator position);
+
+  // Removes the elements in the range [first, last).
+  //
+  // Returns an iterator to the element immediately following the removed range.
+  //
+  // Invalidates all iterators at or after the removed range, including end().
+  iterator erase(const_iterator first, const_iterator last);
+
+  // Gets the arena on which this RepeatedPtrField stores its elements.
+  inline Arena* GetArena() const;
+
+  // For internal use only.
+  //
+  // This is public due to it being called by generated code.
+  void InternalSwap(RepeatedPtrField* other) {
+    internal::RepeatedPtrFieldBase::InternalSwap(other);
+  }
+
+ private:
+  // Note:  RepeatedPtrField SHOULD NOT be subclassed by users.
+  class TypeHandler;
+
+  // Internal version of GetArena().
+  inline Arena* GetOwningArena() const;
+
+  // Implementations for ExtractSubrange(). The copying behavior must be
+  // included only if the type supports the necessary operations (e.g.,
+  // MergeFrom()), so we must resolve this at compile time. ExtractSubrange()
+  // uses SFINAE to choose one of the below implementations.
+  void ExtractSubrangeInternal(int start, int num, Element** elements,
+                               std::true_type);
+  void ExtractSubrangeInternal(int start, int num, Element** elements,
+                               std::false_type);
+
+  friend class Arena;
+
+  template <typename T>
+  friend struct WeakRepeatedPtrField;
+
+  typedef void InternalArenaConstructable_;
+
+};
+
+// -------------------------------------------------------------------
+
+template <typename Element>
+class RepeatedPtrField<Element>::TypeHandler
+    : public internal::GenericTypeHandler<Element> {};
+
+template <>
+class RepeatedPtrField<std::string>::TypeHandler
+    : public internal::StringTypeHandler {};
+
+template <typename Element>
+constexpr RepeatedPtrField<Element>::RepeatedPtrField()
+    : RepeatedPtrFieldBase() {}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(Arena* arena)
+    : RepeatedPtrFieldBase(arena) {}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(
+    const RepeatedPtrField& other)
+    : RepeatedPtrFieldBase() {
+  MergeFrom(other);
+}
+
+template <typename Element>
+template <typename Iter, typename>
+inline RepeatedPtrField<Element>::RepeatedPtrField(Iter begin, Iter end) {
+  Add(begin, end);
+}
+
+template <typename Element>
+RepeatedPtrField<Element>::~RepeatedPtrField() {
+#ifdef __cpp_if_constexpr
+  if constexpr (std::is_base_of<MessageLite, Element>::value) {
+#else
+  if (std::is_base_of<MessageLite, Element>::value) {
+#endif
+    if (NeedsDestroy()) DestroyProtos();
+  } else {
+    Destroy<TypeHandler>();
+  }
+}
+
+template <typename Element>
+inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
+    const RepeatedPtrField& other) {
+  if (this != &other) CopyFrom(other);
+  return *this;
+}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(
+    RepeatedPtrField&& other) noexcept
+    : RepeatedPtrField() {
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+  CopyFrom(other);
+#else   // PROTOBUF_FORCE_COPY_IN_MOVE
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // other is on an arena. This field can't be on an arena because arena
+  // construction always uses the Arena* accepting constructor.
+  if (other.GetOwningArena()) {
+    CopyFrom(other);
+  } else {
+    InternalSwap(&other);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+}
+
+template <typename Element>
+inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
+    RepeatedPtrField&& other) noexcept {
+  // We don't just call Swap(&other) here because it would perform 3 copies if
+  // the two fields are on different arenas.
+  if (this != &other) {
+    if (GetOwningArena() != other.GetOwningArena()
+#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        || GetOwningArena() == nullptr
+#endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      CopyFrom(other);
+    } else {
+      InternalSwap(&other);
+    }
+  }
+  return *this;
+}
+
+template <typename Element>
+inline bool RepeatedPtrField<Element>::empty() const {
+  return RepeatedPtrFieldBase::empty();
+}
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::size() const {
+  return RepeatedPtrFieldBase::size();
+}
+
+template <typename Element>
+inline const Element& RepeatedPtrField<Element>::Get(int index) const {
+  return RepeatedPtrFieldBase::Get<TypeHandler>(index);
+}
+
+template <typename Element>
+inline const Element& RepeatedPtrField<Element>::at(int index) const {
+  return RepeatedPtrFieldBase::at<TypeHandler>(index);
+}
+
+template <typename Element>
+inline Element& RepeatedPtrField<Element>::at(int index) {
+  return RepeatedPtrFieldBase::at<TypeHandler>(index);
+}
+
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::Mutable(int index) {
+  return RepeatedPtrFieldBase::Mutable<TypeHandler>(index);
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::Add() {
+  return RepeatedPtrFieldBase::Add<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Add(Element&& value) {
+  RepeatedPtrFieldBase::Add<TypeHandler>(std::move(value));
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedPtrField<Element>::Add(Iter begin, Iter end) {
+  if (std::is_base_of<
+          std::forward_iterator_tag,
+          typename std::iterator_traits<Iter>::iterator_category>::value) {
+    int reserve = std::distance(begin, end);
+    Reserve(size() + reserve);
+  }
+  for (; begin != end; ++begin) {
+    *Add() = *begin;
+  }
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::RemoveLast() {
+  RepeatedPtrFieldBase::RemoveLast<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::DeleteSubrange(int start, int num) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+  for (int i = 0; i < num; ++i) {
+    RepeatedPtrFieldBase::Delete<TypeHandler>(start + i);
+  }
+  UnsafeArenaExtractSubrange(start, num, nullptr);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrange(int start, int num,
+                                                       Element** elements) {
+  typename internal::TypeImplementsMergeBehavior<
+      typename TypeHandler::Type>::type t;
+  ExtractSubrangeInternal(start, num, elements, t);
+}
+
+// ExtractSubrange() implementation for types that implement merge/copy
+// behavior.
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrangeInternal(
+    int start, int num, Element** elements, std::true_type) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+
+  if (num == 0) return;
+
+  GOOGLE_DCHECK_NE(elements, nullptr)
+      << "Releasing elements without transferring ownership is an unsafe "
+         "operation.  Use UnsafeArenaExtractSubrange.";
+  if (elements == nullptr) {
+    CloseGap(start, num);
+    return;
+  }
+
+  Arena* arena = GetOwningArena();
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  // Always copy.
+  for (int i = 0; i < num; ++i) {
+    elements[i] = copy<TypeHandler>(
+        RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start));
+  }
+  if (arena == nullptr) {
+    for (int i = 0; i < num; ++i) {
+      delete RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+    }
+  }
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+  // If we're on an arena, we perform a copy for each element so that the
+  // returned elements are heap-allocated. Otherwise, just forward it.
+  if (arena != nullptr) {
+    for (int i = 0; i < num; ++i) {
+      elements[i] = copy<TypeHandler>(
+          RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start));
+    }
+  } else {
+    for (int i = 0; i < num; ++i) {
+      elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+    }
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  CloseGap(start, num);
+}
+
+// ExtractSubrange() implementation for types that do not implement merge/copy
+// behavior.
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrangeInternal(
+    int start, int num, Element** elements, std::false_type) {
+  // This case is identical to UnsafeArenaExtractSubrange(). However, since
+  // ExtractSubrange() must return heap-allocated objects by contract, and we
+  // cannot fulfill this contract if we are an on arena, we must GOOGLE_DCHECK() that
+  // we are not on an arena.
+  GOOGLE_DCHECK(GetOwningArena() == nullptr)
+      << "ExtractSubrange() when arena is non-nullptr is only supported when "
+      << "the Element type supplies a MergeFrom() operation to make copies.";
+  UnsafeArenaExtractSubrange(start, num, elements);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaExtractSubrange(
+    int start, int num, Element** elements) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+
+  if (num > 0) {
+    // Save the values of the removed elements if requested.
+    if (elements != nullptr) {
+      for (int i = 0; i < num; ++i) {
+        elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+      }
+    }
+    CloseGap(start, num);
+  }
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Clear() {
+  RepeatedPtrFieldBase::Clear<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::MergeFrom(
+    const RepeatedPtrField& other) {
+  RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::CopyFrom(const RepeatedPtrField& other) {
+  RepeatedPtrFieldBase::CopyFrom<TypeHandler>(other);
+}
+
+template <typename Element>
+template <typename Iter>
+inline void RepeatedPtrField<Element>::Assign(Iter begin, Iter end) {
+  Clear();
+  Add(begin, end);
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator position) {
+  return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator first, const_iterator last) {
+  size_type pos_offset = std::distance(cbegin(), first);
+  size_type last_offset = std::distance(cbegin(), last);
+  DeleteSubrange(pos_offset, last_offset - pos_offset);
+  return begin() + pos_offset;
+}
+
+template <typename Element>
+inline Element** RepeatedPtrField<Element>::mutable_data() {
+  return RepeatedPtrFieldBase::mutable_data<TypeHandler>();
+}
+
+template <typename Element>
+inline const Element* const* RepeatedPtrField<Element>::data() const {
+  return RepeatedPtrFieldBase::data<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
+  if (this == other) return;
+  RepeatedPtrFieldBase::Swap<TypeHandler>(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaSwap(
+    RepeatedPtrField* other) {
+  if (this == other) return;
+  GOOGLE_DCHECK_EQ(GetOwningArena(), other->GetOwningArena());
+  RepeatedPtrFieldBase::InternalSwap(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
+  RepeatedPtrFieldBase::SwapElements(index1, index2);
+}
+
+template <typename Element>
+inline Arena* RepeatedPtrField<Element>::GetArena() const {
+  return RepeatedPtrFieldBase::GetArena();
+}
+
+template <typename Element>
+inline Arena* RepeatedPtrField<Element>::GetOwningArena() const {
+  return RepeatedPtrFieldBase::GetOwningArena();
+}
+
+template <typename Element>
+inline size_t RepeatedPtrField<Element>::SpaceUsedExcludingSelfLong() const {
+  return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong<TypeHandler>();
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::AddAllocated(Element* value) {
+  RepeatedPtrFieldBase::AddAllocated<TypeHandler>(value);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaAddAllocated(Element* value) {
+  RepeatedPtrFieldBase::UnsafeArenaAddAllocated<TypeHandler>(value);
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::ReleaseLast() {
+  return RepeatedPtrFieldBase::ReleaseLast<TypeHandler>();
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::UnsafeArenaReleaseLast() {
+  return RepeatedPtrFieldBase::UnsafeArenaReleaseLast<TypeHandler>();
+}
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::ClearedCount() const {
+  return RepeatedPtrFieldBase::ClearedCount();
+}
+
+#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
+template <typename Element>
+inline void RepeatedPtrField<Element>::AddCleared(Element* value) {
+  return RepeatedPtrFieldBase::AddCleared<TypeHandler>(value);
+}
+
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::ReleaseCleared() {
+  return RepeatedPtrFieldBase::ReleaseCleared<TypeHandler>();
+}
+#endif  // !PROTOBUF_FUTURE_BREAKING_CHANGES
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::Reserve(int new_size) {
+  return RepeatedPtrFieldBase::Reserve(new_size);
+}
+
+template <typename Element>
+inline int RepeatedPtrField<Element>::Capacity() const {
+  return RepeatedPtrFieldBase::Capacity();
+}
+
+// -------------------------------------------------------------------
+
+namespace internal {
+
+// STL-like iterator implementation for RepeatedPtrField.  You should not
+// refer to this class directly; use RepeatedPtrField<T>::iterator instead.
+//
+// The iterator for RepeatedPtrField<T>, RepeatedPtrIterator<T>, is
+// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors.h,
+// but adds random-access operators and is modified to wrap a void** base
+// iterator (since RepeatedPtrField stores its array as a void* array and
+// casting void** to T** would violate C++ aliasing rules).
+//
+// This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin
+// (jyasskin@google.com).
+template <typename Element>
+class RepeatedPtrIterator {
+ public:
+  using iterator = RepeatedPtrIterator<Element>;
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = typename std::remove_const<Element>::type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = Element*;
+  using reference = Element&;
+
+  RepeatedPtrIterator() : it_(nullptr) {}
+  explicit RepeatedPtrIterator(void* const* it) : it_(it) {}
+
+  // Allows "upcasting" from RepeatedPtrIterator<T**> to
+  // RepeatedPtrIterator<const T*const*>.
+  template <typename OtherElement,
+            typename std::enable_if<std::is_convertible<
+                OtherElement*, pointer>::value>::type* = nullptr>
+  RepeatedPtrIterator(const RepeatedPtrIterator<OtherElement>& other)
+      : it_(other.it_) {}
+
+  // dereferenceable
+  reference operator*() const { return *reinterpret_cast<Element*>(*it_); }
+  pointer operator->() const { return &(operator*()); }
+
+  // {inc,dec}rementable
+  iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  iterator operator++(int) { return iterator(it_++); }
+  iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  iterator operator--(int) { return iterator(it_--); }
+
+  // equality_comparable
+  friend bool operator==(const iterator& x, const iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend bool operator!=(const iterator& x, const iterator& y) {
+    return x.it_ != y.it_;
+  }
+
+  // less_than_comparable
+  friend bool operator<(const iterator& x, const iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend bool operator<=(const iterator& x, const iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend bool operator>(const iterator& x, const iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend bool operator>=(const iterator& x, const iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  // addable, subtractable
+  iterator& operator+=(difference_type d) {
+    it_ += d;
+    return *this;
+  }
+  friend iterator operator+(iterator it, const difference_type d) {
+    it += d;
+    return it;
+  }
+  friend iterator operator+(const difference_type d, iterator it) {
+    it += d;
+    return it;
+  }
+  iterator& operator-=(difference_type d) {
+    it_ -= d;
+    return *this;
+  }
+  friend iterator operator-(iterator it, difference_type d) {
+    it -= d;
+    return it;
+  }
+
+  // indexable
+  reference operator[](difference_type d) const { return *(*this + d); }
+
+  // random access iterator
+  friend difference_type operator-(iterator it1, iterator it2) {
+    return it1.it_ - it2.it_;
+  }
+
+ private:
+  template <typename OtherElement>
+  friend class RepeatedPtrIterator;
+
+  // The internal iterator.
+  void* const* it_;
+};
+
+// Provides an iterator that operates on pointers to the underlying objects
+// rather than the objects themselves as RepeatedPtrIterator does.
+// Consider using this when working with stl algorithms that change
+// the array.
+// The VoidPtr template parameter holds the type-agnostic pointer value
+// referenced by the iterator.  It should either be "void *" for a mutable
+// iterator, or "const void* const" for a constant iterator.
+template <typename Element, typename VoidPtr>
+class RepeatedPtrOverPtrsIterator {
+ public:
+  using iterator = RepeatedPtrOverPtrsIterator<Element, VoidPtr>;
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = typename std::remove_const<Element>::type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = Element*;
+  using reference = Element&;
+
+  RepeatedPtrOverPtrsIterator() : it_(nullptr) {}
+  explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {}
+
+  // Allows "upcasting" from RepeatedPtrOverPtrsIterator<T**> to
+  // RepeatedPtrOverPtrsIterator<const T*const*>.
+  template <
+      typename OtherElement, typename OtherVoidPtr,
+      typename std::enable_if<
+          std::is_convertible<OtherElement*, pointer>::value &&
+          std::is_convertible<OtherVoidPtr*, VoidPtr>::value>::type* = nullptr>
+  RepeatedPtrOverPtrsIterator(
+      const RepeatedPtrOverPtrsIterator<OtherElement, OtherVoidPtr>& other)
+      : it_(other.it_) {}
+
+  // dereferenceable
+  reference operator*() const { return *reinterpret_cast<Element*>(it_); }
+  pointer operator->() const { return &(operator*()); }
+
+  // {inc,dec}rementable
+  iterator& operator++() {
+    ++it_;
+    return *this;
+  }
+  iterator operator++(int) { return iterator(it_++); }
+  iterator& operator--() {
+    --it_;
+    return *this;
+  }
+  iterator operator--(int) { return iterator(it_--); }
+
+  // equality_comparable
+  friend bool operator==(const iterator& x, const iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend bool operator!=(const iterator& x, const iterator& y) {
+    return x.it_ != y.it_;
+  }
+
+  // less_than_comparable
+  friend bool operator<(const iterator& x, const iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend bool operator<=(const iterator& x, const iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend bool operator>(const iterator& x, const iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend bool operator>=(const iterator& x, const iterator& y) {
+    return x.it_ >= y.it_;
+  }
+
+  // addable, subtractable
+  iterator& operator+=(difference_type d) {
+    it_ += d;
+    return *this;
+  }
+  friend iterator operator+(iterator it, difference_type d) {
+    it += d;
+    return it;
+  }
+  friend iterator operator+(difference_type d, iterator it) {
+    it += d;
+    return it;
+  }
+  iterator& operator-=(difference_type d) {
+    it_ -= d;
+    return *this;
+  }
+  friend iterator operator-(iterator it, difference_type d) {
+    it -= d;
+    return it;
+  }
+
+  // indexable
+  reference operator[](difference_type d) const { return *(*this + d); }
+
+  // random access iterator
+  friend difference_type operator-(iterator it1, iterator it2) {
+    return it1.it_ - it2.it_;
+  }
+
+ private:
+  template <typename OtherElement, typename OtherVoidPtr>
+  friend class RepeatedPtrOverPtrsIterator;
+
+  // The internal iterator.
+  VoidPtr* it_;
+};
+
+}  // namespace internal
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::begin() {
+  return iterator(raw_data());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::begin() const {
+  return iterator(raw_data());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cbegin() const {
+  return begin();
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::end() {
+  return iterator(raw_data() + size());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::end() const {
+  return iterator(raw_data() + size());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cend() const {
+  return end();
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::pointer_iterator
+RepeatedPtrField<Element>::pointer_begin() {
+  return pointer_iterator(raw_mutable_data());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_begin() const {
+  return const_pointer_iterator(const_cast<const void* const*>(raw_data()));
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::pointer_iterator
+RepeatedPtrField<Element>::pointer_end() {
+  return pointer_iterator(raw_mutable_data() + size());
+}
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_pointer_iterator
+RepeatedPtrField<Element>::pointer_end() const {
+  return const_pointer_iterator(
+      const_cast<const void* const*>(raw_data() + size()));
+}
+
+// Iterators and helper functions that follow the spirit of the STL
+// std::back_insert_iterator and std::back_inserter but are tailor-made
+// for RepeatedField and RepeatedPtrField. Typical usage would be:
+//
+//   std::copy(some_sequence.begin(), some_sequence.end(),
+//             RepeatedFieldBackInserter(proto.mutable_sequence()));
+//
+// Ported by johannes from util/gtl/proto-array-iterators.h
+
+namespace internal {
+
+// A back inserter for RepeatedPtrField objects.
+template <typename T>
+class RepeatedPtrFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  RepeatedPtrFieldBackInsertIterator(RepeatedPtrField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  RepeatedPtrFieldBackInsertIterator<T>& operator=(const T& value) {
+    *field_->Add() = value;
+    return *this;
+  }
+  RepeatedPtrFieldBackInsertIterator<T>& operator=(
+      const T* const ptr_to_value) {
+    *field_->Add() = *ptr_to_value;
+    return *this;
+  }
+  RepeatedPtrFieldBackInsertIterator<T>& operator=(T&& value) {
+    *field_->Add() = std::move(value);
+    return *this;
+  }
+  RepeatedPtrFieldBackInsertIterator<T>& operator*() { return *this; }
+  RepeatedPtrFieldBackInsertIterator<T>& operator++() { return *this; }
+  RepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedPtrField<T>* field_;
+};
+
+// A back inserter for RepeatedPtrFields that inserts by transferring ownership
+// of a pointer.
+template <typename T>
+class AllocatedRepeatedPtrFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  explicit AllocatedRepeatedPtrFieldBackInsertIterator(
+      RepeatedPtrField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=(
+      T* const ptr_to_value) {
+    field_->AddAllocated(ptr_to_value);
+    return *this;
+  }
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() { return *this; }
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() { return *this; }
+  AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedPtrField<T>* field_;
+};
+
+// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one
+// uses the UnsafeArenaAddAllocated instead.
+template <typename T>
+class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator {
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = T;
+  using pointer = void;
+  using reference = void;
+  using difference_type = std::ptrdiff_t;
+
+  explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator(
+      RepeatedPtrField<T>* const mutable_field)
+      : field_(mutable_field) {}
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=(
+      T const* const ptr_to_value) {
+    field_->UnsafeArenaAddAllocated(const_cast<T*>(ptr_to_value));
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() {
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() {
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
+      int /* unused */) {
+    return *this;
+  }
+
+ private:
+  RepeatedPtrField<T>* field_;
+};
+
+}  // namespace internal
+
+// Provides a back insert iterator for RepeatedPtrField instances,
+// similar to std::back_inserter().
+template <typename T>
+internal::RepeatedPtrFieldBackInsertIterator<T> RepeatedPtrFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Special back insert iterator for RepeatedPtrField instances, just in
+// case someone wants to write generic template code that can access both
+// RepeatedFields and RepeatedPtrFields using a common name.
+template <typename T>
+internal::RepeatedPtrFieldBackInsertIterator<T> RepeatedFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
+}
+
+// Provides a back insert iterator for RepeatedPtrField instances
+// similar to std::back_inserter() which transfers the ownership while
+// copying elements.
+template <typename T>
+internal::AllocatedRepeatedPtrFieldBackInsertIterator<T>
+AllocatedRepeatedPtrFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::AllocatedRepeatedPtrFieldBackInsertIterator<T>(
+      mutable_field);
+}
+
+// Similar to AllocatedRepeatedPtrFieldBackInserter, using
+// UnsafeArenaAddAllocated instead of AddAllocated.
+// This is slightly faster if that matters. It is also useful in legacy code
+// that uses temporary ownership to avoid copies. Example:
+//   RepeatedPtrField<T> temp_field;
+//   temp_field.UnsafeArenaAddAllocated(new T);
+//   ... // Do something with temp_field
+//   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
+// Putting temp_field on the arena fails because the ownership transfers to the
+// arena at the "AddAllocated" call and is not released anymore causing a
+// double delete. This function uses UnsafeArenaAddAllocated to prevent this.
+template <typename T>
+internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>
+UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+    RepeatedPtrField<T>* const mutable_field) {
+  return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>(
+      mutable_field);
+}
+
+extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
+    RepeatedPtrField<std::string>;
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/service.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/service.h
new file mode 100644
index 0000000..d288eb5
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/service.h
@@ -0,0 +1,295 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// DEPRECATED:  This module declares the abstract interfaces underlying proto2
+// RPC services.  These are intended to be independent of any particular RPC
+// implementation, so that proto2 services can be used on top of a variety
+// of implementations.  Starting with version 2.3.0, RPC implementations should
+// not try to build on these, but should instead provide code generator plugins
+// which generate code specific to the particular RPC implementation.  This way
+// the generated code can be more appropriate for the implementation in use
+// and can avoid unnecessary layers of indirection.
+//
+//
+// When you use the protocol compiler to compile a service definition, it
+// generates two classes:  An abstract interface for the service (with
+// methods matching the service definition) and a "stub" implementation.
+// A stub is just a type-safe wrapper around an RpcChannel which emulates a
+// local implementation of the service.
+//
+// For example, the service definition:
+//   service MyService {
+//     rpc Foo(MyRequest) returns(MyResponse);
+//   }
+// will generate abstract interface "MyService" and class "MyService::Stub".
+// You could implement a MyService as follows:
+//   class MyServiceImpl : public MyService {
+//    public:
+//     MyServiceImpl() {}
+//     ~MyServiceImpl() {}
+//
+//     // implements MyService ---------------------------------------
+//
+//     void Foo(google::protobuf::RpcController* controller,
+//              const MyRequest* request,
+//              MyResponse* response,
+//              Closure* done) {
+//       // ... read request and fill in response ...
+//       done->Run();
+//     }
+//   };
+// You would then register an instance of MyServiceImpl with your RPC server
+// implementation.  (How to do that depends on the implementation.)
+//
+// To call a remote MyServiceImpl, first you need an RpcChannel connected to it.
+// How to construct a channel depends, again, on your RPC implementation.
+// Here we use a hypothetical "MyRpcChannel" as an example:
+//   MyRpcChannel channel("rpc:hostname:1234/myservice");
+//   MyRpcController controller;
+//   MyServiceImpl::Stub stub(&channel);
+//   FooRequest request;
+//   FooResponse response;
+//
+//   // ... fill in request ...
+//
+//   stub.Foo(&controller, request, &response, NewCallback(HandleResponse));
+//
+// On Thread-Safety:
+//
+// Different RPC implementations may make different guarantees about what
+// threads they may run callbacks on, and what threads the application is
+// allowed to use to call the RPC system.  Portable software should be ready
+// for callbacks to be called on any thread, but should not try to call the
+// RPC system from any thread except for the ones on which it received the
+// callbacks.  Realistically, though, simple software will probably want to
+// use a single-threaded RPC system while high-end software will want to
+// use multiple threads.  RPC implementations should provide multiple
+// choices.
+
+#ifndef GOOGLE_PROTOBUF_SERVICE_H__
+#define GOOGLE_PROTOBUF_SERVICE_H__
+
+
+#include <string>
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Defined in this file.
+class Service;
+class RpcController;
+class RpcChannel;
+
+// Defined in other files.
+class Descriptor;         // descriptor.h
+class ServiceDescriptor;  // descriptor.h
+class MethodDescriptor;   // descriptor.h
+class Message;            // message.h
+
+// Abstract base interface for protocol-buffer-based RPC services.  Services
+// themselves are abstract interfaces (implemented either by servers or as
+// stubs), but they subclass this base interface.  The methods of this
+// interface can be used to call the methods of the Service without knowing
+// its exact type at compile time (analogous to Reflection).
+class PROTOBUF_EXPORT Service {
+ public:
+  inline Service() {}
+  virtual ~Service();
+
+  // When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second
+  // parameter to the constructor to tell it to delete its RpcChannel when
+  // destroyed.
+  enum ChannelOwnership { STUB_OWNS_CHANNEL, STUB_DOESNT_OWN_CHANNEL };
+
+  // Get the ServiceDescriptor describing this service and its methods.
+  virtual const ServiceDescriptor* GetDescriptor() = 0;
+
+  // Call a method of the service specified by MethodDescriptor.  This is
+  // normally implemented as a simple switch() that calls the standard
+  // definitions of the service's methods.
+  //
+  // Preconditions:
+  // * method->service() == GetDescriptor()
+  // * request and response are of the exact same classes as the objects
+  //   returned by GetRequestPrototype(method) and
+  //   GetResponsePrototype(method).
+  // * After the call has started, the request must not be modified and the
+  //   response must not be accessed at all until "done" is called.
+  // * "controller" is of the correct type for the RPC implementation being
+  //   used by this Service.  For stubs, the "correct type" depends on the
+  //   RpcChannel which the stub is using.  Server-side Service
+  //   implementations are expected to accept whatever type of RpcController
+  //   the server-side RPC implementation uses.
+  //
+  // Postconditions:
+  // * "done" will be called when the method is complete.  This may be
+  //   before CallMethod() returns or it may be at some point in the future.
+  // * If the RPC succeeded, "response" contains the response returned by
+  //   the server.
+  // * If the RPC failed, "response"'s contents are undefined.  The
+  //   RpcController can be queried to determine if an error occurred and
+  //   possibly to get more information about the error.
+  virtual void CallMethod(const MethodDescriptor* method,
+                          RpcController* controller, const Message* request,
+                          Message* response, Closure* done) = 0;
+
+  // CallMethod() requires that the request and response passed in are of a
+  // particular subclass of Message.  GetRequestPrototype() and
+  // GetResponsePrototype() get the default instances of these required types.
+  // You can then call Message::New() on these instances to construct mutable
+  // objects which you can then pass to CallMethod().
+  //
+  // Example:
+  //   const MethodDescriptor* method =
+  //     service->GetDescriptor()->FindMethodByName("Foo");
+  //   Message* request  = stub->GetRequestPrototype (method)->New();
+  //   Message* response = stub->GetResponsePrototype(method)->New();
+  //   request->ParseFromString(input);
+  //   service->CallMethod(method, *request, response, callback);
+  virtual const Message& GetRequestPrototype(
+      const MethodDescriptor* method) const = 0;
+  virtual const Message& GetResponsePrototype(
+      const MethodDescriptor* method) const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service);
+};
+
+// An RpcController mediates a single method call.  The primary purpose of
+// the controller is to provide a way to manipulate settings specific to the
+// RPC implementation and to find out about RPC-level errors.
+//
+// The methods provided by the RpcController interface are intended to be a
+// "least common denominator" set of features which we expect all
+// implementations to support.  Specific implementations may provide more
+// advanced features (e.g. deadline propagation).
+class PROTOBUF_EXPORT RpcController {
+ public:
+  inline RpcController() {}
+  virtual ~RpcController();
+
+  // Client-side methods ---------------------------------------------
+  // These calls may be made from the client side only.  Their results
+  // are undefined on the server side (may crash).
+
+  // Resets the RpcController to its initial state so that it may be reused in
+  // a new call.  Must not be called while an RPC is in progress.
+  virtual void Reset() = 0;
+
+  // After a call has finished, returns true if the call failed.  The possible
+  // reasons for failure depend on the RPC implementation.  Failed() must not
+  // be called before a call has finished.  If Failed() returns true, the
+  // contents of the response message are undefined.
+  virtual bool Failed() const = 0;
+
+  // If Failed() is true, returns a human-readable description of the error.
+  virtual std::string ErrorText() const = 0;
+
+  // Advises the RPC system that the caller desires that the RPC call be
+  // canceled.  The RPC system may cancel it immediately, may wait awhile and
+  // then cancel it, or may not even cancel the call at all.  If the call is
+  // canceled, the "done" callback will still be called and the RpcController
+  // will indicate that the call failed at that time.
+  virtual void StartCancel() = 0;
+
+  // Server-side methods ---------------------------------------------
+  // These calls may be made from the server side only.  Their results
+  // are undefined on the client side (may crash).
+
+  // Causes Failed() to return true on the client side.  "reason" will be
+  // incorporated into the message returned by ErrorText().  If you find
+  // you need to return machine-readable information about failures, you
+  // should incorporate it into your response protocol buffer and should
+  // NOT call SetFailed().
+  virtual void SetFailed(const std::string& reason) = 0;
+
+  // If true, indicates that the client canceled the RPC, so the server may
+  // as well give up on replying to it.  The server should still call the
+  // final "done" callback.
+  virtual bool IsCanceled() const = 0;
+
+  // Asks that the given callback be called when the RPC is canceled.  The
+  // callback will always be called exactly once.  If the RPC completes without
+  // being canceled, the callback will be called after completion.  If the RPC
+  // has already been canceled when NotifyOnCancel() is called, the callback
+  // will be called immediately.
+  //
+  // NotifyOnCancel() must be called no more than once per request.
+  virtual void NotifyOnCancel(Closure* callback) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController);
+};
+
+// Abstract interface for an RPC channel.  An RpcChannel represents a
+// communication line to a Service which can be used to call that Service's
+// methods.  The Service may be running on another machine.  Normally, you
+// should not call an RpcChannel directly, but instead construct a stub Service
+// wrapping it.  Example:
+//   RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234");
+//   MyService* service = new MyService::Stub(channel);
+//   service->MyMethod(request, &response, callback);
+class PROTOBUF_EXPORT RpcChannel {
+ public:
+  inline RpcChannel() {}
+  virtual ~RpcChannel();
+
+  // Call the given method of the remote service.  The signature of this
+  // procedure looks the same as Service::CallMethod(), but the requirements
+  // are less strict in one important way:  the request and response objects
+  // need not be of any specific class as long as their descriptors are
+  // method->input_type() and method->output_type().
+  virtual void CallMethod(const MethodDescriptor* method,
+                          RpcController* controller, const Message* request,
+                          Message* response, Closure* done) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_SERVICE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/source_context.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/source_context.pb.h
new file mode 100644
index 0000000..63e7d11
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/source_context.pb.h
@@ -0,0 +1,282 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fsource_5fcontext_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fsource_5fcontext_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fsource_5fcontext_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class SourceContext;
+struct SourceContextDefaultTypeInternal;
+PROTOBUF_EXPORT extern SourceContextDefaultTypeInternal _SourceContext_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::SourceContext* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT SourceContext final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceContext) */ {
+ public:
+  inline SourceContext() : SourceContext(nullptr) {}
+  ~SourceContext() override;
+  explicit PROTOBUF_CONSTEXPR SourceContext(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  SourceContext(const SourceContext& from);
+  SourceContext(SourceContext&& from) noexcept
+    : SourceContext() {
+    *this = ::std::move(from);
+  }
+
+  inline SourceContext& operator=(const SourceContext& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline SourceContext& operator=(SourceContext&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const SourceContext& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const SourceContext* internal_default_instance() {
+    return reinterpret_cast<const SourceContext*>(
+               &_SourceContext_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(SourceContext& a, SourceContext& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(SourceContext* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(SourceContext* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  SourceContext* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<SourceContext>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const SourceContext& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const SourceContext& from) {
+    SourceContext::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(SourceContext* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.SourceContext";
+  }
+  protected:
+  explicit SourceContext(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFileNameFieldNumber = 1,
+  };
+  // string file_name = 1;
+  void clear_file_name();
+  const std::string& file_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_file_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_file_name();
+  PROTOBUF_NODISCARD std::string* release_file_name();
+  void set_allocated_file_name(std::string* file_name);
+  private:
+  const std::string& _internal_file_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_file_name(const std::string& value);
+  std::string* _internal_mutable_file_name();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceContext)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr file_name_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// SourceContext
+
+// string file_name = 1;
+inline void SourceContext::clear_file_name() {
+  _impl_.file_name_.ClearToEmpty();
+}
+inline const std::string& SourceContext::file_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceContext.file_name)
+  return _internal_file_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void SourceContext::set_file_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.file_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceContext.file_name)
+}
+inline std::string* SourceContext::mutable_file_name() {
+  std::string* _s = _internal_mutable_file_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceContext.file_name)
+  return _s;
+}
+inline const std::string& SourceContext::_internal_file_name() const {
+  return _impl_.file_name_.Get();
+}
+inline void SourceContext::_internal_set_file_name(const std::string& value) {
+  
+  _impl_.file_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* SourceContext::_internal_mutable_file_name() {
+  
+  return _impl_.file_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* SourceContext::release_file_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name)
+  return _impl_.file_name_.Release();
+}
+inline void SourceContext::set_allocated_file_name(std::string* file_name) {
+  if (file_name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.file_name_.SetAllocated(file_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.file_name_.IsDefault()) {
+    _impl_.file_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceContext.file_name)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fsource_5fcontext_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/struct.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/struct.pb.h
new file mode 100644
index 0000000..002aa85
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/struct.pb.h
@@ -0,0 +1,1177 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fstruct_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fstruct_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/map.h>  // IWYU pragma: export
+#include <google/protobuf/map_entry.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fstruct_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fstruct_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class ListValue;
+struct ListValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern ListValueDefaultTypeInternal _ListValue_default_instance_;
+class Struct;
+struct StructDefaultTypeInternal;
+PROTOBUF_EXPORT extern StructDefaultTypeInternal _Struct_default_instance_;
+class Struct_FieldsEntry_DoNotUse;
+struct Struct_FieldsEntry_DoNotUseDefaultTypeInternal;
+PROTOBUF_EXPORT extern Struct_FieldsEntry_DoNotUseDefaultTypeInternal _Struct_FieldsEntry_DoNotUse_default_instance_;
+class Value;
+struct ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern ValueDefaultTypeInternal _Value_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::ListValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::ListValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Struct* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Struct>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Value>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+enum NullValue : int {
+  NULL_VALUE = 0,
+  NullValue_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
+  NullValue_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool NullValue_IsValid(int value);
+constexpr NullValue NullValue_MIN = NULL_VALUE;
+constexpr NullValue NullValue_MAX = NULL_VALUE;
+constexpr int NullValue_ARRAYSIZE = NullValue_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* NullValue_descriptor();
+template<typename T>
+inline const std::string& NullValue_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, NullValue>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function NullValue_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    NullValue_descriptor(), enum_t_value);
+}
+inline bool NullValue_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, NullValue* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<NullValue>(
+    NullValue_descriptor(), name, value);
+}
+// ===================================================================
+
+class Struct_FieldsEntry_DoNotUse : public ::PROTOBUF_NAMESPACE_ID::internal::MapEntry<Struct_FieldsEntry_DoNotUse, 
+    std::string, ::PROTOBUF_NAMESPACE_ID::Value,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> {
+public:
+  typedef ::PROTOBUF_NAMESPACE_ID::internal::MapEntry<Struct_FieldsEntry_DoNotUse, 
+    std::string, ::PROTOBUF_NAMESPACE_ID::Value,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING,
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> SuperType;
+  Struct_FieldsEntry_DoNotUse();
+  explicit PROTOBUF_CONSTEXPR Struct_FieldsEntry_DoNotUse(
+      ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+  explicit Struct_FieldsEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena);
+  void MergeFrom(const Struct_FieldsEntry_DoNotUse& other);
+  static const Struct_FieldsEntry_DoNotUse* internal_default_instance() { return reinterpret_cast<const Struct_FieldsEntry_DoNotUse*>(&_Struct_FieldsEntry_DoNotUse_default_instance_); }
+  static bool ValidateKey(std::string* s) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(s->data(), static_cast<int>(s->size()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE, "google.protobuf.Struct.FieldsEntry.key");
+ }
+  static bool ValidateValue(void*) { return true; }
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Struct final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Struct) */ {
+ public:
+  inline Struct() : Struct(nullptr) {}
+  ~Struct() override;
+  explicit PROTOBUF_CONSTEXPR Struct(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Struct(const Struct& from);
+  Struct(Struct&& from) noexcept
+    : Struct() {
+    *this = ::std::move(from);
+  }
+
+  inline Struct& operator=(const Struct& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Struct& operator=(Struct&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Struct& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Struct* internal_default_instance() {
+    return reinterpret_cast<const Struct*>(
+               &_Struct_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(Struct& a, Struct& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Struct* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Struct* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Struct* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Struct>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Struct& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Struct& from) {
+    Struct::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Struct* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Struct";
+  }
+  protected:
+  explicit Struct(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  private:
+  static void ArenaDtor(void* object);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFieldsFieldNumber = 1,
+  };
+  // map<string, .google.protobuf.Value> fields = 1;
+  int fields_size() const;
+  private:
+  int _internal_fields_size() const;
+  public:
+  void clear_fields();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+      _internal_fields() const;
+  ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+      _internal_mutable_fields();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+      fields() const;
+  ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+      mutable_fields();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Struct)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::MapField<
+        Struct_FieldsEntry_DoNotUse,
+        std::string, ::PROTOBUF_NAMESPACE_ID::Value,
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_STRING,
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::TYPE_MESSAGE> fields_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Value) */ {
+ public:
+  inline Value() : Value(nullptr) {}
+  ~Value() override;
+  explicit PROTOBUF_CONSTEXPR Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Value(const Value& from);
+  Value(Value&& from) noexcept
+    : Value() {
+    *this = ::std::move(from);
+  }
+
+  inline Value& operator=(const Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Value& operator=(Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Value& default_instance() {
+    return *internal_default_instance();
+  }
+  enum KindCase {
+    kNullValue = 1,
+    kNumberValue = 2,
+    kStringValue = 3,
+    kBoolValue = 4,
+    kStructValue = 5,
+    kListValue = 6,
+    KIND_NOT_SET = 0,
+  };
+
+  static inline const Value* internal_default_instance() {
+    return reinterpret_cast<const Value*>(
+               &_Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Value& a, Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Value& from) {
+    Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Value";
+  }
+  protected:
+  explicit Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNullValueFieldNumber = 1,
+    kNumberValueFieldNumber = 2,
+    kStringValueFieldNumber = 3,
+    kBoolValueFieldNumber = 4,
+    kStructValueFieldNumber = 5,
+    kListValueFieldNumber = 6,
+  };
+  // .google.protobuf.NullValue null_value = 1;
+  bool has_null_value() const;
+  private:
+  bool _internal_has_null_value() const;
+  public:
+  void clear_null_value();
+  ::PROTOBUF_NAMESPACE_ID::NullValue null_value() const;
+  void set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::NullValue _internal_null_value() const;
+  void _internal_set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value);
+  public:
+
+  // double number_value = 2;
+  bool has_number_value() const;
+  private:
+  bool _internal_has_number_value() const;
+  public:
+  void clear_number_value();
+  double number_value() const;
+  void set_number_value(double value);
+  private:
+  double _internal_number_value() const;
+  void _internal_set_number_value(double value);
+  public:
+
+  // string string_value = 3;
+  bool has_string_value() const;
+  private:
+  bool _internal_has_string_value() const;
+  public:
+  void clear_string_value();
+  const std::string& string_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_string_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_string_value();
+  PROTOBUF_NODISCARD std::string* release_string_value();
+  void set_allocated_string_value(std::string* string_value);
+  private:
+  const std::string& _internal_string_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_string_value(const std::string& value);
+  std::string* _internal_mutable_string_value();
+  public:
+
+  // bool bool_value = 4;
+  bool has_bool_value() const;
+  private:
+  bool _internal_has_bool_value() const;
+  public:
+  void clear_bool_value();
+  bool bool_value() const;
+  void set_bool_value(bool value);
+  private:
+  bool _internal_bool_value() const;
+  void _internal_set_bool_value(bool value);
+  public:
+
+  // .google.protobuf.Struct struct_value = 5;
+  bool has_struct_value() const;
+  private:
+  bool _internal_has_struct_value() const;
+  public:
+  void clear_struct_value();
+  const ::PROTOBUF_NAMESPACE_ID::Struct& struct_value() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::Struct* release_struct_value();
+  ::PROTOBUF_NAMESPACE_ID::Struct* mutable_struct_value();
+  void set_allocated_struct_value(::PROTOBUF_NAMESPACE_ID::Struct* struct_value);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Struct& _internal_struct_value() const;
+  ::PROTOBUF_NAMESPACE_ID::Struct* _internal_mutable_struct_value();
+  public:
+  void unsafe_arena_set_allocated_struct_value(
+      ::PROTOBUF_NAMESPACE_ID::Struct* struct_value);
+  ::PROTOBUF_NAMESPACE_ID::Struct* unsafe_arena_release_struct_value();
+
+  // .google.protobuf.ListValue list_value = 6;
+  bool has_list_value() const;
+  private:
+  bool _internal_has_list_value() const;
+  public:
+  void clear_list_value();
+  const ::PROTOBUF_NAMESPACE_ID::ListValue& list_value() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::ListValue* release_list_value();
+  ::PROTOBUF_NAMESPACE_ID::ListValue* mutable_list_value();
+  void set_allocated_list_value(::PROTOBUF_NAMESPACE_ID::ListValue* list_value);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::ListValue& _internal_list_value() const;
+  ::PROTOBUF_NAMESPACE_ID::ListValue* _internal_mutable_list_value();
+  public:
+  void unsafe_arena_set_allocated_list_value(
+      ::PROTOBUF_NAMESPACE_ID::ListValue* list_value);
+  ::PROTOBUF_NAMESPACE_ID::ListValue* unsafe_arena_release_list_value();
+
+  void clear_kind();
+  KindCase kind_case() const;
+  // @@protoc_insertion_point(class_scope:google.protobuf.Value)
+ private:
+  class _Internal;
+  void set_has_null_value();
+  void set_has_number_value();
+  void set_has_string_value();
+  void set_has_bool_value();
+  void set_has_struct_value();
+  void set_has_list_value();
+
+  inline bool has_kind() const;
+  inline void clear_has_kind();
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    union KindUnion {
+      constexpr KindUnion() : _constinit_{} {}
+        ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized _constinit_;
+      int null_value_;
+      double number_value_;
+      ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr string_value_;
+      bool bool_value_;
+      ::PROTOBUF_NAMESPACE_ID::Struct* struct_value_;
+      ::PROTOBUF_NAMESPACE_ID::ListValue* list_value_;
+    } kind_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+    uint32_t _oneof_case_[1];
+
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT ListValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ListValue) */ {
+ public:
+  inline ListValue() : ListValue(nullptr) {}
+  ~ListValue() override;
+  explicit PROTOBUF_CONSTEXPR ListValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  ListValue(const ListValue& from);
+  ListValue(ListValue&& from) noexcept
+    : ListValue() {
+    *this = ::std::move(from);
+  }
+
+  inline ListValue& operator=(const ListValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline ListValue& operator=(ListValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const ListValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const ListValue* internal_default_instance() {
+    return reinterpret_cast<const ListValue*>(
+               &_ListValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(ListValue& a, ListValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(ListValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ListValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  ListValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<ListValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const ListValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const ListValue& from) {
+    ListValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(ListValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.ListValue";
+  }
+  protected:
+  explicit ListValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValuesFieldNumber = 1,
+  };
+  // repeated .google.protobuf.Value values = 1;
+  int values_size() const;
+  private:
+  int _internal_values_size() const;
+  public:
+  void clear_values();
+  ::PROTOBUF_NAMESPACE_ID::Value* mutable_values(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >*
+      mutable_values();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Value& _internal_values(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Value* _internal_add_values();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Value& values(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Value* add_values();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >&
+      values() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ListValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value > values_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// Struct
+
+// map<string, .google.protobuf.Value> fields = 1;
+inline int Struct::_internal_fields_size() const {
+  return _impl_.fields_.size();
+}
+inline int Struct::fields_size() const {
+  return _internal_fields_size();
+}
+inline void Struct::clear_fields() {
+  _impl_.fields_.Clear();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+Struct::_internal_fields() const {
+  return _impl_.fields_.GetMap();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >&
+Struct::fields() const {
+  // @@protoc_insertion_point(field_map:google.protobuf.Struct.fields)
+  return _internal_fields();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+Struct::_internal_mutable_fields() {
+  return _impl_.fields_.MutableMap();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >*
+Struct::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_map:google.protobuf.Struct.fields)
+  return _internal_mutable_fields();
+}
+
+// -------------------------------------------------------------------
+
+// Value
+
+// .google.protobuf.NullValue null_value = 1;
+inline bool Value::_internal_has_null_value() const {
+  return kind_case() == kNullValue;
+}
+inline bool Value::has_null_value() const {
+  return _internal_has_null_value();
+}
+inline void Value::set_has_null_value() {
+  _impl_._oneof_case_[0] = kNullValue;
+}
+inline void Value::clear_null_value() {
+  if (_internal_has_null_value()) {
+    _impl_.kind_.null_value_ = 0;
+    clear_has_kind();
+  }
+}
+inline ::PROTOBUF_NAMESPACE_ID::NullValue Value::_internal_null_value() const {
+  if (_internal_has_null_value()) {
+    return static_cast< ::PROTOBUF_NAMESPACE_ID::NullValue >(_impl_.kind_.null_value_);
+  }
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::NullValue >(0);
+}
+inline ::PROTOBUF_NAMESPACE_ID::NullValue Value::null_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.null_value)
+  return _internal_null_value();
+}
+inline void Value::_internal_set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value) {
+  if (!_internal_has_null_value()) {
+    clear_kind();
+    set_has_null_value();
+  }
+  _impl_.kind_.null_value_ = value;
+}
+inline void Value::set_null_value(::PROTOBUF_NAMESPACE_ID::NullValue value) {
+  _internal_set_null_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.null_value)
+}
+
+// double number_value = 2;
+inline bool Value::_internal_has_number_value() const {
+  return kind_case() == kNumberValue;
+}
+inline bool Value::has_number_value() const {
+  return _internal_has_number_value();
+}
+inline void Value::set_has_number_value() {
+  _impl_._oneof_case_[0] = kNumberValue;
+}
+inline void Value::clear_number_value() {
+  if (_internal_has_number_value()) {
+    _impl_.kind_.number_value_ = 0;
+    clear_has_kind();
+  }
+}
+inline double Value::_internal_number_value() const {
+  if (_internal_has_number_value()) {
+    return _impl_.kind_.number_value_;
+  }
+  return 0;
+}
+inline void Value::_internal_set_number_value(double value) {
+  if (!_internal_has_number_value()) {
+    clear_kind();
+    set_has_number_value();
+  }
+  _impl_.kind_.number_value_ = value;
+}
+inline double Value::number_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.number_value)
+  return _internal_number_value();
+}
+inline void Value::set_number_value(double value) {
+  _internal_set_number_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.number_value)
+}
+
+// string string_value = 3;
+inline bool Value::_internal_has_string_value() const {
+  return kind_case() == kStringValue;
+}
+inline bool Value::has_string_value() const {
+  return _internal_has_string_value();
+}
+inline void Value::set_has_string_value() {
+  _impl_._oneof_case_[0] = kStringValue;
+}
+inline void Value::clear_string_value() {
+  if (_internal_has_string_value()) {
+    _impl_.kind_.string_value_.Destroy();
+    clear_has_kind();
+  }
+}
+inline const std::string& Value::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.string_value)
+  return _internal_string_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline void Value::set_string_value(ArgT0&& arg0, ArgT... args) {
+  if (!_internal_has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitDefault();
+  }
+  _impl_.kind_.string_value_.Set( static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
+}
+inline std::string* Value::mutable_string_value() {
+  std::string* _s = _internal_mutable_string_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.string_value)
+  return _s;
+}
+inline const std::string& Value::_internal_string_value() const {
+  if (_internal_has_string_value()) {
+    return _impl_.kind_.string_value_.Get();
+  }
+  return ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited();
+}
+inline void Value::_internal_set_string_value(const std::string& value) {
+  if (!_internal_has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitDefault();
+  }
+  _impl_.kind_.string_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Value::_internal_mutable_string_value() {
+  if (!_internal_has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitDefault();
+  }
+  return _impl_.kind_.string_value_.Mutable(      GetArenaForAllocation());
+}
+inline std::string* Value::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value)
+  if (_internal_has_string_value()) {
+    clear_has_kind();
+    return _impl_.kind_.string_value_.Release();
+  } else {
+    return nullptr;
+  }
+}
+inline void Value::set_allocated_string_value(std::string* string_value) {
+  if (has_kind()) {
+    clear_kind();
+  }
+  if (string_value != nullptr) {
+    set_has_string_value();
+    _impl_.kind_.string_value_.InitAllocated(string_value, GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.string_value)
+}
+
+// bool bool_value = 4;
+inline bool Value::_internal_has_bool_value() const {
+  return kind_case() == kBoolValue;
+}
+inline bool Value::has_bool_value() const {
+  return _internal_has_bool_value();
+}
+inline void Value::set_has_bool_value() {
+  _impl_._oneof_case_[0] = kBoolValue;
+}
+inline void Value::clear_bool_value() {
+  if (_internal_has_bool_value()) {
+    _impl_.kind_.bool_value_ = false;
+    clear_has_kind();
+  }
+}
+inline bool Value::_internal_bool_value() const {
+  if (_internal_has_bool_value()) {
+    return _impl_.kind_.bool_value_;
+  }
+  return false;
+}
+inline void Value::_internal_set_bool_value(bool value) {
+  if (!_internal_has_bool_value()) {
+    clear_kind();
+    set_has_bool_value();
+  }
+  _impl_.kind_.bool_value_ = value;
+}
+inline bool Value::bool_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.bool_value)
+  return _internal_bool_value();
+}
+inline void Value::set_bool_value(bool value) {
+  _internal_set_bool_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.bool_value)
+}
+
+// .google.protobuf.Struct struct_value = 5;
+inline bool Value::_internal_has_struct_value() const {
+  return kind_case() == kStructValue;
+}
+inline bool Value::has_struct_value() const {
+  return _internal_has_struct_value();
+}
+inline void Value::set_has_struct_value() {
+  _impl_._oneof_case_[0] = kStructValue;
+}
+inline void Value::clear_struct_value() {
+  if (_internal_has_struct_value()) {
+    if (GetArenaForAllocation() == nullptr) {
+      delete _impl_.kind_.struct_value_;
+    }
+    clear_has_kind();
+  }
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::release_struct_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value)
+  if (_internal_has_struct_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::Struct* temp = _impl_.kind_.struct_value_;
+    if (GetArenaForAllocation() != nullptr) {
+      temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+    }
+    _impl_.kind_.struct_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Struct& Value::_internal_struct_value() const {
+  return _internal_has_struct_value()
+      ? *_impl_.kind_.struct_value_
+      : reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::Struct&>(::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Struct& Value::struct_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.struct_value)
+  return _internal_struct_value();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::unsafe_arena_release_struct_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.Value.struct_value)
+  if (_internal_has_struct_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::Struct* temp = _impl_.kind_.struct_value_;
+    _impl_.kind_.struct_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline void Value::unsafe_arena_set_allocated_struct_value(::PROTOBUF_NAMESPACE_ID::Struct* struct_value) {
+  clear_kind();
+  if (struct_value) {
+    set_has_struct_value();
+    _impl_.kind_.struct_value_ = struct_value;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Value.struct_value)
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::_internal_mutable_struct_value() {
+  if (!_internal_has_struct_value()) {
+    clear_kind();
+    set_has_struct_value();
+    _impl_.kind_.struct_value_ = CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct >(GetArenaForAllocation());
+  }
+  return _impl_.kind_.struct_value_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Struct* Value::mutable_struct_value() {
+  ::PROTOBUF_NAMESPACE_ID::Struct* _msg = _internal_mutable_struct_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.struct_value)
+  return _msg;
+}
+
+// .google.protobuf.ListValue list_value = 6;
+inline bool Value::_internal_has_list_value() const {
+  return kind_case() == kListValue;
+}
+inline bool Value::has_list_value() const {
+  return _internal_has_list_value();
+}
+inline void Value::set_has_list_value() {
+  _impl_._oneof_case_[0] = kListValue;
+}
+inline void Value::clear_list_value() {
+  if (_internal_has_list_value()) {
+    if (GetArenaForAllocation() == nullptr) {
+      delete _impl_.kind_.list_value_;
+    }
+    clear_has_kind();
+  }
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::release_list_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value)
+  if (_internal_has_list_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::ListValue* temp = _impl_.kind_.list_value_;
+    if (GetArenaForAllocation() != nullptr) {
+      temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+    }
+    _impl_.kind_.list_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ListValue& Value::_internal_list_value() const {
+  return _internal_has_list_value()
+      ? *_impl_.kind_.list_value_
+      : reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::ListValue&>(::PROTOBUF_NAMESPACE_ID::_ListValue_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::ListValue& Value::list_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.list_value)
+  return _internal_list_value();
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::unsafe_arena_release_list_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.Value.list_value)
+  if (_internal_has_list_value()) {
+    clear_has_kind();
+    ::PROTOBUF_NAMESPACE_ID::ListValue* temp = _impl_.kind_.list_value_;
+    _impl_.kind_.list_value_ = nullptr;
+    return temp;
+  } else {
+    return nullptr;
+  }
+}
+inline void Value::unsafe_arena_set_allocated_list_value(::PROTOBUF_NAMESPACE_ID::ListValue* list_value) {
+  clear_kind();
+  if (list_value) {
+    set_has_list_value();
+    _impl_.kind_.list_value_ = list_value;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Value.list_value)
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::_internal_mutable_list_value() {
+  if (!_internal_has_list_value()) {
+    clear_kind();
+    set_has_list_value();
+    _impl_.kind_.list_value_ = CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ListValue >(GetArenaForAllocation());
+  }
+  return _impl_.kind_.list_value_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::ListValue* Value::mutable_list_value() {
+  ::PROTOBUF_NAMESPACE_ID::ListValue* _msg = _internal_mutable_list_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.list_value)
+  return _msg;
+}
+
+inline bool Value::has_kind() const {
+  return kind_case() != KIND_NOT_SET;
+}
+inline void Value::clear_has_kind() {
+  _impl_._oneof_case_[0] = KIND_NOT_SET;
+}
+inline Value::KindCase Value::kind_case() const {
+  return Value::KindCase(_impl_._oneof_case_[0]);
+}
+// -------------------------------------------------------------------
+
+// ListValue
+
+// repeated .google.protobuf.Value values = 1;
+inline int ListValue::_internal_values_size() const {
+  return _impl_.values_.size();
+}
+inline int ListValue::values_size() const {
+  return _internal_values_size();
+}
+inline void ListValue::clear_values() {
+  _impl_.values_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Value* ListValue::mutable_values(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ListValue.values)
+  return _impl_.values_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >*
+ListValue::mutable_values() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ListValue.values)
+  return &_impl_.values_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Value& ListValue::_internal_values(int index) const {
+  return _impl_.values_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Value& ListValue::values(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ListValue.values)
+  return _internal_values(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Value* ListValue::_internal_add_values() {
+  return _impl_.values_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Value* ListValue::add_values() {
+  ::PROTOBUF_NAMESPACE_ID::Value* _add = _internal_add_values();
+  // @@protoc_insertion_point(field_add:google.protobuf.ListValue.values)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Value >&
+ListValue::values() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values)
+  return _impl_.values_;
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::NullValue> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::NullValue>() {
+  return ::PROTOBUF_NAMESPACE_ID::NullValue_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fstruct_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/bytestream.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/bytestream.h
new file mode 100644
index 0000000..c7a48de
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/bytestream.h
@@ -0,0 +1,351 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file declares the ByteSink and ByteSource abstract interfaces. These
+// interfaces represent objects that consume (ByteSink) or produce (ByteSource)
+// a sequence of bytes. Using these abstract interfaces in your APIs can help
+// make your code work with a variety of input and output types.
+//
+// This file also declares the following commonly used implementations of these
+// interfaces.
+//
+//   ByteSink:
+//      UncheckedArrayByteSink  Writes to an array, without bounds checking
+//      CheckedArrayByteSink    Writes to an array, with bounds checking
+//      GrowingArrayByteSink    Allocates and writes to a growable buffer
+//      StringByteSink          Writes to an STL string
+//      NullByteSink            Consumes a never-ending stream of bytes
+//
+//   ByteSource:
+//      ArrayByteSource         Reads from an array or string/StringPiece
+//      LimitedByteSource       Limits the number of bytes read from an
+
+#ifndef GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
+#define GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
+
+#include <stddef.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <google/protobuf/port_def.inc>
+
+class CordByteSink;
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+// An abstract interface for an object that consumes a sequence of bytes. This
+// interface offers a way to append data as well as a Flush() function.
+//
+// Example:
+//
+//   string my_data;
+//   ...
+//   ByteSink* sink = ...
+//   sink->Append(my_data.data(), my_data.size());
+//   sink->Flush();
+//
+class PROTOBUF_EXPORT ByteSink {
+ public:
+  ByteSink() {}
+  virtual ~ByteSink() {}
+
+  // Appends the "n" bytes starting at "bytes".
+  virtual void Append(const char* bytes, size_t n) = 0;
+
+  // Flushes internal buffers. The default implementation does nothing. ByteSink
+  // subclasses may use internal buffers that require calling Flush() at the end
+  // of the stream.
+  virtual void Flush();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSink);
+};
+
+// An abstract interface for an object that produces a fixed-size sequence of
+// bytes.
+//
+// Example:
+//
+//   ByteSource* source = ...
+//   while (source->Available() > 0) {
+//     StringPiece data = source->Peek();
+//     ... do something with "data" ...
+//     source->Skip(data.length());
+//   }
+//
+class PROTOBUF_EXPORT ByteSource {
+ public:
+  ByteSource() {}
+  virtual ~ByteSource() {}
+
+  // Returns the number of bytes left to read from the source. Available()
+  // should decrease by N each time Skip(N) is called. Available() may not
+  // increase. Available() returning 0 indicates that the ByteSource is
+  // exhausted.
+  //
+  // Note: Size() may have been a more appropriate name as it's more
+  //       indicative of the fixed-size nature of a ByteSource.
+  virtual size_t Available() const = 0;
+
+  // Returns a StringPiece of the next contiguous region of the source. Does not
+  // reposition the source. The returned region is empty iff Available() == 0.
+  //
+  // The returned region is valid until the next call to Skip() or until this
+  // object is destroyed, whichever occurs first.
+  //
+  // The length of the returned StringPiece will be <= Available().
+  virtual StringPiece Peek() = 0;
+
+  // Skips the next n bytes. Invalidates any StringPiece returned by a previous
+  // call to Peek().
+  //
+  // REQUIRES: Available() >= n
+  virtual void Skip(size_t n) = 0;
+
+  // Writes the next n bytes in this ByteSource to the given ByteSink, and
+  // advances this ByteSource past the copied bytes. The default implementation
+  // of this method just copies the bytes normally, but subclasses might
+  // override CopyTo to optimize certain cases.
+  //
+  // REQUIRES: Available() >= n
+  virtual void CopyTo(ByteSink* sink, size_t n);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSource);
+};
+
+//
+// Some commonly used implementations of ByteSink
+//
+
+// Implementation of ByteSink that writes to an unsized byte array. No
+// bounds-checking is performed--it is the caller's responsibility to ensure
+// that the destination array is large enough.
+//
+// Example:
+//
+//   char buf[10];
+//   UncheckedArrayByteSink sink(buf);
+//   sink.Append("hi", 2);    // OK
+//   sink.Append(data, 100);  // WOOPS! Overflows buf[10].
+//
+class PROTOBUF_EXPORT UncheckedArrayByteSink : public ByteSink {
+ public:
+  explicit UncheckedArrayByteSink(char* dest) : dest_(dest) {}
+  virtual void Append(const char* data, size_t n) override;
+
+  // Returns the current output pointer so that a caller can see how many bytes
+  // were produced.
+  //
+  // Note: this method is not part of the ByteSink interface.
+  char* CurrentDestination() const { return dest_; }
+
+ private:
+  char* dest_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UncheckedArrayByteSink);
+};
+
+// Implementation of ByteSink that writes to a sized byte array. This sink will
+// not write more than "capacity" bytes to outbuf. Once "capacity" bytes are
+// appended, subsequent bytes will be ignored and Overflowed() will return true.
+// Overflowed() does not cause a runtime error (i.e., it does not CHECK fail).
+//
+// Example:
+//
+//   char buf[10];
+//   CheckedArrayByteSink sink(buf, 10);
+//   sink.Append("hi", 2);    // OK
+//   sink.Append(data, 100);  // Will only write 8 more bytes
+//
+class PROTOBUF_EXPORT CheckedArrayByteSink : public ByteSink {
+ public:
+  CheckedArrayByteSink(char* outbuf, size_t capacity);
+  virtual void Append(const char* bytes, size_t n) override;
+
+  // Returns the number of bytes actually written to the sink.
+  size_t NumberOfBytesWritten() const { return size_; }
+
+  // Returns true if any bytes were discarded, i.e., if there was an
+  // attempt to write more than 'capacity' bytes.
+  bool Overflowed() const { return overflowed_; }
+
+ private:
+  char* outbuf_;
+  const size_t capacity_;
+  size_t size_;
+  bool overflowed_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CheckedArrayByteSink);
+};
+
+// Implementation of ByteSink that allocates an internal buffer (a char array)
+// and expands it as needed to accommodate appended data (similar to a string),
+// and allows the caller to take ownership of the internal buffer via the
+// GetBuffer() method. The buffer returned from GetBuffer() must be deleted by
+// the caller with delete[]. GetBuffer() also sets the internal buffer to be
+// empty, and subsequent appends to the sink will create a new buffer. The
+// destructor will free the internal buffer if GetBuffer() was not called.
+//
+// Example:
+//
+//   GrowingArrayByteSink sink(10);
+//   sink.Append("hi", 2);
+//   sink.Append(data, n);
+//   const char* buf = sink.GetBuffer();  // Ownership transferred
+//   delete[] buf;
+//
+class PROTOBUF_EXPORT GrowingArrayByteSink : public strings::ByteSink {
+ public:
+  explicit GrowingArrayByteSink(size_t estimated_size);
+  virtual ~GrowingArrayByteSink();
+  virtual void Append(const char* bytes, size_t n) override;
+
+  // Returns the allocated buffer, and sets nbytes to its size. The caller takes
+  // ownership of the buffer and must delete it with delete[].
+  char* GetBuffer(size_t* nbytes);
+
+ private:
+  void Expand(size_t amount);
+  void ShrinkToFit();
+
+  size_t capacity_;
+  char* buf_;
+  size_t size_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GrowingArrayByteSink);
+};
+
+// Implementation of ByteSink that appends to the given string.
+// Existing contents of "dest" are not modified; new data is appended.
+//
+// Example:
+//
+//   string dest = "Hello ";
+//   StringByteSink sink(&dest);
+//   sink.Append("World", 5);
+//   assert(dest == "Hello World");
+//
+class PROTOBUF_EXPORT StringByteSink : public ByteSink {
+ public:
+  explicit StringByteSink(std::string* dest) : dest_(dest) {}
+  virtual void Append(const char* data, size_t n) override;
+
+ private:
+  std::string* dest_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringByteSink);
+};
+
+// Implementation of ByteSink that discards all data.
+//
+// Example:
+//
+//   NullByteSink sink;
+//   sink.Append(data, data.size());  // All data ignored.
+//
+class PROTOBUF_EXPORT NullByteSink : public ByteSink {
+ public:
+  NullByteSink() {}
+  void Append(const char* /*data*/, size_t /*n*/) override {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NullByteSink);
+};
+
+//
+// Some commonly used implementations of ByteSource
+//
+
+// Implementation of ByteSource that reads from a StringPiece.
+//
+// Example:
+//
+//   string data = "Hello";
+//   ArrayByteSource source(data);
+//   assert(source.Available() == 5);
+//   assert(source.Peek() == "Hello");
+//
+class PROTOBUF_EXPORT ArrayByteSource : public ByteSource {
+ public:
+  explicit ArrayByteSource(StringPiece s) : input_(s) {}
+
+  virtual size_t Available() const override;
+  virtual StringPiece Peek() override;
+  virtual void Skip(size_t n) override;
+
+ private:
+  StringPiece   input_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayByteSource);
+};
+
+// Implementation of ByteSource that wraps another ByteSource, limiting the
+// number of bytes returned.
+//
+// The caller maintains ownership of the underlying source, and may not use the
+// underlying source while using the LimitByteSource object.  The underlying
+// source's pointer is advanced by n bytes every time this LimitByteSource
+// object is advanced by n.
+//
+// Example:
+//
+//   string data = "Hello World";
+//   ArrayByteSource abs(data);
+//   assert(abs.Available() == data.size());
+//
+//   LimitByteSource limit(abs, 5);
+//   assert(limit.Available() == 5);
+//   assert(limit.Peek() == "Hello");
+//
+class PROTOBUF_EXPORT LimitByteSource : public ByteSource {
+ public:
+  // Returns at most "limit" bytes from "source".
+  LimitByteSource(ByteSource* source, size_t limit);
+
+  virtual size_t Available() const override;
+  virtual StringPiece Peek() override;
+  virtual void Skip(size_t n) override;
+
+  // We override CopyTo so that we can forward to the underlying source, in
+  // case it has an efficient implementation of CopyTo.
+  virtual void CopyTo(ByteSink* sink, size_t n) override;
+
+ private:
+  ByteSource* source_;
+  size_t limit_;
+};
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/callback.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/callback.h
new file mode 100644
index 0000000..43d546d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/callback.h
@@ -0,0 +1,583 @@
+#ifndef GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
+#define GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
+
+#include <type_traits>
+
+#include <google/protobuf/stubs/macros.h>
+
+#include <google/protobuf/port_def.inc>
+
+// ===================================================================
+// emulates google3/base/callback.h
+
+namespace google {
+namespace protobuf {
+
+// Abstract interface for a callback.  When calling an RPC, you must provide
+// a Closure to call when the procedure completes.  See the Service interface
+// in service.h.
+//
+// To automatically construct a Closure which calls a particular function or
+// method with a particular set of parameters, use the NewCallback() function.
+// Example:
+//   void FooDone(const FooResponse* response) {
+//     ...
+//   }
+//
+//   void CallFoo() {
+//     ...
+//     // When done, call FooDone() and pass it a pointer to the response.
+//     Closure* callback = NewCallback(&FooDone, response);
+//     // Make the call.
+//     service->Foo(controller, request, response, callback);
+//   }
+//
+// Example that calls a method:
+//   class Handler {
+//    public:
+//     ...
+//
+//     void FooDone(const FooResponse* response) {
+//       ...
+//     }
+//
+//     void CallFoo() {
+//       ...
+//       // When done, call FooDone() and pass it a pointer to the response.
+//       Closure* callback = NewCallback(this, &Handler::FooDone, response);
+//       // Make the call.
+//       service->Foo(controller, request, response, callback);
+//     }
+//   };
+//
+// Currently NewCallback() supports binding zero, one, or two arguments.
+//
+// Callbacks created with NewCallback() automatically delete themselves when
+// executed.  They should be used when a callback is to be called exactly
+// once (usually the case with RPC callbacks).  If a callback may be called
+// a different number of times (including zero), create it with
+// NewPermanentCallback() instead.  You are then responsible for deleting the
+// callback (using the "delete" keyword as normal).
+//
+// Note that NewCallback() is a bit touchy regarding argument types.  Generally,
+// the values you provide for the parameter bindings must exactly match the
+// types accepted by the callback function.  For example:
+//   void Foo(std::string s);
+//   NewCallback(&Foo, "foo");          // WON'T WORK:  const char* != string
+//   NewCallback(&Foo, std::string("foo"));  // WORKS
+// Also note that the arguments cannot be references:
+//   void Foo(const std::string& s);
+//   std::string my_str;
+//   NewCallback(&Foo, my_str);  // WON'T WORK:  Can't use references.
+// However, correctly-typed pointers will work just fine.
+class PROTOBUF_EXPORT Closure {
+ public:
+  Closure() {}
+  virtual ~Closure();
+
+  virtual void Run() = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
+};
+
+template<typename R>
+class ResultCallback {
+ public:
+  ResultCallback() {}
+  virtual ~ResultCallback() {}
+
+  virtual R Run() = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback);
+};
+
+template <typename R, typename A1>
+class PROTOBUF_EXPORT ResultCallback1 {
+ public:
+  ResultCallback1() {}
+  virtual ~ResultCallback1() {}
+
+  virtual R Run(A1) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback1);
+};
+
+template <typename R, typename A1, typename A2>
+class PROTOBUF_EXPORT ResultCallback2 {
+ public:
+  ResultCallback2() {}
+  virtual ~ResultCallback2() {}
+
+  virtual R Run(A1,A2) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback2);
+};
+
+namespace internal {
+
+class PROTOBUF_EXPORT FunctionClosure0 : public Closure {
+ public:
+  typedef void (*FunctionType)();
+
+  FunctionClosure0(FunctionType function, bool self_deleting)
+    : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionClosure0();
+
+  void Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    function_();
+    if (needs_delete) delete this;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template <typename Class>
+class MethodClosure0 : public Closure {
+ public:
+  typedef void (Class::*MethodType)();
+
+  MethodClosure0(Class* object, MethodType method, bool self_deleting)
+    : object_(object), method_(method), self_deleting_(self_deleting) {}
+  ~MethodClosure0() {}
+
+  void Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    (object_->*method_)();
+    if (needs_delete) delete this;
+  }
+
+ private:
+  Class* object_;
+  MethodType method_;
+  bool self_deleting_;
+};
+
+template <typename Arg1>
+class FunctionClosure1 : public Closure {
+ public:
+  typedef void (*FunctionType)(Arg1 arg1);
+
+  FunctionClosure1(FunctionType function, bool self_deleting,
+                   Arg1 arg1)
+    : function_(function), self_deleting_(self_deleting),
+      arg1_(arg1) {}
+  ~FunctionClosure1() {}
+
+  void Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    function_(arg1_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  Arg1 arg1_;
+};
+
+template <typename Class, typename Arg1>
+class MethodClosure1 : public Closure {
+ public:
+  typedef void (Class::*MethodType)(Arg1 arg1);
+
+  MethodClosure1(Class* object, MethodType method, bool self_deleting,
+                 Arg1 arg1)
+    : object_(object), method_(method), self_deleting_(self_deleting),
+      arg1_(arg1) {}
+  ~MethodClosure1() {}
+
+  void Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    (object_->*method_)(arg1_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  Class* object_;
+  MethodType method_;
+  bool self_deleting_;
+  Arg1 arg1_;
+};
+
+template <typename Arg1, typename Arg2>
+class FunctionClosure2 : public Closure {
+ public:
+  typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2);
+
+  FunctionClosure2(FunctionType function, bool self_deleting,
+                   Arg1 arg1, Arg2 arg2)
+    : function_(function), self_deleting_(self_deleting),
+      arg1_(arg1), arg2_(arg2) {}
+  ~FunctionClosure2() {}
+
+  void Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    function_(arg1_, arg2_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+};
+
+template <typename Class, typename Arg1, typename Arg2>
+class MethodClosure2 : public Closure {
+ public:
+  typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2);
+
+  MethodClosure2(Class* object, MethodType method, bool self_deleting,
+                 Arg1 arg1, Arg2 arg2)
+    : object_(object), method_(method), self_deleting_(self_deleting),
+      arg1_(arg1), arg2_(arg2) {}
+  ~MethodClosure2() {}
+
+  void Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    (object_->*method_)(arg1_, arg2_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  Class* object_;
+  MethodType method_;
+  bool self_deleting_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+};
+
+template<typename R>
+class FunctionResultCallback_0_0 : public ResultCallback<R> {
+ public:
+  typedef R (*FunctionType)();
+
+  FunctionResultCallback_0_0(FunctionType function, bool self_deleting)
+      : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionResultCallback_0_0() {}
+
+  R Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_();
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template<typename R, typename P1>
+class FunctionResultCallback_1_0 : public ResultCallback<R> {
+ public:
+  typedef R (*FunctionType)(P1);
+
+  FunctionResultCallback_1_0(FunctionType function, bool self_deleting,
+                             P1 p1)
+      : function_(function), self_deleting_(self_deleting), p1_(p1) {}
+  ~FunctionResultCallback_1_0() {}
+
+  R Run() override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(p1_);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  P1 p1_;
+};
+
+template<typename R, typename Arg1>
+class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> {
+ public:
+  typedef R (*FunctionType)(Arg1 arg1);
+
+  FunctionResultCallback_0_1(FunctionType function, bool self_deleting)
+      : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionResultCallback_0_1() {}
+
+  R Run(Arg1 a1) override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(a1);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template<typename R, typename P1, typename A1>
+class FunctionResultCallback_1_1 : public ResultCallback1<R, A1> {
+ public:
+  typedef R (*FunctionType)(P1, A1);
+
+  FunctionResultCallback_1_1(FunctionType function, bool self_deleting,
+                             P1 p1)
+      : function_(function), self_deleting_(self_deleting), p1_(p1) {}
+  ~FunctionResultCallback_1_1() {}
+
+  R Run(A1 a1) override {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(p1_, a1);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  P1 p1_;
+};
+
+template <typename T>
+struct InternalConstRef {
+  typedef typename std::remove_reference<T>::type base_type;
+  typedef const base_type& type;
+};
+
+template<typename R, typename T>
+class MethodResultCallback_0_0 : public ResultCallback<R> {
+ public:
+  typedef R (T::*MethodType)();
+  MethodResultCallback_0_0(T* object, MethodType method, bool self_deleting)
+      : object_(object),
+        method_(method),
+        self_deleting_(self_deleting) {}
+  ~MethodResultCallback_0_0() {}
+
+  R Run() {
+    bool needs_delete = self_deleting_;
+    R result = (object_->*method_)();
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  T* object_;
+  MethodType method_;
+  bool self_deleting_;
+};
+
+template <typename R, typename T, typename P1, typename P2, typename P3,
+          typename P4, typename P5, typename P6, typename A1, typename A2>
+class MethodResultCallback_6_2 : public ResultCallback2<R, A1, A2> {
+ public:
+  typedef R (T::*MethodType)(P1, P2, P3, P4, P5, P6, A1, A2);
+  MethodResultCallback_6_2(T* object, MethodType method, bool self_deleting,
+                           P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
+      : object_(object),
+        method_(method),
+        self_deleting_(self_deleting),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4),
+        p5_(p5),
+        p6_(p6) {}
+  ~MethodResultCallback_6_2() {}
+
+  R Run(A1 a1, A2 a2) override {
+    bool needs_delete = self_deleting_;
+    R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, p6_, a1, a2);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  T* object_;
+  MethodType method_;
+  bool self_deleting_;
+  typename std::remove_reference<P1>::type p1_;
+  typename std::remove_reference<P2>::type p2_;
+  typename std::remove_reference<P3>::type p3_;
+  typename std::remove_reference<P4>::type p4_;
+  typename std::remove_reference<P5>::type p5_;
+  typename std::remove_reference<P6>::type p6_;
+};
+
+}  // namespace internal
+
+// See Closure.
+inline Closure* NewCallback(void (*function)()) {
+  return new internal::FunctionClosure0(function, true);
+}
+
+// See Closure.
+inline Closure* NewPermanentCallback(void (*function)()) {
+  return new internal::FunctionClosure0(function, false);
+}
+
+// See Closure.
+template <typename Class>
+inline Closure* NewCallback(Class* object, void (Class::*method)()) {
+  return new internal::MethodClosure0<Class>(object, method, true);
+}
+
+// See Closure.
+template <typename Class>
+inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) {
+  return new internal::MethodClosure0<Class>(object, method, false);
+}
+
+// See Closure.
+template <typename Arg1>
+inline Closure* NewCallback(void (*function)(Arg1),
+                            Arg1 arg1) {
+  return new internal::FunctionClosure1<Arg1>(function, true, arg1);
+}
+
+// See Closure.
+template <typename Arg1>
+inline Closure* NewPermanentCallback(void (*function)(Arg1),
+                                     Arg1 arg1) {
+  return new internal::FunctionClosure1<Arg1>(function, false, arg1);
+}
+
+// See Closure.
+template <typename Class, typename Arg1>
+inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1),
+                            Arg1 arg1) {
+  return new internal::MethodClosure1<Class, Arg1>(object, method, true, arg1);
+}
+
+// See Closure.
+template <typename Class, typename Arg1>
+inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1),
+                                     Arg1 arg1) {
+  return new internal::MethodClosure1<Class, Arg1>(object, method, false, arg1);
+}
+
+// See Closure.
+template <typename Arg1, typename Arg2>
+inline Closure* NewCallback(void (*function)(Arg1, Arg2),
+                            Arg1 arg1, Arg2 arg2) {
+  return new internal::FunctionClosure2<Arg1, Arg2>(
+    function, true, arg1, arg2);
+}
+
+// See Closure.
+template <typename Arg1, typename Arg2>
+inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2),
+                                     Arg1 arg1, Arg2 arg2) {
+  return new internal::FunctionClosure2<Arg1, Arg2>(
+    function, false, arg1, arg2);
+}
+
+// See Closure.
+template <typename Class, typename Arg1, typename Arg2>
+inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
+                            Arg1 arg1, Arg2 arg2) {
+  return new internal::MethodClosure2<Class, Arg1, Arg2>(
+    object, method, true, arg1, arg2);
+}
+
+// See Closure.
+template <typename Class, typename Arg1, typename Arg2>
+inline Closure* NewPermanentCallback(
+    Class* object, void (Class::*method)(Arg1, Arg2),
+    Arg1 arg1, Arg2 arg2) {
+  return new internal::MethodClosure2<Class, Arg1, Arg2>(
+    object, method, false, arg1, arg2);
+}
+
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewCallback(R (*function)()) {
+  return new internal::FunctionResultCallback_0_0<R>(function, true);
+}
+
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewPermanentCallback(R (*function)()) {
+  return new internal::FunctionResultCallback_0_0<R>(function, false);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) {
+  return new internal::FunctionResultCallback_1_0<R, P1>(
+      function, true, p1);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewPermanentCallback(
+    R (*function)(P1), P1 p1) {
+  return new internal::FunctionResultCallback_1_0<R, P1>(
+      function, false, p1);
+}
+
+// See ResultCallback1
+template<typename R, typename A1>
+inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) {
+  return new internal::FunctionResultCallback_0_1<R, A1>(function, true);
+}
+
+// See ResultCallback1
+template<typename R, typename A1>
+inline ResultCallback1<R, A1>* NewPermanentCallback(R (*function)(A1)) {
+  return new internal::FunctionResultCallback_0_1<R, A1>(function, false);
+}
+
+// See ResultCallback1
+template<typename R, typename P1, typename A1>
+inline ResultCallback1<R, A1>* NewCallback(R (*function)(P1, A1), P1 p1) {
+  return new internal::FunctionResultCallback_1_1<R, P1, A1>(
+      function, true, p1);
+}
+
+// See ResultCallback1
+template<typename R, typename P1, typename A1>
+inline ResultCallback1<R, A1>* NewPermanentCallback(
+    R (*function)(P1, A1), P1 p1) {
+  return new internal::FunctionResultCallback_1_1<R, P1, A1>(
+      function, false, p1);
+}
+
+// See MethodResultCallback_0_0
+template <typename R, typename T1, typename T2>
+inline ResultCallback<R>* NewPermanentCallback(
+    T1* object, R (T2::*function)()) {
+  return new internal::MethodResultCallback_0_0<R, T1>(object, function, false);
+}
+
+// See MethodResultCallback_6_2
+template <typename R, typename T, typename P1, typename P2, typename P3,
+          typename P4, typename P5, typename P6, typename A1, typename A2>
+inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
+    T* object, R (T::*function)(P1, P2, P3, P4, P5, P6, A1, A2),
+    typename internal::InternalConstRef<P1>::type p1,
+    typename internal::InternalConstRef<P2>::type p2,
+    typename internal::InternalConstRef<P3>::type p3,
+    typename internal::InternalConstRef<P4>::type p4,
+    typename internal::InternalConstRef<P5>::type p5,
+    typename internal::InternalConstRef<P6>::type p6) {
+  return new internal::MethodResultCallback_6_2<R, T, P1, P2, P3, P4, P5, P6,
+                                                A1, A2>(object, function, false,
+                                                        p1, p2, p3, p4, p5, p6);
+}
+
+// A function which does nothing.  Useful for creating no-op callbacks, e.g.:
+//   Closure* nothing = NewCallback(&DoNothing);
+void PROTOBUF_EXPORT DoNothing();
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/casts.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/casts.h
new file mode 100644
index 0000000..ad29dac
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/casts.h
@@ -0,0 +1,138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_CASTS_H__
+#define GOOGLE_PROTOBUF_CASTS_H__
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+#include <type_traits>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertible to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed.  When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo?  It
+// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
+// when you downcast, you should use this macro.  In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not).  In normal mode, we do the efficient static_cast<>
+// instead.  Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+//    This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {                   // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, To>(0);
+  }
+
+#if !defined(NDEBUG) && PROTOBUF_RTTI
+  assert(f == nullptr || dynamic_cast<To>(f) != nullptr);  // RTTI: debug mode only!
+#endif
+  return static_cast<To>(f);
+}
+
+template<typename To, typename From>    // use like this: down_cast<T&>(foo);
+inline To down_cast(From& f) {
+  typedef typename std::remove_reference<To>::type* ToAsPointer;
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, ToAsPointer>(0);
+  }
+
+#if !defined(NDEBUG) && PROTOBUF_RTTI
+  // RTTI: debug mode only!
+  assert(dynamic_cast<ToAsPointer>(&f) != nullptr);
+#endif
+  return *static_cast<ToAsPointer>(&f);
+}
+
+template<typename To, typename From>
+inline To bit_cast(const From& from) {
+  static_assert(sizeof(From) == sizeof(To), "bit_cast_with_different_sizes");
+  To dest;
+  memcpy(&dest, &from, sizeof(dest));
+  return dest;
+}
+
+}  // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::implicit_cast;
+using internal::down_cast;
+using internal::bit_cast;
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_CASTS_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/common.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/common.h
new file mode 100644
index 0000000..0b9fa81
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/common.h
@@ -0,0 +1,197 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda) and others
+//
+// Contains basic types and utilities used by the rest of the library.
+
+#ifndef GOOGLE_PROTOBUF_COMMON_H__
+#define GOOGLE_PROTOBUF_COMMON_H__
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/platform_macros.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+#ifndef PROTOBUF_USE_EXCEPTIONS
+#if defined(_MSC_VER) && defined(_CPPUNWIND)
+  #define PROTOBUF_USE_EXCEPTIONS 1
+#elif defined(__EXCEPTIONS)
+  #define PROTOBUF_USE_EXCEPTIONS 1
+#else
+  #define PROTOBUF_USE_EXCEPTIONS 0
+#endif
+#endif
+
+#if PROTOBUF_USE_EXCEPTIONS
+#include <exception>
+#endif
+#if defined(__APPLE__)
+#include <TargetConditionals.h>  // for TARGET_OS_IPHONE
+#endif
+
+#if defined(__ANDROID__) || defined(GOOGLE_PROTOBUF_OS_ANDROID) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
+#include <pthread.h>
+#endif
+
+#include <google/protobuf/port_def.inc>
+
+namespace std {}
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Some of these constants are macros rather than const ints so that they can
+// be used in #if directives.
+
+// The current version, represented as a single integer to make comparison
+// easier:  major * 10^6 + minor * 10^3 + micro
+#define GOOGLE_PROTOBUF_VERSION 3021012
+
+// A suffix string for alpha, beta or rc releases. Empty for stable releases.
+#define GOOGLE_PROTOBUF_VERSION_SUFFIX ""
+
+// The minimum header version which works with the current version of
+// the library.  This constant should only be used by protoc's C++ code
+// generator.
+static const int kMinHeaderVersionForLibrary = 3021000;
+
+// The minimum protoc version which works with the current version of the
+// headers.
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3021000
+
+// The minimum header version which works with the current version of
+// protoc.  This constant should only be used in VerifyVersion().
+static const int kMinHeaderVersionForProtoc = 3021000;
+
+// Verifies that the headers and libraries are compatible.  Use the macro
+// below to call this.
+void PROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion,
+                                   const char* filename);
+
+// Converts a numeric version number to a string.
+std::string PROTOBUF_EXPORT VersionString(int version);
+
+}  // namespace internal
+
+// Place this macro in your main() function (or somewhere before you attempt
+// to use the protobuf library) to verify that the version you link against
+// matches the headers you compiled against.  If a version mismatch is
+// detected, the process will abort.
+#define GOOGLE_PROTOBUF_VERIFY_VERSION                                    \
+  ::google::protobuf::internal::VerifyVersion(                            \
+    GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION,         \
+    __FILE__)
+
+
+// ===================================================================
+// from google3/util/utf8/public/unilib.h
+
+namespace internal {
+
+// Checks if the buffer contains structurally-valid UTF-8.  Implemented in
+// structurally_valid.cc.
+PROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
+
+inline bool IsStructurallyValidUTF8(StringPiece str) {
+  return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
+}
+
+// Returns initial number of bytes of structurally valid UTF-8.
+PROTOBUF_EXPORT int UTF8SpnStructurallyValid(StringPiece str);
+
+// Coerce UTF-8 byte string in src_str to be
+// a structurally-valid equal-length string by selectively
+// overwriting illegal bytes with replace_char (typically ' ' or '?').
+// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
+// src_str is read-only.
+//
+// Returns pointer to output buffer, src_str.data() if no changes were made,
+//  or idst if some bytes were changed. idst is allocated by the caller
+//  and must be at least as big as src_str
+//
+// Optimized for: all structurally valid and no byte copying is done.
+//
+PROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid(StringPiece str, char* dst,
+                                                    char replace_char);
+
+}  // namespace internal
+
+// This lives in message_lite.h now, but we leave this here for any users that
+// #include common.h and not message_lite.h.
+PROTOBUF_EXPORT void ShutdownProtobufLibrary();
+
+namespace internal {
+
+// Strongly references the given variable such that the linker will be forced
+// to pull in this variable's translation unit.
+template <typename T>
+void StrongReference(const T& var) {
+  auto volatile unused = &var;
+  (void)&unused;  // Use address to avoid an extra load of "unused".
+}
+
+}  // namespace internal
+
+#if PROTOBUF_USE_EXCEPTIONS
+class FatalException : public std::exception {
+ public:
+  FatalException(const char* filename, int line, const std::string& message)
+      : filename_(filename), line_(line), message_(message) {}
+  virtual ~FatalException() throw();
+
+  const char* what() const throw() override;
+
+  const char* filename() const { return filename_; }
+  int line() const { return line_; }
+  const std::string& message() const { return message_; }
+
+ private:
+  const char* filename_;
+  const int line_;
+  const std::string message_;
+};
+#endif
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMMON_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/hash.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/hash.h
new file mode 100644
index 0000000..a7ec068
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/hash.h
@@ -0,0 +1,114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
+#define GOOGLE_PROTOBUF_STUBS_HASH_H__
+
+#include <cstring>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
+  namespace google {                                      \
+  namespace protobuf {
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
+
+namespace google {
+namespace protobuf {
+
+template <typename Key>
+struct hash : public std::hash<Key> {};
+
+template <typename Key>
+struct hash<const Key*> {
+  inline size_t operator()(const Key* key) const {
+    return reinterpret_cast<size_t>(key);
+  }
+};
+
+// Unlike the old SGI version, the TR1 "hash" does not special-case char*.  So,
+// we go ahead and provide our own implementation.
+template <>
+struct hash<const char*> {
+  inline size_t operator()(const char* str) const {
+    size_t result = 0;
+    for (; *str != '\0'; str++) {
+      result = 5 * result + static_cast<size_t>(*str);
+    }
+    return result;
+  }
+};
+
+template<>
+struct hash<bool> {
+  size_t operator()(bool x) const {
+    return static_cast<size_t>(x);
+  }
+};
+
+template <>
+struct hash<std::string> {
+  inline size_t operator()(const std::string& key) const {
+    return hash<const char*>()(key.c_str());
+  }
+
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+  inline bool operator()(const std::string& a, const std::string& b) const {
+    return a < b;
+  }
+};
+
+template <typename First, typename Second>
+struct hash<std::pair<First, Second> > {
+  inline size_t operator()(const std::pair<First, Second>& key) const {
+    size_t first_hash = hash<First>()(key.first);
+    size_t second_hash = hash<Second>()(key.second);
+
+    // FIXME(kenton):  What is the best way to compute this hash?  I have
+    // no idea!  This seems a bit better than an XOR.
+    return first_hash * ((1 << 16) - 1) + second_hash;
+  }
+
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+  inline bool operator()(const std::pair<First, Second>& a,
+                           const std::pair<First, Second>& b) const {
+    return a < b;
+  }
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_HASH_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/int128.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/int128.h
new file mode 100644
index 0000000..92d7bdf
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/int128.h
@@ -0,0 +1,387 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef GOOGLE_PROTOBUF_STUBS_INT128_H_
+#define GOOGLE_PROTOBUF_STUBS_INT128_H_
+
+#include <google/protobuf/stubs/common.h>
+
+#include <iosfwd>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+struct uint128_pod;
+
+// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
+// available.
+#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
+# define UINT128_CONSTEXPR constexpr
+#else
+# define UINT128_CONSTEXPR
+#endif
+
+// An unsigned 128-bit integer type. Thread-compatible.
+class PROTOBUF_EXPORT uint128 {
+ public:
+  UINT128_CONSTEXPR uint128();  // Sets to 0, but don't trust on this behavior.
+  UINT128_CONSTEXPR uint128(uint64_t top, uint64_t bottom);
+#ifndef SWIG
+  UINT128_CONSTEXPR uint128(int bottom);
+  UINT128_CONSTEXPR uint128(uint32_t bottom);   // Top 96 bits = 0
+#endif
+  UINT128_CONSTEXPR uint128(uint64_t bottom);   // hi_ = 0
+  UINT128_CONSTEXPR uint128(const uint128_pod &val);
+
+  // Trivial copy constructor, assignment operator and destructor.
+
+  void Initialize(uint64_t top, uint64_t bottom);
+
+  // Arithmetic operators.
+  uint128& operator+=(const uint128& b);
+  uint128& operator-=(const uint128& b);
+  uint128& operator*=(const uint128& b);
+  // Long division/modulo for uint128.
+  uint128& operator/=(const uint128& b);
+  uint128& operator%=(const uint128& b);
+  uint128 operator++(int);
+  uint128 operator--(int);
+  uint128& operator<<=(int);
+  uint128& operator>>=(int);
+  uint128& operator&=(const uint128& b);
+  uint128& operator|=(const uint128& b);
+  uint128& operator^=(const uint128& b);
+  uint128& operator++();
+  uint128& operator--();
+
+  friend uint64_t Uint128Low64(const uint128& v);
+  friend uint64_t Uint128High64(const uint128& v);
+
+  // We add "std::" to avoid including all of port.h.
+  PROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
+                                                  const uint128& b);
+
+ private:
+  static void DivModImpl(uint128 dividend, uint128 divisor,
+                         uint128* quotient_ret, uint128* remainder_ret);
+
+  // Little-endian memory order optimizations can benefit from
+  // having lo_ first, hi_ last.
+  // See util/endian/endian.h and Load128/Store128 for storing a uint128.
+  uint64_t lo_;
+  uint64_t hi_;
+
+  // Not implemented, just declared for catching automatic type conversions.
+  uint128(uint8_t);
+  uint128(uint16_t);
+  uint128(float v);
+  uint128(double v);
+};
+
+// This is a POD form of uint128 which can be used for static variables which
+// need to be operated on as uint128.
+struct uint128_pod {
+  // Note: The ordering of fields is different than 'class uint128' but the
+  // same as its 2-arg constructor.  This enables more obvious initialization
+  // of static instances, which is the primary reason for this struct in the
+  // first place.  This does not seem to defeat any optimizations wrt
+  // operations involving this struct.
+  uint64_t hi;
+  uint64_t lo;
+};
+
+PROTOBUF_EXPORT extern const uint128_pod kuint128max;
+
+// allow uint128 to be logged
+PROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                                const uint128& b);
+
+// Methods to access low and high pieces of 128-bit value.
+// Defined externally from uint128 to facilitate conversion
+// to native 128-bit types when compilers support them.
+inline uint64_t Uint128Low64(const uint128& v) { return v.lo_; }
+inline uint64_t Uint128High64(const uint128& v) { return v.hi_; }
+
+// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
+
+// --------------------------------------------------------------------------
+//                      Implementation details follow
+// --------------------------------------------------------------------------
+inline bool operator==(const uint128& lhs, const uint128& rhs) {
+  return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
+          Uint128High64(lhs) == Uint128High64(rhs));
+}
+inline bool operator!=(const uint128& lhs, const uint128& rhs) {
+  return !(lhs == rhs);
+}
+
+inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
+inline UINT128_CONSTEXPR uint128::uint128(uint64_t top, uint64_t bottom)
+    : lo_(bottom), hi_(top) {}
+inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
+    : lo_(v.lo), hi_(v.hi) {}
+inline UINT128_CONSTEXPR uint128::uint128(uint64_t bottom)
+    : lo_(bottom), hi_(0) {}
+#ifndef SWIG
+inline UINT128_CONSTEXPR uint128::uint128(uint32_t bottom)
+    : lo_(bottom), hi_(0) {}
+inline UINT128_CONSTEXPR uint128::uint128(int bottom)
+    : lo_(bottom), hi_(static_cast<int64_t>((bottom < 0) ? -1 : 0)) {}
+#endif
+
+#undef UINT128_CONSTEXPR
+
+inline void uint128::Initialize(uint64_t top, uint64_t bottom) {
+  hi_ = top;
+  lo_ = bottom;
+}
+
+// Comparison operators.
+
+#define CMP128(op)                                                \
+inline bool operator op(const uint128& lhs, const uint128& rhs) { \
+  return (Uint128High64(lhs) == Uint128High64(rhs)) ?             \
+      (Uint128Low64(lhs) op Uint128Low64(rhs)) :                  \
+      (Uint128High64(lhs) op Uint128High64(rhs));                 \
+}
+
+CMP128(<)
+CMP128(>)
+CMP128(>=)
+CMP128(<=)
+
+#undef CMP128
+
+// Unary operators
+
+inline uint128 operator-(const uint128& val) {
+  const uint64_t hi_flip = ~Uint128High64(val);
+  const uint64_t lo_flip = ~Uint128Low64(val);
+  const uint64_t lo_add = lo_flip + 1;
+  if (lo_add < lo_flip) {
+    return uint128(hi_flip + 1, lo_add);
+  }
+  return uint128(hi_flip, lo_add);
+}
+
+inline bool operator!(const uint128& val) {
+  return !Uint128High64(val) && !Uint128Low64(val);
+}
+
+// Logical operators.
+
+inline uint128 operator~(const uint128& val) {
+  return uint128(~Uint128High64(val), ~Uint128Low64(val));
+}
+
+#define LOGIC128(op)                                                 \
+inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
+  return uint128(Uint128High64(lhs) op Uint128High64(rhs),           \
+                 Uint128Low64(lhs) op Uint128Low64(rhs));            \
+}
+
+LOGIC128(|)
+LOGIC128(&)
+LOGIC128(^)
+
+#undef LOGIC128
+
+#define LOGICASSIGN128(op)                                   \
+inline uint128& uint128::operator op(const uint128& other) { \
+  hi_ op other.hi_;                                          \
+  lo_ op other.lo_;                                          \
+  return *this;                                              \
+}
+
+LOGICASSIGN128(|=)
+LOGICASSIGN128(&=)
+LOGICASSIGN128(^=)
+
+#undef LOGICASSIGN128
+
+// Shift operators.
+
+inline uint128 operator<<(const uint128& val, int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount == 0) {
+      return val;
+    }
+    uint64_t new_hi = (Uint128High64(val) << amount) |
+                      (Uint128Low64(val) >> (64 - amount));
+    uint64_t new_lo = Uint128Low64(val) << amount;
+    return uint128(new_hi, new_lo);
+  } else if (amount < 128) {
+    return uint128(Uint128Low64(val) << (amount - 64), 0);
+  } else {
+    return uint128(0, 0);
+  }
+}
+
+inline uint128 operator>>(const uint128& val, int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount == 0) {
+      return val;
+    }
+    uint64_t new_hi = Uint128High64(val) >> amount;
+    uint64_t new_lo = (Uint128Low64(val) >> amount) |
+                      (Uint128High64(val) << (64 - amount));
+    return uint128(new_hi, new_lo);
+  } else if (amount < 128) {
+    return uint128(0, Uint128High64(val) >> (amount - 64));
+  } else {
+    return uint128(0, 0);
+  }
+}
+
+inline uint128& uint128::operator<<=(int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
+      lo_ = lo_ << amount;
+    }
+  } else if (amount < 128) {
+    hi_ = lo_ << (amount - 64);
+    lo_ = 0;
+  } else {
+    hi_ = 0;
+    lo_ = 0;
+  }
+  return *this;
+}
+
+inline uint128& uint128::operator>>=(int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
+      hi_ = hi_ >> amount;
+    }
+  } else if (amount < 128) {
+    lo_ = hi_ >> (amount - 64);
+    hi_ = 0;
+  } else {
+    lo_ = 0;
+    hi_ = 0;
+  }
+  return *this;
+}
+
+inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) += rhs;
+}
+
+inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) -= rhs;
+}
+
+inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) *= rhs;
+}
+
+inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) /= rhs;
+}
+
+inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) %= rhs;
+}
+
+inline uint128& uint128::operator+=(const uint128& b) {
+  hi_ += b.hi_;
+  uint64_t lolo = lo_ + b.lo_;
+  if (lolo < lo_)
+    ++hi_;
+  lo_ = lolo;
+  return *this;
+}
+
+inline uint128& uint128::operator-=(const uint128& b) {
+  hi_ -= b.hi_;
+  if (b.lo_ > lo_)
+    --hi_;
+  lo_ -= b.lo_;
+  return *this;
+}
+
+inline uint128& uint128::operator*=(const uint128& b) {
+  uint64_t a96 = hi_ >> 32;
+  uint64_t a64 = hi_ & 0xffffffffu;
+  uint64_t a32 = lo_ >> 32;
+  uint64_t a00 = lo_ & 0xffffffffu;
+  uint64_t b96 = b.hi_ >> 32;
+  uint64_t b64 = b.hi_ & 0xffffffffu;
+  uint64_t b32 = b.lo_ >> 32;
+  uint64_t b00 = b.lo_ & 0xffffffffu;
+  // multiply [a96 .. a00] x [b96 .. b00]
+  // terms higher than c96 disappear off the high side
+  // terms c96 and c64 are safe to ignore carry bit
+  uint64_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
+  uint64_t c64 = a64 * b00 + a32 * b32 + a00 * b64;
+  this->hi_ = (c96 << 32) + c64;
+  this->lo_ = 0;
+  // add terms after this one at a time to capture carry
+  *this += uint128(a32 * b00) << 32;
+  *this += uint128(a00 * b32) << 32;
+  *this += a00 * b00;
+  return *this;
+}
+
+inline uint128 uint128::operator++(int) {
+  uint128 tmp(*this);
+  *this += 1;
+  return tmp;
+}
+
+inline uint128 uint128::operator--(int) {
+  uint128 tmp(*this);
+  *this -= 1;
+  return tmp;
+}
+
+inline uint128& uint128::operator++() {
+  *this += 1;
+  return *this;
+}
+
+inline uint128& uint128::operator--() {
+  *this -= 1;
+  return *this;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_INT128_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/logging.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/logging.h
new file mode 100644
index 0000000..8ecc2fa
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/logging.h
@@ -0,0 +1,239 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_LOGGING_H_
+#define GOOGLE_PROTOBUF_STUBS_LOGGING_H_
+
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <google/protobuf/port_def.inc>
+
+// ===================================================================
+// emulates google3/base/logging.h
+
+namespace google {
+namespace protobuf {
+
+enum LogLevel {
+  LOGLEVEL_INFO,     // Informational.  This is never actually used by
+                     // libprotobuf.
+  LOGLEVEL_WARNING,  // Warns about issues that, although not technically a
+                     // problem now, could cause problems in the future.  For
+                     // example, a // warning will be printed when parsing a
+                     // message that is near the message size limit.
+  LOGLEVEL_ERROR,    // An error occurred which should never happen during
+                     // normal use.
+  LOGLEVEL_FATAL,    // An error occurred from which the library cannot
+                     // recover.  This usually indicates a programming error
+                     // in the code which calls the library, especially when
+                     // compiled in debug mode.
+
+#ifdef NDEBUG
+  LOGLEVEL_DFATAL = LOGLEVEL_ERROR
+#else
+  LOGLEVEL_DFATAL = LOGLEVEL_FATAL
+#endif
+};
+
+class uint128;
+namespace internal {
+
+class LogFinisher;
+
+class PROTOBUF_EXPORT LogMessage {
+ public:
+  LogMessage(LogLevel level, const char* filename, int line);
+  ~LogMessage();
+
+  LogMessage& operator<<(const std::string& value);
+  LogMessage& operator<<(const char* value);
+  LogMessage& operator<<(char value);
+  LogMessage& operator<<(int value);
+  LogMessage& operator<<(uint value);
+  LogMessage& operator<<(long value);
+  LogMessage& operator<<(unsigned long value);
+  LogMessage& operator<<(long long value);
+  LogMessage& operator<<(unsigned long long value);
+  LogMessage& operator<<(double value);
+  LogMessage& operator<<(void* value);
+  LogMessage& operator<<(const StringPiece& value);
+  LogMessage& operator<<(const util::Status& status);
+  LogMessage& operator<<(const uint128& value);
+
+ private:
+  friend class LogFinisher;
+  void Finish();
+
+  LogLevel level_;
+  const char* filename_;
+  int line_;
+  std::string message_;
+};
+
+// Used to make the entire "LOG(BLAH) << etc." expression have a void return
+// type and print a newline after each message.
+class PROTOBUF_EXPORT LogFinisher {
+ public:
+  void operator=(LogMessage& other);
+};
+
+template<typename T>
+bool IsOk(T status) { return status.ok(); }
+template<>
+inline bool IsOk(bool status) { return status; }
+
+}  // namespace internal
+
+// Undef everything in case we're being mixed with some other Google library
+// which already defined them itself.  Presumably all Google libraries will
+// support the same syntax for these so it should not be a big deal if they
+// end up using our definitions instead.
+#undef GOOGLE_LOG
+#undef GOOGLE_LOG_IF
+
+#undef GOOGLE_CHECK
+#undef GOOGLE_CHECK_OK
+#undef GOOGLE_CHECK_EQ
+#undef GOOGLE_CHECK_NE
+#undef GOOGLE_CHECK_LT
+#undef GOOGLE_CHECK_LE
+#undef GOOGLE_CHECK_GT
+#undef GOOGLE_CHECK_GE
+#undef GOOGLE_CHECK_NOTNULL
+
+#undef GOOGLE_DLOG
+#undef GOOGLE_DCHECK
+#undef GOOGLE_DCHECK_OK
+#undef GOOGLE_DCHECK_EQ
+#undef GOOGLE_DCHECK_NE
+#undef GOOGLE_DCHECK_LT
+#undef GOOGLE_DCHECK_LE
+#undef GOOGLE_DCHECK_GT
+#undef GOOGLE_DCHECK_GE
+
+#define GOOGLE_LOG(LEVEL)                          \
+  ::google::protobuf::internal::LogFinisher() = \
+      ::google::protobuf::internal::LogMessage( \
+          ::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
+#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
+  !(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL)
+
+#define GOOGLE_CHECK(EXPRESSION) \
+  GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
+#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(::google::protobuf::internal::IsOk(A))
+#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
+#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
+#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) <  (B))
+#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B))
+#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) >  (B))
+#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
+
+namespace internal {
+template<typename T>
+T* CheckNotNull(const char* /* file */, int /* line */,
+                const char* name, T* val) {
+  if (val == nullptr) {
+    GOOGLE_LOG(FATAL) << name;
+  }
+  return val;
+}
+}  // namespace internal
+#define GOOGLE_CHECK_NOTNULL(A)               \
+  ::google::protobuf::internal::CheckNotNull( \
+      __FILE__, __LINE__, "'" #A "' must not be nullptr", (A))
+
+#ifdef NDEBUG
+
+#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false)
+
+#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
+#define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E))
+#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B))
+#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B))
+#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) <  (B))
+#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B))
+#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) >  (B))
+#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B))
+
+#else  // NDEBUG
+
+#define GOOGLE_DLOG GOOGLE_LOG
+
+#define GOOGLE_DCHECK    GOOGLE_CHECK
+#define GOOGLE_DCHECK_OK GOOGLE_CHECK_OK
+#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
+#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
+#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
+#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
+#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
+#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
+
+#endif  // !NDEBUG
+
+typedef void LogHandler(LogLevel level, const char* filename, int line,
+                        const std::string& message);
+
+// The protobuf library sometimes writes warning and error messages to
+// stderr.  These messages are primarily useful for developers, but may
+// also help end users figure out a problem.  If you would prefer that
+// these messages be sent somewhere other than stderr, call SetLogHandler()
+// to set your own handler.  This returns the old handler.  Set the handler
+// to nullptr to ignore log messages (but see also LogSilencer, below).
+//
+// Obviously, SetLogHandler is not thread-safe.  You should only call it
+// at initialization time, and probably not from library code.  If you
+// simply want to suppress log messages temporarily (e.g. because you
+// have some code that tends to trigger them frequently and you know
+// the warnings are not important to you), use the LogSilencer class
+// below.
+PROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func);
+
+// Create a LogSilencer if you want to temporarily suppress all log
+// messages.  As long as any LogSilencer objects exist, non-fatal
+// log messages will be discarded (the current LogHandler will *not*
+// be called).  Constructing a LogSilencer is thread-safe.  You may
+// accidentally suppress log messages occurring in another thread, but
+// since messages are generally for debugging purposes only, this isn't
+// a big deal.  If you want to intercept log messages, use SetLogHandler().
+class PROTOBUF_EXPORT LogSilencer {
+ public:
+  LogSilencer();
+  ~LogSilencer();
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_LOGGING_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/macros.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/macros.h
new file mode 100644
index 0000000..ae9a8b9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/macros.h
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_MACROS_H__
+#define GOOGLE_PROTOBUF_MACROS_H__
+
+namespace google {
+namespace protobuf {
+
+#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
+#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
+  TypeName(const TypeName&) = delete;               \
+  void operator=(const TypeName&) = delete
+
+#undef GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS
+#define GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName() = delete;                                  \
+  TypeName(const TypeName&) = delete;                   \
+  void operator=(const TypeName&) = delete
+
+// ===================================================================
+// from google3/base/basictypes.h
+
+// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.
+//
+// GOOGLE_ARRAYSIZE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
+// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+//
+// Kudos to Jorg Brown for this simple and elegant implementation.
+
+#undef GOOGLE_ARRAYSIZE
+#define GOOGLE_ARRAYSIZE(a) \
+  ((sizeof(a) / sizeof(*(a))) / \
+   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MACROS_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/map_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/map_util.h
new file mode 100644
index 0000000..24e098a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/map_util.h
@@ -0,0 +1,769 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/util/gtl/map_util.h
+// Author: Anton Carver
+
+#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
+
+#include <stddef.h>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// Local implementation of RemoveConst to avoid including base/type_traits.h.
+template <class T> struct RemoveConst { typedef T type; };
+template <class T> struct RemoveConst<const T> : RemoveConst<T> {};
+}  // namespace internal
+
+//
+// Find*()
+//
+
+// Returns a const reference to the value associated with the given key if it
+// exists. Crashes otherwise.
+//
+// This is intended as a replacement for operator[] as an rvalue (for reading)
+// when the key is guaranteed to exist.
+//
+// operator[] for lookup is discouraged for several reasons:
+//  * It has a side-effect of inserting missing keys
+//  * It is not thread-safe (even when it is not inserting, it can still
+//      choose to resize the underlying storage)
+//  * It invalidates iterators (when it chooses to resize)
+//  * It default constructs a value object even if it doesn't need to
+//
+// This version assumes the key is printable, and includes it in the fatal log
+// message.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDie(const Collection& collection,
+          const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+  return it->second;
+}
+
+// Same as above, but returns a non-const reference.
+template <class Collection>
+typename Collection::value_type::second_type&
+FindOrDie(Collection& collection,  // NOLINT
+          const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
+  return it->second;
+}
+
+// Same as FindOrDie above, but doesn't log the key on failure.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDieNoPrint(const Collection& collection,
+                 const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found";
+  return it->second;
+}
+
+// Same as above, but returns a non-const reference.
+template <class Collection>
+typename Collection::value_type::second_type&
+FindOrDieNoPrint(Collection& collection,  // NOLINT
+                 const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) << "Map key not found";
+  return it->second;
+}
+
+// Returns a const reference to the value associated with the given key if it
+// exists, otherwise returns a const reference to the provided default value.
+//
+// WARNING: If a temporary object is passed as the default "value,"
+// this function will return a reference to that temporary object,
+// which will be destroyed at the end of the statement. A common
+// example: if you have a map with string values, and you pass a char*
+// as the default "value," either use the returned value immediately
+// or store it in a string (not string&).
+// Details: http://go/findwithdefault
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindWithDefault(const Collection& collection,
+                const typename Collection::value_type::first_type& key,
+                const typename Collection::value_type::second_type& value) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return value;
+  }
+  return it->second;
+}
+
+// Returns a pointer to the const value associated with the given key if it
+// exists, or nullptr otherwise.
+template <class Collection>
+const typename Collection::value_type::second_type*
+FindOrNull(const Collection& collection,
+           const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  return &it->second;
+}
+
+// Same as above but returns a pointer to the non-const value.
+template <class Collection>
+typename Collection::value_type::second_type*
+FindOrNull(Collection& collection,  // NOLINT
+           const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  return &it->second;
+}
+
+// Returns the pointer value associated with the given key. If none is found,
+// nullptr is returned. The function is designed to be used with a map of keys to
+// pointers.
+//
+// This function does not distinguish between a missing key and a key mapped
+// to nullptr.
+template <class Collection>
+typename Collection::value_type::second_type
+FindPtrOrNull(const Collection& collection,
+              const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return typename Collection::value_type::second_type();
+  }
+  return it->second;
+}
+
+// Same as above, except takes non-const reference to collection.
+//
+// This function is needed for containers that propagate constness to the
+// pointee, such as boost::ptr_map.
+template <class Collection>
+typename Collection::value_type::second_type
+FindPtrOrNull(Collection& collection,  // NOLINT
+              const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return typename Collection::value_type::second_type();
+  }
+  return it->second;
+}
+
+// Finds the pointer value associated with the given key in a map whose values
+// are linked_ptrs. Returns nullptr if key is not found.
+template <class Collection>
+typename Collection::value_type::second_type::element_type*
+FindLinkedPtrOrNull(const Collection& collection,
+                    const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return 0;
+  }
+  // Since linked_ptr::get() is a const member returning a non const,
+  // we do not need a version of this function taking a non const collection.
+  return it->second.get();
+}
+
+// Same as above, but dies if the key is not found.
+template <class Collection>
+typename Collection::value_type::second_type::element_type&
+FindLinkedPtrOrDie(const Collection& collection,
+                   const typename Collection::value_type::first_type& key) {
+  typename Collection::const_iterator it = collection.find(key);
+  GOOGLE_CHECK(it != collection.end()) <<  "key not found: " << key;
+  // Since linked_ptr::operator*() is a const member returning a non const,
+  // we do not need a version of this function taking a non const collection.
+  return *it->second;
+}
+
+// Finds the value associated with the given key and copies it to *value (if not
+// nullptr). Returns false if the key was not found, true otherwise.
+template <class Collection, class Key, class Value>
+bool FindCopy(const Collection& collection,
+              const Key& key,
+              Value* const value) {
+  typename Collection::const_iterator it = collection.find(key);
+  if (it == collection.end()) {
+    return false;
+  }
+  if (value) {
+    *value = it->second;
+  }
+  return true;
+}
+
+//
+// Contains*()
+//
+
+// Returns true if and only if the given collection contains the given key.
+template <class Collection, class Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+  return collection.find(key) != collection.end();
+}
+
+// Returns true if and only if the given collection contains the given key-value
+// pair.
+template <class Collection, class Key, class Value>
+bool ContainsKeyValuePair(const Collection& collection,
+                          const Key& key,
+                          const Value& value) {
+  typedef typename Collection::const_iterator const_iterator;
+  std::pair<const_iterator, const_iterator> range = collection.equal_range(key);
+  for (const_iterator it = range.first; it != range.second; ++it) {
+    if (it->second == value) {
+      return true;
+    }
+  }
+  return false;
+}
+
+//
+// Insert*()
+//
+
+// Inserts the given key-value pair into the collection. Returns true if and
+// only if the key from the given pair didn't previously exist. Otherwise, the
+// value in the map is replaced with the value from the given pair.
+template <class Collection>
+bool InsertOrUpdate(Collection* const collection,
+                    const typename Collection::value_type& vt) {
+  std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+  if (!ret.second) {
+    // update
+    ret.first->second = vt.second;
+    return false;
+  }
+  return true;
+}
+
+// Same as above, except that the key and value are passed separately.
+template <class Collection>
+bool InsertOrUpdate(Collection* const collection,
+                    const typename Collection::value_type::first_type& key,
+                    const typename Collection::value_type::second_type& value) {
+  return InsertOrUpdate(
+      collection, typename Collection::value_type(key, value));
+}
+
+// Inserts/updates all the key-value pairs from the range defined by the
+// iterators "first" and "last" into the given collection.
+template <class Collection, class InputIterator>
+void InsertOrUpdateMany(Collection* const collection,
+                        InputIterator first, InputIterator last) {
+  for (; first != last; ++first) {
+    InsertOrUpdate(collection, *first);
+  }
+}
+
+// Change the value associated with a particular key in a map or hash_map
+// of the form map<Key, Value*> which owns the objects pointed to by the
+// value pointers.  If there was an existing value for the key, it is deleted.
+// True indicates an insert took place, false indicates an update + delete.
+template <class Collection>
+bool InsertAndDeleteExisting(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& value) {
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, value));
+  if (!ret.second) {
+    delete ret.first->second;
+    ret.first->second = value;
+    return false;
+  }
+  return true;
+}
+
+// Inserts the given key and value into the given collection if and only if the
+// given key did NOT already exist in the collection. If the key previously
+// existed in the collection, the value is not changed. Returns true if the
+// key-value pair was inserted; returns false if the key was already present.
+template <class Collection>
+bool InsertIfNotPresent(Collection* const collection,
+                        const typename Collection::value_type& vt) {
+  return collection->insert(vt).second;
+}
+
+// Same as above except the key and value are passed separately.
+template <class Collection>
+bool InsertIfNotPresent(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& value) {
+  return InsertIfNotPresent(
+      collection, typename Collection::value_type(key, value));
+}
+
+// Same as above except dies if the key already exists in the collection.
+template <class Collection>
+void InsertOrDie(Collection* const collection,
+                 const typename Collection::value_type& value) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value))
+      << "duplicate value: " << value;
+}
+
+// Same as above except doesn't log the value on error.
+template <class Collection>
+void InsertOrDieNoPrint(Collection* const collection,
+                        const typename Collection::value_type& value) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
+}
+
+// Inserts the key-value pair into the collection. Dies if key was already
+// present.
+template <class Collection>
+void InsertOrDie(Collection* const collection,
+                 const typename Collection::value_type::first_type& key,
+                 const typename Collection::value_type::second_type& data) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, key, data))
+      << "duplicate key: " << key;
+}
+
+// Same as above except doesn't log the key on error.
+template <class Collection>
+void InsertOrDieNoPrint(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& data) {
+  GOOGLE_CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key.";
+}
+
+// Inserts a new key and default-initialized value. Dies if the key was already
+// present. Returns a reference to the value. Example usage:
+//
+// map<int, SomeProto> m;
+// SomeProto& proto = InsertKeyOrDie(&m, 3);
+// proto.set_field("foo");
+template <class Collection>
+typename Collection::value_type::second_type& InsertKeyOrDie(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typedef typename Collection::value_type value_type;
+  std::pair<typename Collection::iterator, bool> res =
+      collection->insert(value_type(key, typename value_type::second_type()));
+  GOOGLE_CHECK(res.second) << "duplicate key: " << key;
+  return res.first->second;
+}
+
+//
+// Lookup*()
+//
+
+// Looks up a given key and value pair in a collection and inserts the key-value
+// pair if it's not already present. Returns a reference to the value associated
+// with the key.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsert(Collection* const collection,
+               const typename Collection::value_type& vt) {
+  return collection->insert(vt).first->second;
+}
+
+// Same as above except the key-value are passed separately.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsert(Collection* const collection,
+               const typename Collection::value_type::first_type& key,
+               const typename Collection::value_type::second_type& value) {
+  return LookupOrInsert(
+      collection, typename Collection::value_type(key, value));
+}
+
+// Counts the number of equivalent elements in the given "sequence", and stores
+// the results in "count_map" with element as the key and count as the value.
+//
+// Example:
+//   vector<string> v = {"a", "b", "c", "a", "b"};
+//   map<string, int> m;
+//   AddTokenCounts(v, 1, &m);
+//   assert(m["a"] == 2);
+//   assert(m["b"] == 2);
+//   assert(m["c"] == 1);
+template <typename Sequence, typename Collection>
+void AddTokenCounts(
+    const Sequence& sequence,
+    const typename Collection::value_type::second_type& increment,
+    Collection* const count_map) {
+  for (typename Sequence::const_iterator it = sequence.begin();
+       it != sequence.end(); ++it) {
+    typename Collection::value_type::second_type& value =
+        LookupOrInsert(count_map, *it,
+                       typename Collection::value_type::second_type());
+    value += increment;
+  }
+}
+
+// Returns a reference to the value associated with key. If not found, a value
+// is default constructed on the heap and added to the map.
+//
+// This function is useful for containers of the form map<Key, Value*>, where
+// inserting a new key, value pair involves constructing a new heap-allocated
+// Value, and storing a pointer to that in the collection.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsertNew(Collection* const collection,
+                  const typename Collection::value_type::first_type& key) {
+  typedef typename std::iterator_traits<
+    typename Collection::value_type::second_type>::value_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(
+          key,
+          static_cast<typename Collection::value_type::second_type>(nullptr)));
+  if (ret.second) {
+    ret.first->second = new Element();
+  }
+  return ret.first->second;
+}
+
+// Same as above but constructs the value using the single-argument constructor
+// and the given "arg".
+template <class Collection, class Arg>
+typename Collection::value_type::second_type&
+LookupOrInsertNew(Collection* const collection,
+                  const typename Collection::value_type::first_type& key,
+                  const Arg& arg) {
+  typedef typename std::iterator_traits<
+    typename Collection::value_type::second_type>::value_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(
+          key,
+          static_cast<typename Collection::value_type::second_type>(nullptr)));
+  if (ret.second) {
+    ret.first->second = new Element(arg);
+  }
+  return ret.first->second;
+}
+
+// Lookup of linked/shared pointers is used in two scenarios:
+//
+// Use LookupOrInsertNewLinkedPtr if the container owns the elements.
+// In this case it is fine working with the raw pointer as long as it is
+// guaranteed that no other thread can delete/update an accessed element.
+// A mutex will need to lock the container operation as well as the use
+// of the returned elements. Finding an element may be performed using
+// FindLinkedPtr*().
+//
+// Use LookupOrInsertNewSharedPtr if the container does not own the elements
+// for their whole lifetime. This is typically the case when a reader allows
+// parallel updates to the container. In this case a Mutex only needs to lock
+// container operations, but all element operations must be performed on the
+// shared pointer. Finding an element must be performed using FindPtr*() and
+// cannot be done with FindLinkedPtr*() even though it compiles.
+
+// Lookup a key in a map or hash_map whose values are linked_ptrs.  If it is
+// missing, set collection[key].reset(new Value::element_type) and return that.
+// Value::element_type must be default constructable.
+template <class Collection>
+typename Collection::value_type::second_type::element_type*
+LookupOrInsertNewLinkedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typedef typename Collection::value_type::second_type Value;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, Value()));
+  if (ret.second) {
+    ret.first->second.reset(new typename Value::element_type);
+  }
+  return ret.first->second.get();
+}
+
+// A variant of LookupOrInsertNewLinkedPtr where the value is constructed using
+// a single-parameter constructor.  Note: the constructor argument is computed
+// even if it will not be used, so only values cheap to compute should be passed
+// here.  On the other hand it does not matter how expensive the construction of
+// the actual stored value is, as that only occurs if necessary.
+template <class Collection, class Arg>
+typename Collection::value_type::second_type::element_type*
+LookupOrInsertNewLinkedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const Arg& arg) {
+  typedef typename Collection::value_type::second_type Value;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, Value()));
+  if (ret.second) {
+    ret.first->second.reset(new typename Value::element_type(arg));
+  }
+  return ret.first->second.get();
+}
+
+// Lookup a key in a map or hash_map whose values are shared_ptrs.  If it is
+// missing, set collection[key].reset(new Value::element_type). Unlike
+// LookupOrInsertNewLinkedPtr, this function returns the shared_ptr instead of
+// the raw pointer. Value::element_type must be default constructable.
+template <class Collection>
+typename Collection::value_type::second_type&
+LookupOrInsertNewSharedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typedef typename Collection::value_type::second_type SharedPtr;
+  typedef typename Collection::value_type::second_type::element_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, SharedPtr()));
+  if (ret.second) {
+    ret.first->second.reset(new Element());
+  }
+  return ret.first->second;
+}
+
+// A variant of LookupOrInsertNewSharedPtr where the value is constructed using
+// a single-parameter constructor.  Note: the constructor argument is computed
+// even if it will not be used, so only values cheap to compute should be passed
+// here.  On the other hand it does not matter how expensive the construction of
+// the actual stored value is, as that only occurs if necessary.
+template <class Collection, class Arg>
+typename Collection::value_type::second_type&
+LookupOrInsertNewSharedPtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const Arg& arg) {
+  typedef typename Collection::value_type::second_type SharedPtr;
+  typedef typename Collection::value_type::second_type::element_type Element;
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, SharedPtr()));
+  if (ret.second) {
+    ret.first->second.reset(new Element(arg));
+  }
+  return ret.first->second;
+}
+
+//
+// Misc Utility Functions
+//
+
+// Updates the value associated with the given key. If the key was not already
+// present, then the key-value pair are inserted and "previous" is unchanged. If
+// the key was already present, the value is updated and "*previous" will
+// contain a copy of the old value.
+//
+// InsertOrReturnExisting has complementary behavior that returns the
+// address of an already existing value, rather than updating it.
+template <class Collection>
+bool UpdateReturnCopy(Collection* const collection,
+                      const typename Collection::value_type::first_type& key,
+                      const typename Collection::value_type::second_type& value,
+                      typename Collection::value_type::second_type* previous) {
+  std::pair<typename Collection::iterator, bool> ret =
+      collection->insert(typename Collection::value_type(key, value));
+  if (!ret.second) {
+    // update
+    if (previous) {
+      *previous = ret.first->second;
+    }
+    ret.first->second = value;
+    return true;
+  }
+  return false;
+}
+
+// Same as above except that the key and value are passed as a pair.
+template <class Collection>
+bool UpdateReturnCopy(Collection* const collection,
+                      const typename Collection::value_type& vt,
+                      typename Collection::value_type::second_type* previous) {
+  std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+  if (!ret.second) {
+    // update
+    if (previous) {
+      *previous = ret.first->second;
+    }
+    ret.first->second = vt.second;
+    return true;
+  }
+  return false;
+}
+
+// Tries to insert the given key-value pair into the collection. Returns nullptr if
+// the insert succeeds. Otherwise, returns a pointer to the existing value.
+//
+// This complements UpdateReturnCopy in that it allows to update only after
+// verifying the old value and still insert quickly without having to look up
+// twice. Unlike UpdateReturnCopy this also does not come with the issue of an
+// undefined previous* in case new data was inserted.
+template <class Collection>
+typename Collection::value_type::second_type* InsertOrReturnExisting(
+    Collection* const collection, const typename Collection::value_type& vt) {
+  std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
+  if (ret.second) {
+    return nullptr;  // Inserted, no existing previous value.
+  } else {
+    return &ret.first->second;  // Return address of already existing value.
+  }
+}
+
+// Same as above, except for explicit key and data.
+template <class Collection>
+typename Collection::value_type::second_type* InsertOrReturnExisting(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key,
+    const typename Collection::value_type::second_type& data) {
+  return InsertOrReturnExisting(collection,
+                                typename Collection::value_type(key, data));
+}
+
+// Erases the collection item identified by the given key, and returns the value
+// associated with that key. It is assumed that the value (i.e., the
+// mapped_type) is a pointer. Returns nullptr if the key was not found in the
+// collection.
+//
+// Examples:
+//   map<string, MyType*> my_map;
+//
+// One line cleanup:
+//     delete EraseKeyReturnValuePtr(&my_map, "abc");
+//
+// Use returned value:
+//     std::unique_ptr<MyType> value_ptr(
+//         EraseKeyReturnValuePtr(&my_map, "abc"));
+//     if (value_ptr.get())
+//       value_ptr->DoSomething();
+//
+template <class Collection>
+typename Collection::value_type::second_type EraseKeyReturnValuePtr(
+    Collection* const collection,
+    const typename Collection::value_type::first_type& key) {
+  typename Collection::iterator it = collection->find(key);
+  if (it == collection->end()) {
+    return nullptr;
+  }
+  typename Collection::value_type::second_type v = it->second;
+  collection->erase(it);
+  return v;
+}
+
+// Inserts all the keys from map_container into key_container, which must
+// support insert(MapContainer::key_type).
+//
+// Note: any initial contents of the key_container are not cleared.
+template <class MapContainer, class KeyContainer>
+void InsertKeysFromMap(const MapContainer& map_container,
+                       KeyContainer* key_container) {
+  GOOGLE_CHECK(key_container != nullptr);
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    key_container->insert(it->first);
+  }
+}
+
+// Appends all the keys from map_container into key_container, which must
+// support push_back(MapContainer::key_type).
+//
+// Note: any initial contents of the key_container are not cleared.
+template <class MapContainer, class KeyContainer>
+void AppendKeysFromMap(const MapContainer& map_container,
+                       KeyContainer* key_container) {
+  GOOGLE_CHECK(key_container != nullptr);
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    key_container->push_back(it->first);
+  }
+}
+
+// A more specialized overload of AppendKeysFromMap to optimize reallocations
+// for the common case in which we're appending keys to a vector and hence can
+// (and sometimes should) call reserve() first.
+//
+// (It would be possible to play SFINAE games to call reserve() for any
+// container that supports it, but this seems to get us 99% of what we need
+// without the complexity of a SFINAE-based solution.)
+template <class MapContainer, class KeyType>
+void AppendKeysFromMap(const MapContainer& map_container,
+                       std::vector<KeyType>* key_container) {
+  GOOGLE_CHECK(key_container != nullptr);
+  // We now have the opportunity to call reserve(). Calling reserve() every
+  // time is a bad idea for some use cases: libstdc++'s implementation of
+  // vector<>::reserve() resizes the vector's backing store to exactly the
+  // given size (unless it's already at least that big). Because of this,
+  // the use case that involves appending a lot of small maps (total size
+  // N) one by one to a vector would be O(N^2). But never calling reserve()
+  // loses the opportunity to improve the use case of adding from a large
+  // map to an empty vector (this improves performance by up to 33%). A
+  // number of heuristics are possible; see the discussion in
+  // cl/34081696. Here we use the simplest one.
+  if (key_container->empty()) {
+    key_container->reserve(map_container.size());
+  }
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    key_container->push_back(it->first);
+  }
+}
+
+// Inserts all the values from map_container into value_container, which must
+// support push_back(MapContainer::mapped_type).
+//
+// Note: any initial contents of the value_container are not cleared.
+template <class MapContainer, class ValueContainer>
+void AppendValuesFromMap(const MapContainer& map_container,
+                         ValueContainer* value_container) {
+  GOOGLE_CHECK(value_container != nullptr);
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    value_container->push_back(it->second);
+  }
+}
+
+// A more specialized overload of AppendValuesFromMap to optimize reallocations
+// for the common case in which we're appending values to a vector and hence
+// can (and sometimes should) call reserve() first.
+//
+// (It would be possible to play SFINAE games to call reserve() for any
+// container that supports it, but this seems to get us 99% of what we need
+// without the complexity of a SFINAE-based solution.)
+template <class MapContainer, class ValueType>
+void AppendValuesFromMap(const MapContainer& map_container,
+                         std::vector<ValueType>* value_container) {
+  GOOGLE_CHECK(value_container != nullptr);
+  // See AppendKeysFromMap for why this is done.
+  if (value_container->empty()) {
+    value_container->reserve(map_container.size());
+  }
+  for (typename MapContainer::const_iterator it = map_container.begin();
+       it != map_container.end(); ++it) {
+    value_container->push_back(it->second);
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/mathutil.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/mathutil.h
new file mode 100644
index 0000000..1d16bce
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/mathutil.h
@@ -0,0 +1,162 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
+#define GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
+
+#include <cmath>
+#include <float.h>
+#include <limits>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Like std::make_unsigned_t except floating point types map to themselves.
+template <typename T>
+using MakeUnsignedT =
+    typename std::conditional<std::is_integral<T>::value, std::make_unsigned<T>,
+                              std::common_type<T>>::type::type;
+
+// Like std::isnan() except a template function that is defined for all numeric
+// types.
+template <typename T,
+          typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
+bool IsNan(T /*val*/) {
+  return false;
+}
+
+template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
+                                              int>::type = 0>
+bool IsNan(T val) {
+  return std::isnan(val);
+}
+
+template<typename T>
+bool AlmostEquals(T a, T b) {
+  return a == b;
+}
+template<>
+inline bool AlmostEquals(float a, float b) {
+  return fabs(a - b) < 32 * FLT_EPSILON;
+}
+
+template<>
+inline bool AlmostEquals(double a, double b) {
+  return fabs(a - b) < 32 * DBL_EPSILON;
+}
+
+}  // namespace internal
+
+class MathUtil {
+ public:
+  template <typename T>
+  static T Sign(T value) {
+    if (value == T(0) || internal::IsNan(value)) {
+      return value;
+    }
+    return value > T(0) ? 1 : -1;
+  }
+
+  template <typename T>
+  static bool AlmostEquals(T a, T b) {
+    return internal::AlmostEquals(a, b);
+  }
+
+  // Largest of two values.
+  // Works correctly for special floating point values.
+  // Note: 0.0 and -0.0 are not differentiated by Max (Max(0.0, -0.0) is -0.0),
+  // which should be OK because, although they (can) have different
+  // bit representation, they are observably the same when examined
+  // with arithmetic and (in)equality operators.
+  template <typename T>
+  static T Max(const T x, const T y) {
+    return internal::IsNan(x) || x > y ? x : y;
+  }
+
+  // Absolute value of x
+  // Works correctly for unsigned types and
+  // for special floating point values.
+  // Note: 0.0 and -0.0 are not differentiated by Abs (Abs(0.0) is -0.0),
+  // which should be OK: see the comment for Max above.
+  template<typename T>
+  static T Abs(const T x) {
+    return x > T(0) ? x : -x;
+  }
+
+  // Absolute value of the difference between two numbers.
+  // Works correctly for signed types and special floating point values.
+  template <typename T>
+  static typename internal::MakeUnsignedT<T> AbsDiff(const T x, const T y) {
+    // Carries out arithmetic as unsigned to avoid overflow.
+    typedef typename internal::MakeUnsignedT<T> R;
+    return x > y ? R(x) - R(y) : R(y) - R(x);
+  }
+
+  // If two (usually floating point) numbers are within a certain
+  // fraction of their magnitude or within a certain absolute margin of error.
+  // This is the same as the following but faster:
+  //   WithinFraction(x, y, fraction)  ||  WithinMargin(x, y, margin)
+  // E.g. WithinFraction(0.0, 1e-10, 1e-5) is false but
+  //      WithinFractionOrMargin(0.0, 1e-10, 1e-5, 1e-5) is true.
+  template<typename T>
+  static bool WithinFractionOrMargin(const T x, const T y,
+                                     const T fraction, const T margin);
+};
+
+template<typename T>
+bool MathUtil::WithinFractionOrMargin(const T x, const T y,
+                                      const T fraction, const T margin) {
+  // Not just "0 <= fraction" to fool the compiler for unsigned types.
+  GOOGLE_DCHECK((T(0) < fraction || T(0) == fraction) &&
+         fraction < T(1) &&
+         margin >= T(0));
+
+  // Template specialization will convert the if() condition to a constant,
+  // which will cause the compiler to generate code for either the "if" part
+  // or the "then" part.  In this way we avoid a compiler warning
+  // about a potential integer overflow in crosstool v12 (gcc 4.3.1).
+  if (std::numeric_limits<T>::is_integer) {
+    return x == y;
+  } else {
+    if (!std::isfinite(x) || !std::isfinite(y)) {
+      return false;
+    }
+    T relative_margin = static_cast<T>(fraction * Max(Abs(x), Abs(y)));
+    return AbsDiff(x, y) <= Max(margin, relative_margin);
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/mutex.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/mutex.h
new file mode 100644
index 0000000..c459991
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/mutex.h
@@ -0,0 +1,218 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_MUTEX_H_
+#define GOOGLE_PROTOBUF_STUBS_MUTEX_H_
+
+#include <mutex>
+
+#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
+#include <windows.h>
+
+// GetMessage conflicts with GeneratedMessageReflection::GetMessage().
+#ifdef GetMessage
+#undef GetMessage
+#endif
+
+#endif
+
+#include <google/protobuf/stubs/macros.h>
+
+// Define thread-safety annotations for use below, if we are building with
+// Clang.
+#if defined(__clang__) && !defined(SWIG)
+#define GOOGLE_PROTOBUF_ACQUIRE(...) \
+  __attribute__((acquire_capability(__VA_ARGS__)))
+#define GOOGLE_PROTOBUF_RELEASE(...) \
+  __attribute__((release_capability(__VA_ARGS__)))
+#define GOOGLE_PROTOBUF_SCOPED_CAPABILITY __attribute__((scoped_lockable))
+#define GOOGLE_PROTOBUF_CAPABILITY(x) __attribute__((capability(x)))
+#else
+#define GOOGLE_PROTOBUF_ACQUIRE(...)
+#define GOOGLE_PROTOBUF_RELEASE(...)
+#define GOOGLE_PROTOBUF_SCOPED_CAPABILITY
+#define GOOGLE_PROTOBUF_CAPABILITY(x)
+#endif
+
+#include <google/protobuf/port_def.inc>
+
+// ===================================================================
+// emulates google3/base/mutex.h
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#define GOOGLE_PROTOBUF_LINKER_INITIALIZED
+
+#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
+// This class is a lightweight replacement for std::mutex on Windows platforms.
+// std::mutex does not work on Windows XP SP2 with the latest VC++ libraries,
+// because it utilizes the Concurrency Runtime that is only supported on Windows
+// XP SP3 and above.
+class PROTOBUF_EXPORT CriticalSectionLock {
+ public:
+  CriticalSectionLock() { InitializeCriticalSection(&critical_section_); }
+  ~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); }
+  void lock() { EnterCriticalSection(&critical_section_); }
+  void unlock() { LeaveCriticalSection(&critical_section_); }
+
+ private:
+  CRITICAL_SECTION critical_section_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CriticalSectionLock);
+};
+
+#endif
+
+// In MSVC std::mutex does not have a constexpr constructor.
+// This wrapper makes the constructor constexpr.
+template <typename T>
+class CallOnceInitializedMutex {
+ public:
+  constexpr CallOnceInitializedMutex() : flag_{}, buf_{} {}
+  ~CallOnceInitializedMutex() { get().~T(); }
+
+  void lock() { get().lock(); }
+  void unlock() { get().unlock(); }
+
+ private:
+  T& get() {
+    std::call_once(flag_, [&] { ::new (static_cast<void*>(&buf_)) T(); });
+    return reinterpret_cast<T&>(buf_);
+  }
+
+  std::once_flag flag_;
+  alignas(T) char buf_[sizeof(T)];
+};
+
+// Mutex is a natural type to wrap. As both google and other organization have
+// specialized mutexes. gRPC also provides an injection mechanism for custom
+// mutexes.
+class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
+ public:
+#if defined(__QNX__)
+  constexpr WrappedMutex() = default;
+#else
+  constexpr WrappedMutex() {}
+#endif
+  void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); }
+  void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.unlock(); }
+  // Crash if this Mutex is not held exclusively by this thread.
+  // May fail to crash when it should; will never crash when it should not.
+  void AssertHeld() const {}
+
+ private:
+#if defined(GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP)
+  CallOnceInitializedMutex<CriticalSectionLock> mu_{};
+#elif defined(_WIN32)
+  CallOnceInitializedMutex<std::mutex> mu_{};
+#else
+  std::mutex mu_{};
+#endif
+};
+
+using Mutex = WrappedMutex;
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class GOOGLE_PROTOBUF_SCOPED_CAPABILITY PROTOBUF_EXPORT MutexLock {
+ public:
+  explicit MutexLock(Mutex* mu) GOOGLE_PROTOBUF_ACQUIRE(mu) : mu_(mu) {
+    this->mu_->Lock();
+  }
+  ~MutexLock() GOOGLE_PROTOBUF_RELEASE() { this->mu_->Unlock(); }
+
+ private:
+  Mutex *const mu_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
+};
+
+// TODO(kenton):  Implement these?  Hard to implement portably.
+typedef MutexLock ReaderMutexLock;
+typedef MutexLock WriterMutexLock;
+
+// MutexLockMaybe is like MutexLock, but is a no-op when mu is nullptr.
+class PROTOBUF_EXPORT MutexLockMaybe {
+ public:
+  explicit MutexLockMaybe(Mutex *mu) :
+    mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
+  ~MutexLockMaybe() { if (this->mu_ != nullptr) { this->mu_->Unlock(); } }
+ private:
+  Mutex *const mu_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
+};
+
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+template<typename T>
+class ThreadLocalStorage {
+ public:
+  ThreadLocalStorage() {
+    pthread_key_create(&key_, &ThreadLocalStorage::Delete);
+  }
+  ~ThreadLocalStorage() {
+    pthread_key_delete(key_);
+  }
+  T* Get() {
+    T* result = static_cast<T*>(pthread_getspecific(key_));
+    if (result == nullptr) {
+      result = new T();
+      pthread_setspecific(key_, result);
+    }
+    return result;
+  }
+ private:
+  static void Delete(void* value) {
+    delete static_cast<T*>(value);
+  }
+  pthread_key_t key_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage);
+};
+#endif
+
+}  // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::Mutex;
+using internal::MutexLock;
+using internal::ReaderMutexLock;
+using internal::WriterMutexLock;
+using internal::MutexLockMaybe;
+
+}  // namespace protobuf
+}  // namespace google
+
+#undef GOOGLE_PROTOBUF_ACQUIRE
+#undef GOOGLE_PROTOBUF_RELEASE
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MUTEX_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/once.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/once.h
new file mode 100644
index 0000000..070d36d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/once.h
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
+#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
+
+#include <mutex>
+#include <utility>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+using once_flag = std::once_flag;
+template <typename... Args>
+void call_once(Args&&... args ) {
+  std::call_once(std::forward<Args>(args)...);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_ONCE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/platform_macros.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/platform_macros.h
new file mode 100644
index 0000000..d10faf9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/platform_macros.h
@@ -0,0 +1,138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
+#define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
+
+#define GOOGLE_PROTOBUF_PLATFORM_ERROR \
+#error "Host platform was not detected as supported by protobuf"
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+//   or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define GOOGLE_PROTOBUF_ARCH_X64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define GOOGLE_PROTOBUF_ARCH_IA32 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__QNX__)
+#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1
+#if defined(__aarch64__)
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(_M_ARM) || defined(__ARMEL__)
+#define GOOGLE_PROTOBUF_ARCH_ARM 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(_M_ARM64)
+#define GOOGLE_PROTOBUF_ARCH_ARM 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__aarch64__)
+#define GOOGLE_PROTOBUF_ARCH_AARCH64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__mips__)
+#if defined(__LP64__)
+#define GOOGLE_PROTOBUF_ARCH_MIPS64 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_MIPS 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(__pnacl__)
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(sparc)
+#define GOOGLE_PROTOBUF_ARCH_SPARC 1
+#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__)
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#else
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#endif
+#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
+#define GOOGLE_PROTOBUF_ARCH_POWER 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__PPC__)
+#define GOOGLE_PROTOBUF_ARCH_PPC 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__GNUC__)
+# if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
+// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
+# elif defined(__clang__)
+#  if !__has_extension(c_atomic)
+GOOGLE_PROTOBUF_PLATFORM_ERROR
+#  endif
+// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
+# endif
+# if __LP64__
+#  define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+# else
+#  define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+# endif
+#else
+GOOGLE_PROTOBUF_PLATFORM_ERROR
+#endif
+
+#if defined(__APPLE__)
+#define GOOGLE_PROTOBUF_OS_APPLE
+#include <Availability.h>
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#define GOOGLE_PROTOBUF_OS_IPHONE
+#endif
+#elif defined(__EMSCRIPTEN__)
+#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN
+#elif defined(__native_client__)
+#define GOOGLE_PROTOBUF_OS_NACL
+#elif defined(sun)
+#define GOOGLE_PROTOBUF_OS_SOLARIS
+#elif defined(_AIX)
+#define GOOGLE_PROTOBUF_OS_AIX
+#elif defined(__ANDROID__)
+#define GOOGLE_PROTOBUF_OS_ANDROID
+#endif
+
+#undef GOOGLE_PROTOBUF_PLATFORM_ERROR
+
+#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
+// Android ndk does not support the __thread keyword very well yet. Here
+// we use pthread_key_create()/pthread_getspecific()/... methods for
+// TLS support on android.
+// iOS also does not support the __thread keyword.
+#define GOOGLE_PROTOBUF_NO_THREADLOCAL
+#endif
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+// __thread keyword requires at least 10.7
+#define GOOGLE_PROTOBUF_NO_THREADLOCAL
+#endif
+
+#endif  // GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/port.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/port.h
new file mode 100644
index 0000000..b074cb1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/port.h
@@ -0,0 +1,413 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_PORT_H_
+#define GOOGLE_PROTOBUF_STUBS_PORT_H_
+
+#include <assert.h>
+#include <cstdint>
+#include <stdlib.h>
+#include <cstddef>
+#include <string>
+#include <string.h>
+
+#include <google/protobuf/stubs/platform_macros.h>
+
+#include <google/protobuf/port_def.inc>
+
+#undef PROTOBUF_LITTLE_ENDIAN
+#ifdef _WIN32
+  // Assuming windows is always little-endian.
+  // TODO(xiaofeng): The PROTOBUF_LITTLE_ENDIAN is not only used for
+  // optimization but also for correctness. We should define an
+  // different macro to test the big-endian code path in coded_stream.
+  #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+    #define PROTOBUF_LITTLE_ENDIAN 1
+  #endif
+#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
+// If MSVC has "/RTCc" set, it will complain about truncating casts at
+// runtime.  This file contains some intentional truncating casts.
+#pragma runtime_checks("c", off)
+#endif
+#else
+#ifdef __APPLE__
+#include <machine/endian.h>  // __BYTE_ORDER
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>  // __BYTE_ORDER
+#elif (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__))
+#include <sys/isa_defs.h>  // __BYTE_ORDER
+#elif defined(_AIX) || defined(__TOS_AIX__)
+#include <sys/machine.h>  // BYTE_ORDER
+#else
+#if !defined(__QNX__)
+#include <endian.h>  // __BYTE_ORDER
+#endif
+#endif
+#if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) ||   \
+     (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
+     (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN)) &&      \
+    !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+#define PROTOBUF_LITTLE_ENDIAN 1
+#endif
+#endif
+
+// These #includes are for the byte swap functions declared later on.
+#ifdef _MSC_VER
+#include <stdlib.h>  // NOLINT(build/include)
+#include <intrin.h>
+#elif defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__)
+#include <byteswap.h>  // IWYU pragma: export
+#endif
+
+// Legacy: some users reference these (internal-only) macros even though we
+// don't need them any more.
+#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS)
+  #ifdef LIBPROTOBUF_EXPORTS
+    #define LIBPROTOBUF_EXPORT __declspec(dllexport)
+  #else
+    #define LIBPROTOBUF_EXPORT __declspec(dllimport)
+  #endif
+  #ifdef LIBPROTOC_EXPORTS
+    #define LIBPROTOC_EXPORT   __declspec(dllexport)
+  #else
+    #define LIBPROTOC_EXPORT   __declspec(dllimport)
+  #endif
+#else
+  #define LIBPROTOBUF_EXPORT
+  #define LIBPROTOC_EXPORT
+#endif
+
+#define PROTOBUF_RUNTIME_DEPRECATED(message) PROTOBUF_DEPRECATED_MSG(message)
+#define GOOGLE_PROTOBUF_RUNTIME_DEPRECATED(message) \
+  PROTOBUF_DEPRECATED_MSG(message)
+
+// ===================================================================
+// from google3/base/port.h
+
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
+     (defined(_MSC_VER) && _MSC_VER >= 1900))
+// Define this to 1 if the code is compiled in C++11 mode; leave it
+// undefined otherwise.  Do NOT define it to 0 -- that causes
+// '#ifdef LANG_CXX11' to behave differently from '#if LANG_CXX11'.
+#define LANG_CXX11 1
+#else
+#error "Protobuf requires at least C++11."
+#endif
+
+namespace google {
+namespace protobuf {
+
+using ConstStringParam = const std::string &;
+
+typedef unsigned int uint;
+
+typedef int8_t int8;
+typedef int16_t int16;
+typedef int32_t int32;
+typedef int64_t int64;
+
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+
+static const int32 kint32max = 0x7FFFFFFF;
+static const int32 kint32min = -kint32max - 1;
+static const int64 kint64max = int64_t{0x7FFFFFFFFFFFFFFF};
+static const int64 kint64min = -kint64max - 1;
+static const uint32 kuint32max = 0xFFFFFFFFu;
+static const uint64 kuint64max = uint64_t{0xFFFFFFFFFFFFFFFFu};
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
+    defined(MEMORY_SANITIZER)
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+uint16_t __sanitizer_unaligned_load16(const void *p);
+uint32_t __sanitizer_unaligned_load32(const void *p);
+uint64_t __sanitizer_unaligned_load64(const void *p);
+void __sanitizer_unaligned_store16(void *p, uint16_t v);
+void __sanitizer_unaligned_store32(void *p, uint32_t v);
+void __sanitizer_unaligned_store64(void *p, uint64_t v);
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
+
+inline uint16_t GOOGLE_UNALIGNED_LOAD16(const void *p) {
+  return __sanitizer_unaligned_load16(p);
+}
+
+inline uint32_t GOOGLE_UNALIGNED_LOAD32(const void *p) {
+  return __sanitizer_unaligned_load32(p);
+}
+
+inline uint64_t GOOGLE_UNALIGNED_LOAD64(const void *p) {
+  return __sanitizer_unaligned_load64(p);
+}
+
+inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16_t v) {
+  __sanitizer_unaligned_store16(p, v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32_t v) {
+  __sanitizer_unaligned_store32(p, v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64_t v) {
+  __sanitizer_unaligned_store64(p, v);
+}
+
+#elif defined(GOOGLE_PROTOBUF_USE_UNALIGNED) && GOOGLE_PROTOBUF_USE_UNALIGNED
+
+#define GOOGLE_UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16_t *>(_p))
+#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32_t *>(_p))
+#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64_t *>(_p))
+
+#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16_t *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32_t *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64_t *>(_p) = (_val))
+
+#else
+inline uint16_t GOOGLE_UNALIGNED_LOAD16(const void *p) {
+  uint16_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32_t GOOGLE_UNALIGNED_LOAD32(const void *p) {
+  uint32_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64_t GOOGLE_UNALIGNED_LOAD64(const void *p) {
+  uint64_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16_t v) {
+  memcpy(p, &v, sizeof v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32_t v) {
+  memcpy(p, &v, sizeof v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64_t v) {
+  memcpy(p, &v, sizeof v);
+}
+#endif
+
+#if defined(GOOGLE_PROTOBUF_OS_NACL) \
+    || (defined(__ANDROID__) && defined(__clang__) \
+        && (__clang_major__ == 3 && __clang_minor__ == 8) \
+        && (__clang_patchlevel__ < 275480))
+# define GOOGLE_PROTOBUF_USE_PORTABLE_LOG2
+#endif
+
+// The following guarantees declaration of the byte swap functions.
+#ifdef _MSC_VER
+#define bswap_16(x) _byteswap_ushort(x)
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+// Mac OS X / Darwin features
+#define bswap_16(x) OSSwapInt16(x)
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif !defined(__linux__) && !defined(__ANDROID__) && !defined(__CYGWIN__)
+
+#ifndef bswap_16
+static inline uint16_t bswap_16(uint16_t x) {
+  return static_cast<uint16_t>(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));
+}
+#define bswap_16(x) bswap_16(x)
+#endif
+
+#ifndef bswap_32
+static inline uint32_t bswap_32(uint32_t x) {
+  return (((x & 0xFF) << 24) |
+          ((x & 0xFF00) << 8) |
+          ((x & 0xFF0000) >> 8) |
+          ((x & 0xFF000000) >> 24));
+}
+#define bswap_32(x) bswap_32(x)
+#endif
+
+#ifndef bswap_64
+static inline uint64_t bswap_64(uint64_t x) {
+  return (((x & uint64_t{0xFFu}) << 56) | ((x & uint64_t{0xFF00u}) << 40) |
+          ((x & uint64_t{0xFF0000u}) << 24) |
+          ((x & uint64_t{0xFF000000u}) << 8) |
+          ((x & uint64_t{0xFF00000000u}) >> 8) |
+          ((x & uint64_t{0xFF0000000000u}) >> 24) |
+          ((x & uint64_t{0xFF000000000000u}) >> 40) |
+          ((x & uint64_t{0xFF00000000000000u}) >> 56));
+}
+#define bswap_64(x) bswap_64(x)
+#endif
+
+#endif
+
+// ===================================================================
+// from google3/util/bits/bits.h
+
+class Bits {
+ public:
+  static uint32_t Log2FloorNonZero(uint32_t n) {
+#if defined(__GNUC__)
+  return 31 ^ static_cast<uint32_t>(__builtin_clz(n));
+#elif defined(_MSC_VER)
+  unsigned long where;
+  _BitScanReverse(&where, n);
+  return where;
+#else
+  return Log2FloorNonZero_Portable(n);
+#endif
+  }
+
+  static uint32_t Log2FloorNonZero64(uint64_t n) {
+    // Older versions of clang run into an instruction-selection failure when
+    // it encounters __builtin_clzll:
+    // https://bugs.chromium.org/p/nativeclient/issues/detail?id=4395
+    // This includes arm-nacl-clang and clang in older Android NDK versions.
+    // To work around this, when we build with those we use the portable
+    // implementation instead.
+#if defined(__GNUC__) && !defined(GOOGLE_PROTOBUF_USE_PORTABLE_LOG2)
+  return 63 ^ static_cast<uint32_t>(__builtin_clzll(n));
+#elif defined(_MSC_VER) && defined(_M_X64)
+  unsigned long where;
+  _BitScanReverse64(&where, n);
+  return where;
+#else
+  return Log2FloorNonZero64_Portable(n);
+#endif
+  }
+ private:
+  static int Log2FloorNonZero_Portable(uint32_t n) {
+    if (n == 0)
+      return -1;
+    int log = 0;
+    uint32_t value = n;
+    for (int i = 4; i >= 0; --i) {
+      int shift = (1 << i);
+      uint32_t x = value >> shift;
+      if (x != 0) {
+        value = x;
+        log += shift;
+      }
+    }
+    assert(value == 1);
+    return log;
+  }
+
+  static int Log2FloorNonZero64_Portable(uint64_t n) {
+    const uint32_t topbits = static_cast<uint32_t>(n >> 32);
+    if (topbits == 0) {
+      // Top bits are zero, so scan in bottom bits
+      return static_cast<int>(Log2FloorNonZero(static_cast<uint32_t>(n)));
+    } else {
+      return 32 + static_cast<int>(Log2FloorNonZero(topbits));
+    }
+  }
+};
+
+// ===================================================================
+// from google3/util/endian/endian.h
+PROTOBUF_EXPORT uint32_t ghtonl(uint32_t x);
+
+class BigEndian {
+ public:
+#ifdef PROTOBUF_LITTLE_ENDIAN
+
+  static uint16_t FromHost16(uint16_t x) { return bswap_16(x); }
+  static uint16_t ToHost16(uint16_t x) { return bswap_16(x); }
+
+  static uint32_t FromHost32(uint32_t x) { return bswap_32(x); }
+  static uint32_t ToHost32(uint32_t x) { return bswap_32(x); }
+
+  static uint64_t FromHost64(uint64_t x) { return bswap_64(x); }
+  static uint64_t ToHost64(uint64_t x) { return bswap_64(x); }
+
+  static bool IsLittleEndian() { return true; }
+
+#else
+
+  static uint16_t FromHost16(uint16_t x) { return x; }
+  static uint16_t ToHost16(uint16_t x) { return x; }
+
+  static uint32_t FromHost32(uint32_t x) { return x; }
+  static uint32_t ToHost32(uint32_t x) { return x; }
+
+  static uint64_t FromHost64(uint64_t x) { return x; }
+  static uint64_t ToHost64(uint64_t x) { return x; }
+
+  static bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+  // Functions to do unaligned loads and stores in big-endian order.
+  static uint16_t Load16(const void *p) {
+    return ToHost16(GOOGLE_UNALIGNED_LOAD16(p));
+  }
+
+  static void Store16(void *p, uint16_t v) {
+    GOOGLE_UNALIGNED_STORE16(p, FromHost16(v));
+  }
+
+  static uint32_t Load32(const void *p) {
+    return ToHost32(GOOGLE_UNALIGNED_LOAD32(p));
+  }
+
+  static void Store32(void *p, uint32_t v) {
+    GOOGLE_UNALIGNED_STORE32(p, FromHost32(v));
+  }
+
+  static uint64_t Load64(const void *p) {
+    return ToHost64(GOOGLE_UNALIGNED_LOAD64(p));
+  }
+
+  static void Store64(void *p, uint64_t v) {
+    GOOGLE_UNALIGNED_STORE64(p, FromHost64(v));
+  }
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_PORT_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/status.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/status.h
new file mode 100644
index 0000000..c858cf6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/status.h
@@ -0,0 +1,196 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUS_H_
+
+#include <string>
+
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace status_internal {
+
+// These values must match error codes defined in google/rpc/code.proto.
+enum class StatusCode : int {
+  kOk = 0,
+  kCancelled = 1,
+  kUnknown = 2,
+  kInvalidArgument = 3,
+  kDeadlineExceeded = 4,
+  kNotFound = 5,
+  kAlreadyExists = 6,
+  kPermissionDenied = 7,
+  kUnauthenticated = 16,
+  kResourceExhausted = 8,
+  kFailedPrecondition = 9,
+  kAborted = 10,
+  kOutOfRange = 11,
+  kUnimplemented = 12,
+  kInternal = 13,
+  kUnavailable = 14,
+  kDataLoss = 15,
+};
+
+class PROTOBUF_EXPORT Status {
+ public:
+  // Creates a "successful" status.
+  Status();
+
+  // Create a status in the canonical error space with the specified
+  // code, and error message.  If "code == 0", error_message is
+  // ignored and a Status object identical to Status::kOk is
+  // constructed.
+  Status(StatusCode error_code, StringPiece error_message);
+  Status(const Status&);
+  Status& operator=(const Status& x);
+  ~Status() {}
+
+  // Accessor
+  bool ok() const { return error_code_ == StatusCode::kOk; }
+  StatusCode code() const { return error_code_; }
+  StringPiece message() const {
+    return error_message_;
+  }
+
+  bool operator==(const Status& x) const;
+  bool operator!=(const Status& x) const {
+    return !operator==(x);
+  }
+
+  // Return a combination of the error code name and message.
+  std::string ToString() const;
+
+ private:
+  StatusCode error_code_;
+  std::string error_message_;
+};
+
+// Returns an OK status, equivalent to a default constructed instance. Prefer
+// usage of `OkStatus()` when constructing such an OK status.
+PROTOBUF_EXPORT Status OkStatus();
+
+// Prints a human-readable representation of 'x' to 'os'.
+PROTOBUF_EXPORT std::ostream& operator<<(std::ostream& os, const Status& x);
+
+// These convenience functions return `true` if a given status matches the
+// `StatusCode` error code of its associated function.
+PROTOBUF_EXPORT bool IsAborted(const Status& status);
+PROTOBUF_EXPORT bool IsAlreadyExists(const Status& status);
+PROTOBUF_EXPORT bool IsCancelled(const Status& status);
+PROTOBUF_EXPORT bool IsDataLoss(const Status& status);
+PROTOBUF_EXPORT bool IsDeadlineExceeded(const Status& status);
+PROTOBUF_EXPORT bool IsFailedPrecondition(const Status& status);
+PROTOBUF_EXPORT bool IsInternal(const Status& status);
+PROTOBUF_EXPORT bool IsInvalidArgument(const Status& status);
+PROTOBUF_EXPORT bool IsNotFound(const Status& status);
+PROTOBUF_EXPORT bool IsOutOfRange(const Status& status);
+PROTOBUF_EXPORT bool IsPermissionDenied(const Status& status);
+PROTOBUF_EXPORT bool IsResourceExhausted(const Status& status);
+PROTOBUF_EXPORT bool IsUnauthenticated(const Status& status);
+PROTOBUF_EXPORT bool IsUnavailable(const Status& status);
+PROTOBUF_EXPORT bool IsUnimplemented(const Status& status);
+PROTOBUF_EXPORT bool IsUnknown(const Status& status);
+
+// These convenience functions create an `Status` object with an error code as
+// indicated by the associated function name, using the error message passed in
+// `message`.
+//
+// These functions are intentionally named `*Error` rather than `*Status` to
+// match the names from Abseil:
+// https://github.com/abseil/abseil-cpp/blob/2e9532cc6c701a8323d0cffb468999ab804095ab/absl/status/status.h#L716
+PROTOBUF_EXPORT Status AbortedError(StringPiece message);
+PROTOBUF_EXPORT Status AlreadyExistsError(StringPiece message);
+PROTOBUF_EXPORT Status CancelledError(StringPiece message);
+PROTOBUF_EXPORT Status DataLossError(StringPiece message);
+PROTOBUF_EXPORT Status DeadlineExceededError(StringPiece message);
+PROTOBUF_EXPORT Status FailedPreconditionError(StringPiece message);
+PROTOBUF_EXPORT Status InternalError(StringPiece message);
+PROTOBUF_EXPORT Status InvalidArgumentError(StringPiece message);
+PROTOBUF_EXPORT Status NotFoundError(StringPiece message);
+PROTOBUF_EXPORT Status OutOfRangeError(StringPiece message);
+PROTOBUF_EXPORT Status PermissionDeniedError(StringPiece message);
+PROTOBUF_EXPORT Status ResourceExhaustedError(StringPiece message);
+PROTOBUF_EXPORT Status UnauthenticatedError(StringPiece message);
+PROTOBUF_EXPORT Status UnavailableError(StringPiece message);
+PROTOBUF_EXPORT Status UnimplementedError(StringPiece message);
+PROTOBUF_EXPORT Status UnknownError(StringPiece message);
+
+}  // namespace status_internal
+
+using ::google::protobuf::util::status_internal::Status;
+using ::google::protobuf::util::status_internal::StatusCode;
+
+using ::google::protobuf::util::status_internal::IsAborted;
+using ::google::protobuf::util::status_internal::IsAlreadyExists;
+using ::google::protobuf::util::status_internal::IsCancelled;
+using ::google::protobuf::util::status_internal::IsDataLoss;
+using ::google::protobuf::util::status_internal::IsDeadlineExceeded;
+using ::google::protobuf::util::status_internal::IsFailedPrecondition;
+using ::google::protobuf::util::status_internal::IsInternal;
+using ::google::protobuf::util::status_internal::IsInvalidArgument;
+using ::google::protobuf::util::status_internal::IsNotFound;
+using ::google::protobuf::util::status_internal::IsOutOfRange;
+using ::google::protobuf::util::status_internal::IsPermissionDenied;
+using ::google::protobuf::util::status_internal::IsResourceExhausted;
+using ::google::protobuf::util::status_internal::IsUnauthenticated;
+using ::google::protobuf::util::status_internal::IsUnavailable;
+using ::google::protobuf::util::status_internal::IsUnimplemented;
+using ::google::protobuf::util::status_internal::IsUnknown;
+
+using ::google::protobuf::util::status_internal::AbortedError;
+using ::google::protobuf::util::status_internal::AlreadyExistsError;
+using ::google::protobuf::util::status_internal::CancelledError;
+using ::google::protobuf::util::status_internal::DataLossError;
+using ::google::protobuf::util::status_internal::DeadlineExceededError;
+using ::google::protobuf::util::status_internal::FailedPreconditionError;
+using ::google::protobuf::util::status_internal::InternalError;
+using ::google::protobuf::util::status_internal::InvalidArgumentError;
+using ::google::protobuf::util::status_internal::NotFoundError;
+using ::google::protobuf::util::status_internal::OkStatus;
+using ::google::protobuf::util::status_internal::OutOfRangeError;
+using ::google::protobuf::util::status_internal::PermissionDeniedError;
+using ::google::protobuf::util::status_internal::ResourceExhaustedError;
+using ::google::protobuf::util::status_internal::UnauthenticatedError;
+using ::google::protobuf::util::status_internal::UnavailableError;
+using ::google::protobuf::util::status_internal::UnimplementedError;
+using ::google::protobuf::util::status_internal::UnknownError;
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STATUS_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/status_macros.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/status_macros.h
new file mode 100644
index 0000000..407ff4c
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/status_macros.h
@@ -0,0 +1,89 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// From: util/task/contrib/status_macros/status_macros.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_MACROS_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUS_MACROS_H_
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Run a command that returns a util::Status.  If the called code returns an
+// error status, return that status up out of this method too.
+//
+// Example:
+//   RETURN_IF_ERROR(DoThings(4));
+#define RETURN_IF_ERROR(expr)                                                \
+  do {                                                                       \
+    /* Using _status below to avoid capture problems if expr is "status". */ \
+    const PROTOBUF_NAMESPACE_ID::util::Status _status = (expr);              \
+    if (PROTOBUF_PREDICT_FALSE(!_status.ok())) return _status;               \
+  } while (0)
+
+// Internal helper for concatenating macro values.
+#define STATUS_MACROS_CONCAT_NAME_INNER(x, y) x##y
+#define STATUS_MACROS_CONCAT_NAME(x, y) STATUS_MACROS_CONCAT_NAME_INNER(x, y)
+
+template<typename T>
+Status DoAssignOrReturn(T& lhs, StatusOr<T> result) {
+  if (result.ok()) {
+    lhs = result.value();
+  }
+  return result.status();
+}
+
+#define ASSIGN_OR_RETURN_IMPL(status, lhs, rexpr) \
+  Status status = DoAssignOrReturn(lhs, (rexpr)); \
+  if (PROTOBUF_PREDICT_FALSE(!status.ok())) return status;
+
+// Executes an expression that returns a util::StatusOr, extracting its value
+// into the variable defined by lhs (or returning on error).
+//
+// Example: Assigning to an existing value
+//   ValueType value;
+//   ASSIGN_OR_RETURN(value, MaybeGetValue(arg));
+//
+// WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used
+//  in a single statement (e.g. as the body of an if statement without {})!
+#define ASSIGN_OR_RETURN(lhs, rexpr) \
+  ASSIGN_OR_RETURN_IMPL( \
+      STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, rexpr);
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STATUS_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/statusor.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/statusor.h
new file mode 100644
index 0000000..20e603e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/statusor.h
@@ -0,0 +1,253 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// StatusOr<T> is the union of a Status object and a T
+// object. StatusOr models the concept of an object that is either a
+// usable value, or an error Status explaining why such a value is
+// not present. To this end, StatusOr<T> does not allow its Status
+// value to be OkStatus(). Further, StatusOr<T*> does not allow the
+// contained pointer to be nullptr.
+//
+// The primary use-case for StatusOr<T> is as the return value of a
+// function which may fail.
+//
+// Example client usage for a StatusOr<T>, where T is not a pointer:
+//
+//  StatusOr<float> result = DoBigCalculationThatCouldFail();
+//  if (result.ok()) {
+//    float answer = result.value();
+//    printf("Big calculation yielded: %f", answer);
+//  } else {
+//    LOG(ERROR) << result.status();
+//  }
+//
+// Example client usage for a StatusOr<T*>:
+//
+//  StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
+//  if (result.ok()) {
+//    std::unique_ptr<Foo> foo(result.value());
+//    foo->DoSomethingCool();
+//  } else {
+//    LOG(ERROR) << result.status();
+//  }
+//
+// Example factory implementation returning StatusOr<T*>:
+//
+//  StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
+//    if (arg <= 0) {
+//      return InvalidArgumentError("Arg must be positive");
+//    } else {
+//      return new Foo(arg);
+//    }
+//  }
+//
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
+
+#include <new>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/status.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace statusor_internal {
+
+template<typename T>
+class StatusOr {
+  template<typename U> friend class StatusOr;
+
+ public:
+  using value_type = T;
+
+  // Construct a new StatusOr with Status::UNKNOWN status.
+  // Construct a new StatusOr with UnknownError() status.
+  explicit StatusOr();
+
+  // Construct a new StatusOr with the given non-ok status. After calling
+  // this constructor, calls to value() will CHECK-fail.
+  //
+  // NOTE: Not explicit - we want to use StatusOr<T> as a return
+  // value, so it is convenient and sensible to be able to do 'return
+  // Status()' when the return type is StatusOr<T>.
+  //
+  // REQUIRES: status != OkStatus(). This requirement is DCHECKed.
+  // In optimized builds, passing OkStatus() here will have the effect
+  // of passing PosixErrorSpace::EINVAL as a fallback.
+  StatusOr(const Status& status);  // NOLINT
+
+  // Construct a new StatusOr with the given value. If T is a plain pointer,
+  // value must not be nullptr. After calling this constructor, calls to
+  // value() will succeed, and calls to status() will return OK.
+  //
+  // NOTE: Not explicit - we want to use StatusOr<T> as a return type
+  // so it is convenient and sensible to be able to do 'return T()'
+  // when when the return type is StatusOr<T>.
+  //
+  // REQUIRES: if T is a plain pointer, value != nullptr. This requirement is
+  // DCHECKed. In optimized builds, passing a null pointer here will have
+  // the effect of passing PosixErrorSpace::EINVAL as a fallback.
+  StatusOr(const T& value);  // NOLINT
+
+  // Copy constructor.
+  StatusOr(const StatusOr& other);
+
+  // Conversion copy constructor, T must be copy constructible from U
+  template<typename U>
+  StatusOr(const StatusOr<U>& other);
+
+  // Assignment operator.
+  StatusOr& operator=(const StatusOr& other);
+
+  // Conversion assignment operator, T must be assignable from U
+  template<typename U>
+  StatusOr& operator=(const StatusOr<U>& other);
+
+  // Returns a reference to our status. If this contains a T, then
+  // returns OkStatus().
+  const Status& status() const;
+
+  // Returns this->status().ok()
+  bool ok() const;
+
+  // Returns a reference to our current value, or CHECK-fails if !this->ok().
+  const T& value () const;
+
+ private:
+  Status status_;
+  T value_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation details for StatusOr<T>
+
+class PROTOBUF_EXPORT StatusOrHelper {
+ public:
+  // Move type-agnostic error handling to the .cc.
+  static void Crash(const util::Status& status);
+
+  // Customized behavior for StatusOr<T> vs. StatusOr<T*>
+  template<typename T>
+  struct Specialize;
+};
+
+template<typename T>
+struct StatusOrHelper::Specialize {
+  // For non-pointer T, a reference can never be nullptr.
+  static inline bool IsValueNull(const T& /*t*/) { return false; }
+};
+
+template<typename T>
+struct StatusOrHelper::Specialize<T*> {
+  static inline bool IsValueNull(const T* t) { return t == nullptr; }
+};
+
+template <typename T>
+inline StatusOr<T>::StatusOr() : status_(util::UnknownError("")) {}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const Status& status) {
+  if (status.ok()) {
+    status_ = util::InternalError("OkStatus() is not a valid argument.");
+  } else {
+    status_ = status;
+  }
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const T& value) {
+  if (StatusOrHelper::Specialize<T>::IsValueNull(value)) {
+    status_ = util::InternalError("nullptr is not a valid argument.");
+  } else {
+    status_ = util::OkStatus();
+    value_ = value;
+  }
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
+    : status_(other.status_), value_(other.value_) {
+}
+
+template<typename T>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
+  status_ = other.status_;
+  value_ = other.value_;
+  return *this;
+}
+
+template<typename T>
+template<typename U>
+inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
+    : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
+}
+
+template<typename T>
+template<typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
+  status_ = other.status_;
+  if (status_.ok()) value_ = other.value_;
+  return *this;
+}
+
+template<typename T>
+inline const Status& StatusOr<T>::status() const {
+  return status_;
+}
+
+template<typename T>
+inline bool StatusOr<T>::ok() const {
+  return status().ok();
+}
+
+template<typename T>
+inline const T& StatusOr<T>::value() const {
+  if (!status_.ok()) {
+    StatusOrHelper::Crash(status_);
+  }
+  return value_;
+}
+
+}  // namespace statusor_internal
+
+using ::google::protobuf::util::statusor_internal::StatusOr;
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stl_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stl_util.h
new file mode 100644
index 0000000..e6260d0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stl_util.h
@@ -0,0 +1,90 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/util/gtl/stl_util.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+
+#include <algorithm>
+
+// Must be last.
+#include <google/protobuf/port_def.inc>  // NOLINT
+
+namespace google {
+namespace protobuf {
+
+// Inside Google, this function implements a horrible, disgusting hack in which
+// we reach into the string's private implementation and resize it without
+// initializing the new bytes.  In some cases doing this can significantly
+// improve performance.  However, since it's totally non-portable it has no
+// place in open source code.  Feel free to fill this function in with your
+// own disgusting hack if you want the perf boost.
+inline void STLStringResizeUninitialized(std::string* s, size_t new_size) {
+  s->resize(new_size);
+}
+
+// As above, but we make sure to follow amortized growth in which we always
+// increase the capacity by at least a constant factor >1.
+inline void STLStringResizeUninitializedAmortized(std::string* s,
+                                                  size_t new_size) {
+  const size_t cap = s->capacity();
+  if (new_size > cap) {
+    // Make sure to always grow by at least a factor of 2x.
+    s->reserve(std::max<size_t>(new_size, 2 * cap));
+  }
+  STLStringResizeUninitialized(s, new_size);
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(std::string* str) {
+  // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+  return str->empty() ? nullptr : &*str->begin();
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>  // NOLINT
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stringpiece.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stringpiece.h
new file mode 100644
index 0000000..c63e25b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stringpiece.h
@@ -0,0 +1,402 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A StringPiece points to part or all of a string, Cord, double-quoted string
+// literal, or other string-like object.  A StringPiece does *not* own the
+// string to which it points.  A StringPiece is not null-terminated.
+//
+// You can use StringPiece as a function or method parameter.  A StringPiece
+// parameter can receive a double-quoted string literal argument, a "const
+// char*" argument, a string argument, or a StringPiece argument with no data
+// copying.  Systematic use of StringPiece for arguments reduces data
+// copies and strlen() calls.
+//
+// Prefer passing StringPieces by value:
+//   void MyFunction(StringPiece arg);
+// If circumstances require, you may also pass by const reference:
+//   void MyFunction(const StringPiece& arg);  // not preferred
+// Both of these have the same lifetime semantics.  Passing by value
+// generates slightly smaller code.  For more discussion, see the thread
+// go/stringpiecebyvalue on c-users.
+//
+// StringPiece is also suitable for local variables if you know that
+// the lifetime of the underlying object is longer than the lifetime
+// of your StringPiece variable.
+//
+// Beware of binding a StringPiece to a temporary:
+//   StringPiece sp = obj.MethodReturningString();  // BAD: lifetime problem
+//
+// This code is okay:
+//   string str = obj.MethodReturningString();  // str owns its contents
+//   StringPiece sp(str);  // GOOD, because str outlives sp
+//
+// StringPiece is sometimes a poor choice for a return value and usually a poor
+// choice for a data member.  If you do use a StringPiece this way, it is your
+// responsibility to ensure that the object pointed to by the StringPiece
+// outlives the StringPiece.
+//
+// A StringPiece may represent just part of a string; thus the name "Piece".
+// For example, when splitting a string, vector<StringPiece> is a natural data
+// type for the output.  For another example, a Cord is a non-contiguous,
+// potentially very long string-like object.  The Cord class has an interface
+// that iteratively provides StringPiece objects that point to the
+// successive pieces of a Cord object.
+//
+// A StringPiece is not null-terminated.  If you write code that scans a
+// StringPiece, you must check its length before reading any characters.
+// Common idioms that work on null-terminated strings do not work on
+// StringPiece objects.
+//
+// There are several ways to create a null StringPiece:
+//   StringPiece()
+//   StringPiece(nullptr)
+//   StringPiece(nullptr, 0)
+// For all of the above, sp.data() == nullptr, sp.length() == 0,
+// and sp.empty() == true.  Also, if you create a StringPiece with
+// a non-null pointer then sp.data() != nullptr.  Once created,
+// sp.data() will stay either nullptr or not-nullptr, except if you call
+// sp.clear() or sp.set().
+//
+// Thus, you can use StringPiece(nullptr) to signal an out-of-band value
+// that is different from other StringPiece values.  This is similar
+// to the way that const char* p1 = nullptr; is different from
+// const char* p2 = "";.
+//
+// There are many ways to create an empty StringPiece:
+//   StringPiece()
+//   StringPiece(nullptr)
+//   StringPiece(nullptr, 0)
+//   StringPiece("")
+//   StringPiece("", 0)
+//   StringPiece("abcdef", 0)
+//   StringPiece("abcdef"+6, 0)
+// For all of the above, sp.length() will be 0 and sp.empty() will be true.
+// For some empty StringPiece values, sp.data() will be nullptr.
+// For some empty StringPiece values, sp.data() will not be nullptr.
+//
+// Be careful not to confuse: null StringPiece and empty StringPiece.
+// The set of empty StringPieces properly includes the set of null StringPieces.
+// That is, every null StringPiece is an empty StringPiece,
+// but some non-null StringPieces are empty Stringpieces too.
+//
+// All empty StringPiece values compare equal to each other.
+// Even a null StringPieces compares equal to a non-null empty StringPiece:
+//  StringPiece() == StringPiece("", 0)
+//  StringPiece(nullptr) == StringPiece("abc", 0)
+//  StringPiece(nullptr, 0) == StringPiece("abcdef"+6, 0)
+//
+// Look carefully at this example:
+//   StringPiece("") == nullptr
+// True or false?  TRUE, because StringPiece::operator== converts
+// the right-hand side from nullptr to StringPiece(nullptr),
+// and then compares two zero-length spans of characters.
+// However, we are working to make this example produce a compile error.
+//
+// Suppose you want to write:
+//   bool TestWhat?(StringPiece sp) { return sp == nullptr; }  // BAD
+// Do not do that.  Write one of these instead:
+//   bool TestNull(StringPiece sp) { return sp.data() == nullptr; }
+//   bool TestEmpty(StringPiece sp) { return sp.empty(); }
+// The intent of TestWhat? is unclear.  Did you mean TestNull or TestEmpty?
+// Right now, TestWhat? behaves likes TestEmpty.
+// We are working to make TestWhat? produce a compile error.
+// TestNull is good to test for an out-of-band signal.
+// TestEmpty is good to test for an empty StringPiece.
+//
+// Caveats (again):
+// (1) The lifetime of the pointed-to string (or piece of a string)
+//     must be longer than the lifetime of the StringPiece.
+// (2) There may or may not be a '\0' character after the end of
+//     StringPiece data.
+// (3) A null StringPiece is empty.
+//     An empty StringPiece may or may not be a null StringPiece.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
+#define GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <iosfwd>
+#include <limits>
+#include <string>
+
+#if defined(__cpp_lib_string_view)
+#include <string_view>
+#endif
+
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace stringpiece_internal {
+
+class PROTOBUF_EXPORT StringPiece {
+ public:
+  using traits_type = std::char_traits<char>;
+  using value_type = char;
+  using pointer = char*;
+  using const_pointer = const char*;
+  using reference = char&;
+  using const_reference = const char&;
+  using const_iterator = const char*;
+  using iterator = const_iterator;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using reverse_iterator = const_reverse_iterator;
+  using size_type = size_t;
+  using difference_type = std::ptrdiff_t;
+
+ private:
+  const char* ptr_;
+  size_type length_;
+
+  static constexpr size_type kMaxSize =
+      (std::numeric_limits<difference_type>::max)();
+
+  static size_type CheckSize(size_type size) {
+#if !defined(NDEBUG) || defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
+    if (PROTOBUF_PREDICT_FALSE(size > kMaxSize)) {
+      // Some people grep for this message in logs
+      // so take care if you ever change it.
+      LogFatalSizeTooBig(size, "string length exceeds max size");
+    }
+#endif
+    return size;
+  }
+
+  // Out-of-line error path.
+  static void LogFatalSizeTooBig(size_type size, const char* details);
+
+ public:
+  // We provide non-explicit singleton constructors so users can pass
+  // in a "const char*" or a "string" wherever a "StringPiece" is
+  // expected.
+  //
+  // Style guide exception granted:
+  // http://goto/style-guide-exception-20978288
+  StringPiece() : ptr_(nullptr), length_(0) {}
+
+  StringPiece(const char* str)  // NOLINT(runtime/explicit)
+      : ptr_(str), length_(0) {
+    if (str != nullptr) {
+      length_ = CheckSize(strlen(str));
+    }
+  }
+
+  template <class Allocator>
+  StringPiece(  // NOLINT(runtime/explicit)
+      const std::basic_string<char, std::char_traits<char>, Allocator>& str)
+      : ptr_(str.data()), length_(0) {
+    length_ = CheckSize(str.size());
+  }
+
+#if defined(__cpp_lib_string_view)
+  StringPiece(  // NOLINT(runtime/explicit)
+      std::string_view str)
+      : ptr_(str.data()), length_(0) {
+    length_ = CheckSize(str.size());
+  }
+#endif
+
+  StringPiece(const char* offset, size_type len)
+      : ptr_(offset), length_(CheckSize(len)) {}
+
+  // data() may return a pointer to a buffer with embedded NULs, and the
+  // returned buffer may or may not be null terminated.  Therefore it is
+  // typically a mistake to pass data() to a routine that expects a NUL
+  // terminated string.
+  const_pointer data() const { return ptr_; }
+  size_type size() const { return length_; }
+  size_type length() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  char operator[](size_type i) const {
+    assert(i < length_);
+    return ptr_[i];
+  }
+
+  void remove_prefix(size_type n) {
+    assert(length_ >= n);
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  void remove_suffix(size_type n) {
+    assert(length_ >= n);
+    length_ -= n;
+  }
+
+  // returns {-1, 0, 1}
+  int compare(StringPiece x) const {
+    size_type min_size = length_ < x.length_ ? length_ : x.length_;
+    int r = memcmp(ptr_, x.ptr_, static_cast<size_t>(min_size));
+    if (r < 0) return -1;
+    if (r > 0) return 1;
+    if (length_ < x.length_) return -1;
+    if (length_ > x.length_) return 1;
+    return 0;
+  }
+
+  std::string as_string() const { return ToString(); }
+  // We also define ToString() here, since many other string-like
+  // interfaces name the routine that converts to a C++ string
+  // "ToString", and it's confusing to have the method that does that
+  // for a StringPiece be called "as_string()".  We also leave the
+  // "as_string()" method defined here for existing code.
+  std::string ToString() const {
+    if (ptr_ == nullptr) return "";
+    return std::string(data(), static_cast<size_type>(size()));
+  }
+
+  explicit operator std::string() const { return ToString(); }
+
+  void CopyToString(std::string* target) const;
+  void AppendToString(std::string* target) const;
+
+  bool starts_with(StringPiece x) const {
+    return (length_ >= x.length_) &&
+           (memcmp(ptr_, x.ptr_, static_cast<size_t>(x.length_)) == 0);
+  }
+
+  bool ends_with(StringPiece x) const {
+    return ((length_ >= x.length_) &&
+            (memcmp(ptr_ + (length_-x.length_), x.ptr_,
+                 static_cast<size_t>(x.length_)) == 0));
+  }
+
+  // Checks whether StringPiece starts with x and if so advances the beginning
+  // of it to past the match.  It's basically a shortcut for starts_with
+  // followed by remove_prefix.
+  bool Consume(StringPiece x);
+  // Like above but for the end of the string.
+  bool ConsumeFromEnd(StringPiece x);
+
+  // standard STL container boilerplate
+  static const size_type npos;
+  const_iterator begin() const { return ptr_; }
+  const_iterator end() const { return ptr_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(ptr_ + length_);
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(ptr_);
+  }
+  size_type max_size() const { return length_; }
+  size_type capacity() const { return length_; }
+
+  // cpplint.py emits a false positive [build/include_what_you_use]
+  size_type copy(char* buf, size_type n, size_type pos = 0) const;  // NOLINT
+
+  bool contains(StringPiece s) const;
+
+  size_type find(StringPiece s, size_type pos = 0) const;
+  size_type find(char c, size_type pos = 0) const;
+  size_type rfind(StringPiece s, size_type pos = npos) const;
+  size_type rfind(char c, size_type pos = npos) const;
+
+  size_type find_first_of(StringPiece s, size_type pos = 0) const;
+  size_type find_first_of(char c, size_type pos = 0) const {
+    return find(c, pos);
+  }
+  size_type find_first_not_of(StringPiece s, size_type pos = 0) const;
+  size_type find_first_not_of(char c, size_type pos = 0) const;
+  size_type find_last_of(StringPiece s, size_type pos = npos) const;
+  size_type find_last_of(char c, size_type pos = npos) const {
+    return rfind(c, pos);
+  }
+  size_type find_last_not_of(StringPiece s, size_type pos = npos) const;
+  size_type find_last_not_of(char c, size_type pos = npos) const;
+
+  StringPiece substr(size_type pos, size_type n = npos) const;
+};
+
+// This large function is defined inline so that in a fairly common case where
+// one of the arguments is a literal, the compiler can elide a lot of the
+// following comparisons.
+inline bool operator==(StringPiece x, StringPiece y) {
+  StringPiece::size_type len = x.size();
+  if (len != y.size()) {
+    return false;
+  }
+
+  return x.data() == y.data() || len <= 0 ||
+      memcmp(x.data(), y.data(), static_cast<size_t>(len)) == 0;
+}
+
+inline bool operator!=(StringPiece x, StringPiece y) {
+  return !(x == y);
+}
+
+inline bool operator<(StringPiece x, StringPiece y) {
+  const StringPiece::size_type min_size =
+      x.size() < y.size() ? x.size() : y.size();
+  const int r = memcmp(x.data(), y.data(), static_cast<size_t>(min_size));
+  return (r < 0) || (r == 0 && x.size() < y.size());
+}
+
+inline bool operator>(StringPiece x, StringPiece y) {
+  return y < x;
+}
+
+inline bool operator<=(StringPiece x, StringPiece y) {
+  return !(x > y);
+}
+
+inline bool operator>=(StringPiece x, StringPiece y) {
+  return !(x < y);
+}
+
+// allow StringPiece to be logged
+extern std::ostream& operator<<(std::ostream& o, StringPiece piece);
+
+}  // namespace stringpiece_internal
+
+using ::google::protobuf::stringpiece_internal::StringPiece;
+
+}  // namespace protobuf
+}  // namespace google
+
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
+template<> struct hash<StringPiece> {
+  size_t operator()(const StringPiece& s) const {
+    size_t result = 0;
+    for (const char *str = s.data(), *end = str + s.size(); str < end; str++) {
+      result = 5 * result + static_cast<size_t>(*str);
+    }
+    return result;
+  }
+};
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // STRINGS_STRINGPIECE_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stringprintf.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stringprintf.h
new file mode 100644
index 0000000..e3858be
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/stringprintf.h
@@ -0,0 +1,85 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf.h
+//
+// Printf variants that place their output in a C++ string.
+//
+// Usage:
+//      string result = StringPrintf("%d %s\n", 10, "hello");
+//      SStringPrintf(&result, "%d %s\n", 10, "hello");
+//      StringAppendF(&result, "%d %s\n", 20, "there");
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
+
+#include <stdarg.h>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+// Return a C++ string
+PROTOBUF_EXPORT extern std::string StringPrintf(const char* format, ...);
+
+// Store result into a supplied string and return it
+PROTOBUF_EXPORT extern const std::string& SStringPrintf(std::string* dst,
+                                                        const char* format,
+                                                        ...);
+
+// Append result to a supplied string
+PROTOBUF_EXPORT extern void StringAppendF(std::string* dst, const char* format,
+                                          ...);
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string.  All other routines are just convenience wrappers around it.
+PROTOBUF_EXPORT extern void StringAppendV(std::string* dst, const char* format,
+                                          va_list ap);
+
+// The max arguments supported by StringPrintfVector
+PROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs;
+
+// You can use this version when all your arguments are strings, but
+// you don't know how many arguments you'll have at compile time.
+// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
+PROTOBUF_EXPORT extern std::string StringPrintfVector(
+    const char* format, const std::vector<std::string>& v);
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/strutil.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/strutil.h
new file mode 100644
index 0000000..9658abf
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/strutil.h
@@ -0,0 +1,950 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/strings/strutil.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
+#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <stdlib.h>
+
+#include <cstring>
+#include <google/protobuf/port_def.inc>
+#include <vector>
+
+namespace google {
+namespace protobuf {
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#define strtoll  _strtoi64
+#define strtoull _strtoui64
+#elif defined(__DECCXX) && defined(__osf__)
+// HP C++ on Tru64 does not have strtoll, but strtol is already 64-bit.
+#define strtoll strtol
+#define strtoull strtoul
+#endif
+
+// ----------------------------------------------------------------------
+// ascii_isalnum()
+//    Check if an ASCII character is alphanumeric.  We can't use ctype's
+//    isalnum() because it is affected by locale.  This function is applied
+//    to identifiers in the protocol buffer language, not to natural-language
+//    strings, so locale should not be taken into account.
+// ascii_isdigit()
+//    Like above, but only accepts digits.
+// ascii_isspace()
+//    Check if the character is a space character.
+// ----------------------------------------------------------------------
+
+inline bool ascii_isalnum(char c) {
+  return ('a' <= c && c <= 'z') ||
+         ('A' <= c && c <= 'Z') ||
+         ('0' <= c && c <= '9');
+}
+
+inline bool ascii_isdigit(char c) {
+  return ('0' <= c && c <= '9');
+}
+
+inline bool ascii_isspace(char c) {
+  return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
+      c == '\r';
+}
+
+inline bool ascii_isupper(char c) {
+  return c >= 'A' && c <= 'Z';
+}
+
+inline bool ascii_islower(char c) {
+  return c >= 'a' && c <= 'z';
+}
+
+inline char ascii_toupper(char c) {
+  return ascii_islower(c) ? c - ('a' - 'A') : c;
+}
+
+inline char ascii_tolower(char c) {
+  return ascii_isupper(c) ? c + ('a' - 'A') : c;
+}
+
+inline int hex_digit_to_int(char c) {
+  /* Assume ASCII. */
+  int x = static_cast<unsigned char>(c);
+  if (x > '9') {
+    x += 9;
+  }
+  return x & 0xf;
+}
+
+// ----------------------------------------------------------------------
+// HasPrefixString()
+//    Check if a string begins with a given prefix.
+// StripPrefixString()
+//    Given a string and a putative prefix, returns the string minus the
+//    prefix string if the prefix matches, otherwise the original
+//    string.
+// ----------------------------------------------------------------------
+inline bool HasPrefixString(StringPiece str, StringPiece prefix) {
+  return str.size() >= prefix.size() &&
+         memcmp(str.data(), prefix.data(), prefix.size()) == 0;
+}
+
+inline std::string StripPrefixString(const std::string& str,
+                                     const std::string& prefix) {
+  if (HasPrefixString(str, prefix)) {
+    return str.substr(prefix.size());
+  } else {
+    return str;
+  }
+}
+
+// ----------------------------------------------------------------------
+// HasSuffixString()
+//    Return true if str ends in suffix.
+// StripSuffixString()
+//    Given a string and a putative suffix, returns the string minus the
+//    suffix string if the suffix matches, otherwise the original
+//    string.
+// ----------------------------------------------------------------------
+inline bool HasSuffixString(StringPiece str, StringPiece suffix) {
+  return str.size() >= suffix.size() &&
+         memcmp(str.data() + str.size() - suffix.size(), suffix.data(),
+                suffix.size()) == 0;
+}
+
+inline std::string StripSuffixString(const std::string& str,
+                                     const std::string& suffix) {
+  if (HasSuffixString(str, suffix)) {
+    return str.substr(0, str.size() - suffix.size());
+  } else {
+    return str;
+  }
+}
+
+// ----------------------------------------------------------------------
+// ReplaceCharacters
+//    Replaces any occurrence of the character 'remove' (or the characters
+//    in 'remove') with the character 'replacewith'.
+//    Good for keeping html characters or protocol characters (\t) out
+//    of places where they might cause a problem.
+// StripWhitespace
+//    Removes whitespaces from both ends of the given string.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void ReplaceCharacters(std::string* s, const char* remove,
+                                       char replacewith);
+
+PROTOBUF_EXPORT void StripWhitespace(std::string* s);
+
+// ----------------------------------------------------------------------
+// LowerString()
+// UpperString()
+// ToUpper()
+//    Convert the characters in "s" to lowercase or uppercase.  ASCII-only:
+//    these functions intentionally ignore locale because they are applied to
+//    identifiers used in the Protocol Buffer language, not to natural-language
+//    strings.
+// ----------------------------------------------------------------------
+
+inline void LowerString(std::string* s) {
+  std::string::iterator end = s->end();
+  for (std::string::iterator i = s->begin(); i != end; ++i) {
+    // tolower() changes based on locale.  We don't want this!
+    if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
+  }
+}
+
+inline void UpperString(std::string* s) {
+  std::string::iterator end = s->end();
+  for (std::string::iterator i = s->begin(); i != end; ++i) {
+    // toupper() changes based on locale.  We don't want this!
+    if ('a' <= *i && *i <= 'z') *i += 'A' - 'a';
+  }
+}
+
+inline void ToUpper(std::string* s) { UpperString(s); }
+
+inline std::string ToUpper(const std::string& s) {
+  std::string out = s;
+  UpperString(&out);
+  return out;
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+//    Give me a string and two patterns "old" and "new", and I replace
+//    the first instance of "old" in the string with "new", if it
+//    exists.  RETURN a new string, regardless of whether the replacement
+//    happened or not.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT std::string StringReplace(const std::string& s,
+                                          const std::string& oldsub,
+                                          const std::string& newsub,
+                                          bool replace_all);
+
+// ----------------------------------------------------------------------
+// SplitStringUsing()
+//    Split a string using a character delimiter. Append the components
+//    to 'result'.  If there are consecutive delimiters, this function skips
+//    over all of them.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void SplitStringUsing(StringPiece full, const char* delim,
+                                      std::vector<std::string>* res);
+
+// Split a string using one or more byte delimiters, presented
+// as a nul-terminated c string. Append the components to 'result'.
+// If there are consecutive delimiters, this function will return
+// corresponding empty strings.  If you want to drop the empty
+// strings, try SplitStringUsing().
+//
+// If "full" is the empty string, yields an empty string as the only value.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void SplitStringAllowEmpty(StringPiece full, const char* delim,
+                                           std::vector<std::string>* result);
+
+// ----------------------------------------------------------------------
+// Split()
+//    Split a string using a character delimiter.
+// ----------------------------------------------------------------------
+inline std::vector<std::string> Split(StringPiece full, const char* delim,
+                                      bool skip_empty = true) {
+  std::vector<std::string> result;
+  if (skip_empty) {
+    SplitStringUsing(full, delim, &result);
+  } else {
+    SplitStringAllowEmpty(full, delim, &result);
+  }
+  return result;
+}
+
+// ----------------------------------------------------------------------
+// JoinStrings()
+//    These methods concatenate a vector of strings into a C++ string, using
+//    the C-string "delim" as a separator between components. There are two
+//    flavors of the function, one flavor returns the concatenated string,
+//    another takes a pointer to the target string. In the latter case the
+//    target string is cleared and overwritten.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void JoinStrings(const std::vector<std::string>& components,
+                                 const char* delim, std::string* result);
+
+inline std::string JoinStrings(const std::vector<std::string>& components,
+                               const char* delim) {
+  std::string result;
+  JoinStrings(components, delim, &result);
+  return result;
+}
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeSequences()
+//    Copies "source" to "dest", rewriting C-style escape sequences
+//    -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII
+//    equivalents.  "dest" must be sufficiently large to hold all
+//    the characters in the rewritten string (i.e. at least as large
+//    as strlen(source) + 1 should be safe, since the replacements
+//    are always shorter than the original escaped sequences).  It's
+//    safe for source and dest to be the same.  RETURNS the length
+//    of dest.
+//
+//    It allows hex sequences \xhh, or generally \xhhhhh with an
+//    arbitrary number of hex digits, but all of them together must
+//    specify a value of a single byte (e.g. \x0045 is equivalent
+//    to \x45, and \x1234 is erroneous).
+//
+//    It also allows escape sequences of the form \uhhhh (exactly four
+//    hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight
+//    hex digits, upper or lower case) to specify a Unicode code
+//    point. The dest array will contain the UTF8-encoded version of
+//    that code-point (e.g., if source contains \u2019, then dest will
+//    contain the three bytes 0xE2, 0x80, and 0x99).
+//
+//    Errors: In the first form of the call, errors are reported with
+//    LOG(ERROR). The same is true for the second form of the call if
+//    the pointer to the string std::vector is nullptr; otherwise, error
+//    messages are stored in the std::vector. In either case, the effect on
+//    the dest array is not defined, but rest of the source will be
+//    processed.
+//    ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest);
+PROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest,
+                                             std::vector<std::string>* errors);
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeString()
+//    This does the same thing as UnescapeCEscapeSequences, but creates
+//    a new string. The caller does not need to worry about allocating
+//    a dest buffer. This should be used for non performance critical
+//    tasks such as printing debug messages. It is safe for src and dest
+//    to be the same.
+//
+//    The second call stores its errors in a supplied string vector.
+//    If the string vector pointer is nullptr, it reports the errors with LOG().
+//
+//    In the first and second calls, the length of dest is returned. In the
+//    the third call, the new string is returned.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT int UnescapeCEscapeString(const std::string& src,
+                                          std::string* dest);
+PROTOBUF_EXPORT int UnescapeCEscapeString(const std::string& src,
+                                          std::string* dest,
+                                          std::vector<std::string>* errors);
+PROTOBUF_EXPORT std::string UnescapeCEscapeString(const std::string& src);
+
+// ----------------------------------------------------------------------
+// CEscape()
+//    Escapes 'src' using C-style escape sequences and returns the resulting
+//    string.
+//
+//    Escaped chars: \n, \r, \t, ", ', \, and !isprint().
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string CEscape(const std::string& src);
+
+// ----------------------------------------------------------------------
+// CEscapeAndAppend()
+//    Escapes 'src' using C-style escape sequences, and appends the escaped
+//    string to 'dest'.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, std::string* dest);
+
+namespace strings {
+// Like CEscape() but does not escape bytes with the upper bit set.
+PROTOBUF_EXPORT std::string Utf8SafeCEscape(const std::string& src);
+
+// Like CEscape() but uses hex (\x) escapes instead of octals.
+PROTOBUF_EXPORT std::string CHexEscape(const std::string& src);
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// strto32()
+// strtou32()
+// strto64()
+// strtou64()
+//    Architecture-neutral plug compatible replacements for strtol() and
+//    strtoul().  Long's have different lengths on ILP-32 and LP-64
+//    platforms, so using these is safer, from the point of view of
+//    overflow behavior, than using the standard libc functions.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int32_t strto32_adaptor(const char* nptr, char** endptr,
+                                        int base);
+PROTOBUF_EXPORT uint32_t strtou32_adaptor(const char* nptr, char** endptr,
+                                          int base);
+
+inline int32_t strto32(const char *nptr, char **endptr, int base) {
+  if (sizeof(int32_t) == sizeof(long))
+    return strtol(nptr, endptr, base);
+  else
+    return strto32_adaptor(nptr, endptr, base);
+}
+
+inline uint32_t strtou32(const char *nptr, char **endptr, int base) {
+  if (sizeof(uint32_t) == sizeof(unsigned long))
+    return strtoul(nptr, endptr, base);
+  else
+    return strtou32_adaptor(nptr, endptr, base);
+}
+
+// For now, long long is 64-bit on all the platforms we care about, so these
+// functions can simply pass the call to strto[u]ll.
+inline int64_t strto64(const char *nptr, char **endptr, int base) {
+  static_assert(sizeof(int64_t) == sizeof(long long),
+                "sizeof int64_t is not sizeof long long");
+  return strtoll(nptr, endptr, base);
+}
+
+inline uint64_t strtou64(const char *nptr, char **endptr, int base) {
+  static_assert(sizeof(uint64_t) == sizeof(unsigned long long),
+                "sizeof uint64_t is not sizeof unsigned long long");
+  return strtoull(nptr, endptr, base);
+}
+
+// ----------------------------------------------------------------------
+// safe_strtob()
+// safe_strto32()
+// safe_strtou32()
+// safe_strto64()
+// safe_strtou64()
+// safe_strtof()
+// safe_strtod()
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT bool safe_strtob(StringPiece str, bool* value);
+
+PROTOBUF_EXPORT bool safe_strto32(const std::string& str, int32_t* value);
+PROTOBUF_EXPORT bool safe_strtou32(const std::string& str, uint32_t* value);
+inline bool safe_strto32(const char* str, int32_t* value) {
+  return safe_strto32(std::string(str), value);
+}
+inline bool safe_strto32(StringPiece str, int32_t* value) {
+  return safe_strto32(str.ToString(), value);
+}
+inline bool safe_strtou32(const char* str, uint32_t* value) {
+  return safe_strtou32(std::string(str), value);
+}
+inline bool safe_strtou32(StringPiece str, uint32_t* value) {
+  return safe_strtou32(str.ToString(), value);
+}
+
+PROTOBUF_EXPORT bool safe_strto64(const std::string& str, int64_t* value);
+PROTOBUF_EXPORT bool safe_strtou64(const std::string& str, uint64_t* value);
+inline bool safe_strto64(const char* str, int64_t* value) {
+  return safe_strto64(std::string(str), value);
+}
+inline bool safe_strto64(StringPiece str, int64_t* value) {
+  return safe_strto64(str.ToString(), value);
+}
+inline bool safe_strtou64(const char* str, uint64_t* value) {
+  return safe_strtou64(std::string(str), value);
+}
+inline bool safe_strtou64(StringPiece str, uint64_t* value) {
+  return safe_strtou64(str.ToString(), value);
+}
+
+PROTOBUF_EXPORT bool safe_strtof(const char* str, float* value);
+PROTOBUF_EXPORT bool safe_strtod(const char* str, double* value);
+inline bool safe_strtof(const std::string& str, float* value) {
+  return safe_strtof(str.c_str(), value);
+}
+inline bool safe_strtod(const std::string& str, double* value) {
+  return safe_strtod(str.c_str(), value);
+}
+inline bool safe_strtof(StringPiece str, float* value) {
+  return safe_strtof(str.ToString(), value);
+}
+inline bool safe_strtod(StringPiece str, double* value) {
+  return safe_strtod(str.ToString(), value);
+}
+
+// ----------------------------------------------------------------------
+// FastIntToBuffer()
+// FastHexToBuffer()
+// FastHex64ToBuffer()
+// FastHex32ToBuffer()
+// FastTimeToBuffer()
+//    These are intended for speed.  FastIntToBuffer() assumes the
+//    integer is non-negative.  FastHexToBuffer() puts output in
+//    hex rather than decimal.  FastTimeToBuffer() puts the output
+//    into RFC822 format.
+//
+//    FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format,
+//    padded to exactly 16 bytes (plus one byte for '\0')
+//
+//    FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format,
+//    padded to exactly 8 bytes (plus one byte for '\0')
+//
+//       All functions take the output buffer as an arg.
+//    They all return a pointer to the beginning of the output,
+//    which may not be the beginning of the input buffer.
+// ----------------------------------------------------------------------
+
+// Suggested buffer size for FastToBuffer functions.  Also works with
+// DoubleToBuffer() and FloatToBuffer().
+static const int kFastToBufferSize = 32;
+
+PROTOBUF_EXPORT char* FastInt32ToBuffer(int32_t i, char* buffer);
+PROTOBUF_EXPORT char* FastInt64ToBuffer(int64_t i, char* buffer);
+char* FastUInt32ToBuffer(uint32_t i, char* buffer);  // inline below
+char* FastUInt64ToBuffer(uint64_t i, char* buffer);  // inline below
+PROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer);
+PROTOBUF_EXPORT char* FastHex64ToBuffer(uint64_t i, char* buffer);
+PROTOBUF_EXPORT char* FastHex32ToBuffer(uint32_t i, char* buffer);
+
+// at least 22 bytes long
+inline char* FastIntToBuffer(int i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
+}
+inline char* FastUIntToBuffer(unsigned int i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
+}
+inline char* FastLongToBuffer(long i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
+}
+inline char* FastULongToBuffer(unsigned long i, char* buffer) {
+  return (sizeof(i) == 4 ?
+          FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
+}
+
+// ----------------------------------------------------------------------
+// FastInt32ToBufferLeft()
+// FastUInt32ToBufferLeft()
+// FastInt64ToBufferLeft()
+// FastUInt64ToBufferLeft()
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer (hence the name, as the
+// output is left-aligned).  The caller is responsible for ensuring that
+// the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the string (i.e. the null character
+// terminating the string).
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32_t i, char* buffer);
+PROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32_t i, char* buffer);
+PROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64_t i, char* buffer);
+PROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64_t i, char* buffer);
+
+// Just define these in terms of the above.
+inline char* FastUInt32ToBuffer(uint32_t i, char* buffer) {
+  FastUInt32ToBufferLeft(i, buffer);
+  return buffer;
+}
+inline char* FastUInt64ToBuffer(uint64_t i, char* buffer) {
+  FastUInt64ToBufferLeft(i, buffer);
+  return buffer;
+}
+
+inline std::string SimpleBtoa(bool value) { return value ? "true" : "false"; }
+
+// ----------------------------------------------------------------------
+// SimpleItoa()
+//    Description: converts an integer to a string.
+//
+//    Return value: string
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string SimpleItoa(int i);
+PROTOBUF_EXPORT std::string SimpleItoa(unsigned int i);
+PROTOBUF_EXPORT std::string SimpleItoa(long i);
+PROTOBUF_EXPORT std::string SimpleItoa(unsigned long i);
+PROTOBUF_EXPORT std::string SimpleItoa(long long i);
+PROTOBUF_EXPORT std::string SimpleItoa(unsigned long long i);
+
+// ----------------------------------------------------------------------
+// SimpleDtoa()
+// SimpleFtoa()
+// DoubleToBuffer()
+// FloatToBuffer()
+//    Description: converts a double or float to a string which, if
+//    passed to NoLocaleStrtod(), will produce the exact same original double
+//    (except in case of NaN; all NaNs are considered the same value).
+//    We try to keep the string short but it's not guaranteed to be as
+//    short as possible.
+//
+//    DoubleToBuffer() and FloatToBuffer() write the text to the given
+//    buffer and return it.  The buffer must be at least
+//    kDoubleToBufferSize bytes for doubles and kFloatToBufferSize
+//    bytes for floats.  kFastToBufferSize is also guaranteed to be large
+//    enough to hold either.
+//
+//    Return value: string
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string SimpleDtoa(double value);
+PROTOBUF_EXPORT std::string SimpleFtoa(float value);
+
+PROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer);
+PROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer);
+
+// In practice, doubles should never need more than 24 bytes and floats
+// should never need more than 14 (including null terminators), but we
+// overestimate to be safe.
+static const int kDoubleToBufferSize = 32;
+static const int kFloatToBufferSize = 24;
+
+namespace strings {
+
+enum PadSpec {
+  NO_PAD = 1,
+  ZERO_PAD_2,
+  ZERO_PAD_3,
+  ZERO_PAD_4,
+  ZERO_PAD_5,
+  ZERO_PAD_6,
+  ZERO_PAD_7,
+  ZERO_PAD_8,
+  ZERO_PAD_9,
+  ZERO_PAD_10,
+  ZERO_PAD_11,
+  ZERO_PAD_12,
+  ZERO_PAD_13,
+  ZERO_PAD_14,
+  ZERO_PAD_15,
+  ZERO_PAD_16,
+};
+
+struct Hex {
+  uint64_t value;
+  enum PadSpec spec;
+  template <class Int>
+  explicit Hex(Int v, PadSpec s = NO_PAD)
+      : spec(s) {
+    // Prevent sign-extension by casting integers to
+    // their unsigned counterparts.
+#ifdef LANG_CXX11
+    static_assert(
+        sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
+        "Unknown integer type");
+#endif
+    value = sizeof(v) == 1 ? static_cast<uint8_t>(v)
+          : sizeof(v) == 2 ? static_cast<uint16_t>(v)
+          : sizeof(v) == 4 ? static_cast<uint32_t>(v)
+          : static_cast<uint64_t>(v);
+  }
+};
+
+struct PROTOBUF_EXPORT AlphaNum {
+  const char *piece_data_;  // move these to string_ref eventually
+  size_t piece_size_;       // move these to string_ref eventually
+
+  char digits[kFastToBufferSize];
+
+  // No bool ctor -- bools convert to an integral type.
+  // A bool ctor would also convert incoming pointers (bletch).
+
+  AlphaNum(int i32)
+      : piece_data_(digits),
+        piece_size_(FastInt32ToBufferLeft(i32, digits) - &digits[0]) {}
+  AlphaNum(unsigned int u32)
+      : piece_data_(digits),
+        piece_size_(FastUInt32ToBufferLeft(u32, digits) - &digits[0]) {}
+  AlphaNum(long long i64)
+      : piece_data_(digits),
+        piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
+  AlphaNum(unsigned long long u64)
+      : piece_data_(digits),
+        piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
+
+  // Note: on some architectures, "long" is only 32 bits, not 64, but the
+  // performance hit of using FastInt64ToBufferLeft to handle 32-bit values
+  // is quite minor.
+  AlphaNum(long i64)
+      : piece_data_(digits),
+        piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
+  AlphaNum(unsigned long u64)
+      : piece_data_(digits),
+        piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
+
+  AlphaNum(float f)
+    : piece_data_(digits), piece_size_(strlen(FloatToBuffer(f, digits))) {}
+  AlphaNum(double f)
+    : piece_data_(digits), piece_size_(strlen(DoubleToBuffer(f, digits))) {}
+
+  AlphaNum(Hex hex);
+
+  AlphaNum(const char* c_str)
+      : piece_data_(c_str), piece_size_(strlen(c_str)) {}
+  // TODO: Add a string_ref constructor, eventually
+  // AlphaNum(const StringPiece &pc) : piece(pc) {}
+
+  AlphaNum(const std::string& str)
+      : piece_data_(str.data()), piece_size_(str.size()) {}
+
+  AlphaNum(StringPiece str)
+      : piece_data_(str.data()), piece_size_(str.size()) {}
+
+  size_t size() const { return piece_size_; }
+  const char *data() const { return piece_data_; }
+
+ private:
+  // Use ":" not ':'
+  AlphaNum(char c);  // NOLINT(runtime/explicit)
+
+  // Disallow copy and assign.
+  AlphaNum(const AlphaNum&);
+  void operator=(const AlphaNum&);
+};
+
+}  // namespace strings
+
+using strings::AlphaNum;
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or numbers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, strings, bool values,
+//    and numeric values.
+//
+//    Don't use this for user-visible strings.  The localization process
+//    works poorly on strings built up out of fragments.
+//
+//    For clarity and performance, don't use StrCat when appending to a
+//    string.  In particular, avoid using any of these (anti-)patterns:
+//      str.append(StrCat(...)
+//      str += StrCat(...)
+//      str = StrCat(str, ...)
+//    where the last is the worse, with the potential to change a loop
+//    from a linear time operation with O(1) dynamic allocations into a
+//    quadratic time operation with O(n) dynamic allocations.  StrAppend
+//    is a better choice than any of the above, subject to the restriction
+//    of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
+//    be a reference into str.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e, const AlphaNum& f);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e, const AlphaNum& f,
+                                   const AlphaNum& g);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e, const AlphaNum& f,
+                                   const AlphaNum& g, const AlphaNum& h);
+PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d,
+                                   const AlphaNum& e, const AlphaNum& f,
+                                   const AlphaNum& g, const AlphaNum& h,
+                                   const AlphaNum& i);
+
+inline std::string StrCat(const AlphaNum& a) {
+  return std::string(a.data(), a.size());
+}
+
+// ----------------------------------------------------------------------
+// StrAppend()
+//    Same as above, but adds the output to the given string.
+//    WARNING: For speed, StrAppend does not try to check each of its input
+//    arguments to be sure that they are not a subset of the string being
+//    appended to.  That is, while this will work:
+//
+//    string s = "foo";
+//    s += s;
+//
+//    This will not (necessarily) work:
+//
+//    string s = "foo";
+//    StrAppend(&s, s);
+//
+//    Note: while StrCat supports appending up to 9 arguments, StrAppend
+//    is currently limited to 4.  That's rarely an issue except when
+//    automatically transforming StrCat to StrAppend, and can easily be
+//    worked around as consecutive calls to StrAppend are quite efficient.
+// ----------------------------------------------------------------------
+
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a);
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
+                               const AlphaNum& b);
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
+                               const AlphaNum& b, const AlphaNum& c);
+PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
+                               const AlphaNum& b, const AlphaNum& c,
+                               const AlphaNum& d);
+
+// ----------------------------------------------------------------------
+// Join()
+//    These methods concatenate a range of components into a C++ string, using
+//    the C-string "delim" as a separator between components.
+// ----------------------------------------------------------------------
+template <typename Iterator>
+void Join(Iterator start, Iterator end, const char* delim,
+          std::string* result) {
+  for (Iterator it = start; it != end; ++it) {
+    if (it != start) {
+      result->append(delim);
+    }
+    StrAppend(result, *it);
+  }
+}
+
+template <typename Range>
+std::string Join(const Range& components, const char* delim) {
+  std::string result;
+  Join(components.begin(), components.end(), delim, &result);
+  return result;
+}
+
+// ----------------------------------------------------------------------
+// ToHex()
+//    Return a lower-case hex string representation of the given integer.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT std::string ToHex(uint64_t num);
+
+// ----------------------------------------------------------------------
+// GlobalReplaceSubstring()
+//    Replaces all instances of a substring in a string.  Does nothing
+//    if 'substring' is empty.  Returns the number of replacements.
+//
+//    NOTE: The string pieces must not overlap s.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int GlobalReplaceSubstring(const std::string& substring,
+                                           const std::string& replacement,
+                                           std::string* s);
+
+// ----------------------------------------------------------------------
+// Base64Unescape()
+//    Converts "src" which is encoded in Base64 to its binary equivalent and
+//    writes it to "dest". If src contains invalid characters, dest is cleared
+//    and the function returns false. Returns true on success.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT bool Base64Unescape(StringPiece src, std::string* dest);
+
+// ----------------------------------------------------------------------
+// WebSafeBase64Unescape()
+//    This is a variation of Base64Unescape which uses '-' instead of '+', and
+//    '_' instead of '/'. src is not null terminated, instead specify len. I
+//    recommend that slen<szdest, but we honor szdest anyway.
+//    RETURNS the length of dest, or -1 if src contains invalid chars.
+
+//    The variation that stores into a string clears the string first, and
+//    returns false (with dest empty) if src contains invalid chars; for
+//    this version src and dest must be different strings.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int WebSafeBase64Unescape(const char* src, int slen, char* dest,
+                                          int szdest);
+PROTOBUF_EXPORT bool WebSafeBase64Unescape(StringPiece src, std::string* dest);
+
+// Return the length to use for the output buffer given to the base64 escape
+// routines. Make sure to use the same value for do_padding in both.
+// This function may return incorrect results if given input_len values that
+// are extremely high, which should happen rarely.
+PROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len, bool do_padding);
+// Use this version when calling Base64Escape without a do_padding arg.
+PROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len);
+
+// ----------------------------------------------------------------------
+// Base64Escape()
+// WebSafeBase64Escape()
+//    Encode "src" to "dest" using base64 encoding.
+//    src is not null terminated, instead specify len.
+//    'dest' should have at least CalculateBase64EscapedLen() length.
+//    RETURNS the length of dest.
+//    The WebSafe variation use '-' instead of '+' and '_' instead of '/'
+//    so that we can place the out in the URL or cookies without having
+//    to escape them.  It also has an extra parameter "do_padding",
+//    which when set to false will prevent padding with "=".
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int Base64Escape(const unsigned char* src, int slen, char* dest,
+                                 int szdest);
+PROTOBUF_EXPORT int WebSafeBase64Escape(const unsigned char* src, int slen,
+                                        char* dest, int szdest,
+                                        bool do_padding);
+// Encode src into dest with padding.
+PROTOBUF_EXPORT void Base64Escape(StringPiece src, std::string* dest);
+// Encode src into dest web-safely without padding.
+PROTOBUF_EXPORT void WebSafeBase64Escape(StringPiece src, std::string* dest);
+// Encode src into dest web-safely with padding.
+PROTOBUF_EXPORT void WebSafeBase64EscapeWithPadding(StringPiece src,
+                                                    std::string* dest);
+
+PROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc,
+                                  std::string* dest, bool do_padding);
+PROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc,
+                                         std::string* dest, bool do_padding);
+
+inline bool IsValidCodePoint(uint32_t code_point) {
+  return code_point < 0xD800 ||
+         (code_point >= 0xE000 && code_point <= 0x10FFFF);
+}
+
+static const int UTFmax = 4;
+// ----------------------------------------------------------------------
+// EncodeAsUTF8Char()
+//  Helper to append a Unicode code point to a string as UTF8, without bringing
+//  in any external dependencies. The output buffer must be as least 4 bytes
+//  large.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int EncodeAsUTF8Char(uint32_t code_point, char* output);
+
+// ----------------------------------------------------------------------
+// UTF8FirstLetterNumBytes()
+//   Length of the first UTF-8 character.
+// ----------------------------------------------------------------------
+PROTOBUF_EXPORT int UTF8FirstLetterNumBytes(const char* src, int len);
+
+// From google3/third_party/absl/strings/escaping.h
+
+// ----------------------------------------------------------------------
+// CleanStringLineEndings()
+//   Clean up a multi-line string to conform to Unix line endings.
+//   Reads from src and appends to dst, so usually dst should be empty.
+//
+//   If there is no line ending at the end of a non-empty string, it can
+//   be added automatically.
+//
+//   Four different types of input are correctly handled:
+//
+//     - Unix/Linux files: line ending is LF: pass through unchanged
+//
+//     - DOS/Windows files: line ending is CRLF: convert to LF
+//
+//     - Legacy Mac files: line ending is CR: convert to LF
+//
+//     - Garbled files: random line endings: convert gracefully
+//                      lonely CR, lonely LF, CRLF: convert to LF
+//
+//   @param src The multi-line string to convert
+//   @param dst The converted string is appended to this string
+//   @param auto_end_last_line Automatically terminate the last line
+//
+//   Limitations:
+//
+//     This does not do the right thing for CRCRLF files created by
+//     broken programs that do another Unix->DOS conversion on files
+//     that are already in CRLF format.  For this, a two-pass approach
+//     brute-force would be needed that
+//
+//       (1) determines the presence of LF (first one is ok)
+//       (2) if yes, removes any CR, else convert every CR to LF
+PROTOBUF_EXPORT void CleanStringLineEndings(const std::string& src,
+                                            std::string* dst,
+                                            bool auto_end_last_line);
+
+// Same as above, but transforms the argument in place.
+PROTOBUF_EXPORT void CleanStringLineEndings(std::string* str,
+                                            bool auto_end_last_line);
+
+namespace strings {
+inline bool EndsWith(StringPiece text, StringPiece suffix) {
+  return suffix.empty() ||
+      (text.size() >= suffix.size() &&
+       memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
+              suffix.size()) == 0);
+}
+}  // namespace strings
+
+namespace internal {
+
+// A locale-independent version of the standard strtod(), which always
+// uses a dot as the decimal separator.
+double NoLocaleStrtod(const char* str, char** endptr);
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/substitute.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/substitute.h
new file mode 100644
index 0000000..0f851de
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/substitute.h
@@ -0,0 +1,178 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// from google3/strings/substitute.h
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <string>
+
+#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
+#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+// ----------------------------------------------------------------------
+// strings::Substitute()
+// strings::SubstituteAndAppend()
+//   Kind of like StringPrintf, but different.
+//
+//   Example:
+//     string GetMessage(string first_name, string last_name, int age) {
+//       return strings::Substitute("My name is $0 $1 and I am $2 years old.",
+//                                  first_name, last_name, age);
+//     }
+//
+//   Differences from StringPrintf:
+//   * The format string does not identify the types of arguments.
+//     Instead, the magic of C++ deals with this for us.  See below
+//     for a list of accepted types.
+//   * Substitutions in the format string are identified by a '$'
+//     followed by a digit.  So, you can use arguments out-of-order and
+//     use the same argument multiple times.
+//   * It's much faster than StringPrintf.
+//
+//   Supported types:
+//   * Strings (const char*, const string&)
+//     * Note that this means you do not have to add .c_str() to all of
+//       your strings.  In fact, you shouldn't; it will be slower.
+//   * int32, int64, uint32, uint64:  Formatted using SimpleItoa().
+//   * float, double:  Formatted using SimpleFtoa() and SimpleDtoa().
+//   * bool:  Printed as "true" or "false".
+//
+//   SubstituteAndAppend() is like Substitute() but appends the result to
+//   *output.  Example:
+//
+//     string str;
+//     strings::SubstituteAndAppend(&str,
+//                                  "My name is $0 $1 and I am $2 years old.",
+//                                  first_name, last_name, age);
+//
+//   Substitute() is significantly faster than StringPrintf().  For very
+//   large strings, it may be orders of magnitude faster.
+// ----------------------------------------------------------------------
+
+namespace internal {  // Implementation details.
+
+class SubstituteArg {
+ public:
+  inline SubstituteArg(const char* value)
+    : text_(value), size_(strlen(text_)) {}
+  inline SubstituteArg(const std::string& value)
+      : text_(value.data()), size_(value.size()) {}
+  inline SubstituteArg(const StringPiece value)
+      : text_(value.data()), size_(value.size()) {}
+
+  // Indicates that no argument was given.
+  inline explicit SubstituteArg()
+    : text_(nullptr), size_(-1) {}
+
+  // Primitives
+  // We don't overload for signed and unsigned char because if people are
+  // explicitly declaring their chars as signed or unsigned then they are
+  // probably actually using them as 8-bit integers and would probably
+  // prefer an integer representation.  But, we don't really know.  So, we
+  // make the caller decide what to do.
+  inline SubstituteArg(char value)
+    : text_(scratch_), size_(1) { scratch_[0] = value; }
+  inline SubstituteArg(short value)
+    : text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned short value)
+    : text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(int value)
+    : text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned int value)
+    : text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(long value)
+    : text_(FastLongToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned long value)
+    : text_(FastULongToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(long long value)
+    : text_(FastInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(unsigned long long value)
+    : text_(FastUInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(float value)
+    : text_(FloatToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(double value)
+    : text_(DoubleToBuffer(value, scratch_)), size_(strlen(text_)) {}
+  inline SubstituteArg(bool value)
+    : text_(value ? "true" : "false"), size_(strlen(text_)) {}
+
+  inline const char* data() const { return text_; }
+  inline int size() const { return size_; }
+
+ private:
+  const char* text_;
+  int size_;
+  char scratch_[kFastToBufferSize];
+};
+
+}  // namespace internal
+
+PROTOBUF_EXPORT std::string Substitute(
+    const std::string& format,
+    const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg9 = internal::SubstituteArg());
+
+PROTOBUF_EXPORT void SubstituteAndAppend(
+    std::string* output, const char* format,
+    const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
+    const internal::SubstituteArg& arg9 = internal::SubstituteArg());
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/template_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/template_util.h
new file mode 100644
index 0000000..feef904
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/template_util.h
@@ -0,0 +1,138 @@
+// Copyright 2005 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ----
+// Author: lar@google.com (Laramie Leavitt)
+//
+// Template metaprogramming utility functions.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems.  Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+//
+// The names chosen here reflect those used in tr1 and the boost::mpl
+// library, there are similar operations used in the Loki library as
+// well.  I prefer the boost names for 2 reasons:
+// 1.  I think that portions of the Boost libraries are more likely to
+// be included in the c++ standard.
+// 2.  It is not impossible that some of the boost libraries will be
+// included in our own build in the future.
+// Both of these outcomes means that we may be able to directly replace
+// some of these with boost equivalents.
+//
+#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+  char dummy[2];
+};
+
+// Identity metafunction.
+template <class T>
+struct identity_ {
+  typedef T type;
+};
+
+// integral_constant, defined in tr1, is a wrapper for an integer
+// value. We don't really need this generality; we could get away
+// with hardcoding the integer type to bool. We use the fully
+// general integer_constant for compatibility with tr1.
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+
+// Abbreviations: true_type and false_type are structs that represent boolean
+// true and false values. Also define the boost::mpl versions of those names,
+// true_ and false_.
+typedef integral_constant<bool, true>  true_type;
+typedef integral_constant<bool, false> false_type;
+typedef true_type  true_;
+typedef false_type false_;
+
+// if_ is a templatized conditional statement.
+// if_<cond, A, B> is a compile time evaluation of cond.
+// if_<>::type contains A if cond is true, B otherwise.
+template<bool cond, typename A, typename B>
+struct if_{
+  typedef A type;
+};
+
+template<typename A, typename B>
+struct if_<false, A, B> {
+  typedef B type;
+};
+
+
+// type_equals_ is a template type comparator, similar to Loki IsSameType.
+// type_equals_<A, B>::value is true iff "A" is the same type as "B".
+//
+// New code should prefer base::is_same, defined in base/type_traits.h.
+// It is functionally identical, but is_same is the standard spelling.
+template<typename A, typename B>
+struct type_equals_ : public false_ {
+};
+
+template<typename A>
+struct type_equals_<A, A> : public true_ {
+};
+
+// and_ is a template && operator.
+// and_<A, B>::value evaluates "A::value && B::value".
+template<typename A, typename B>
+struct and_ : public integral_constant<bool, (A::value && B::value)> {
+};
+
+// or_ is a template || operator.
+// or_<A, B>::value evaluates "A::value || B::value".
+template<typename A, typename B>
+struct or_ : public integral_constant<bool, (A::value || B::value)> {
+};
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/time.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/time.h
new file mode 100644
index 0000000..8b6e562
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/stubs/time.h
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef GOOGLE_PROTOBUF_STUBS_TIME_H_
+#define GOOGLE_PROTOBUF_STUBS_TIME_H_
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+struct DateTime {
+  int year;
+  int month;
+  int day;
+  int hour;
+  int minute;
+  int second;
+};
+
+// Converts a timestamp (seconds elapsed since 1970-01-01T00:00:00, could be
+// negative to represent time before 1970-01-01) to DateTime. Returns false
+// if the timestamp is not in the range between 0001-01-01T00:00:00 and
+// 9999-12-31T23:59:59.
+bool PROTOBUF_EXPORT SecondsToDateTime(int64_t seconds, DateTime* time);
+// Converts DateTime to a timestamp (seconds since 1970-01-01T00:00:00).
+// Returns false if the DateTime is not valid or is not in the valid range.
+bool PROTOBUF_EXPORT DateTimeToSeconds(const DateTime& time, int64_t* seconds);
+
+void PROTOBUF_EXPORT GetCurrentTime(int64_t* seconds, int32_t* nanos);
+
+// Formats a time string in RFC3339 format.
+//
+// For example, "2015-05-20T13:29:35.120Z". For nanos, 0, 3, 6 or 9 fractional
+// digits will be used depending on how many are required to represent the exact
+// value.
+//
+// Note that "nanos" must in the range of [0, 999999999].
+std::string PROTOBUF_EXPORT FormatTime(int64_t seconds, int32_t nanos);
+// Parses a time string. This method accepts RFC3339 date/time string with UTC
+// offset. For example, "2015-05-20T13:29:35.120-08:00".
+bool PROTOBUF_EXPORT ParseTime(const std::string& value, int64_t* seconds,
+                               int32_t* nanos);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_STUBS_TIME_H_
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/text_format.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/text_format.h
new file mode 100644
index 0000000..e10bef7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/text_format.h
@@ -0,0 +1,693 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Utilities for printing and parsing protocol messages in a human-readable,
+// text-based format.
+
+#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
+#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
+
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+PROTOBUF_EXPORT extern const char kDebugStringSilentMarker[1];
+PROTOBUF_EXPORT extern const char kDebugStringSilentMarkerForDetection[3];
+}  // namespace internal
+
+namespace io {
+class ErrorCollector;  // tokenizer.h
+}
+
+// This class implements protocol buffer text format, colloquially known as text
+// proto.  Printing and parsing protocol messages in text format is useful for
+// debugging and human editing of messages.
+//
+// This class is really a namespace that contains only static methods.
+class PROTOBUF_EXPORT TextFormat {
+ public:
+  // Outputs a textual representation of the given message to the given
+  // output stream. Returns false if printing fails.
+  static bool Print(const Message& message, io::ZeroCopyOutputStream* output);
+
+  // Print the fields in an UnknownFieldSet.  They are printed by tag number
+  // only.  Embedded messages are heuristically identified by attempting to
+  // parse them. Returns false if printing fails.
+  static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+                                 io::ZeroCopyOutputStream* output);
+
+  // Like Print(), but outputs directly to a string.
+  // Note: output will be cleared prior to printing, and will be left empty
+  // even if printing fails. Returns false if printing fails.
+  static bool PrintToString(const Message& message, std::string* output);
+
+  // Like PrintUnknownFields(), but outputs directly to a string. Returns
+  // false if printing fails.
+  static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
+                                         std::string* output);
+
+  // Outputs a textual representation of the value of the field supplied on
+  // the message supplied. For non-repeated fields, an index of -1 must
+  // be supplied. Note that this method will print the default value for a
+  // field if it is not set.
+  static void PrintFieldValueToString(const Message& message,
+                                      const FieldDescriptor* field, int index,
+                                      std::string* output);
+
+  class PROTOBUF_EXPORT BaseTextGenerator {
+   public:
+    virtual ~BaseTextGenerator();
+
+    virtual void Indent() {}
+    virtual void Outdent() {}
+    // Returns the current indentation size in characters.
+    virtual size_t GetCurrentIndentationSize() const { return 0; }
+
+    // Print text to the output stream.
+    virtual void Print(const char* text, size_t size) = 0;
+
+    void PrintString(const std::string& str) { Print(str.data(), str.size()); }
+
+    template <size_t n>
+    void PrintLiteral(const char (&text)[n]) {
+      Print(text, n - 1);  // n includes the terminating zero character.
+    }
+  };
+
+  // The default printer that converts scalar values from fields into their
+  // string representation.
+  // You can derive from this FastFieldValuePrinter if you want to have fields
+  // to be printed in a different way and register it at the Printer.
+  class PROTOBUF_EXPORT FastFieldValuePrinter {
+   public:
+    FastFieldValuePrinter();
+    virtual ~FastFieldValuePrinter();
+    virtual void PrintBool(bool val, BaseTextGenerator* generator) const;
+    virtual void PrintInt32(int32_t val, BaseTextGenerator* generator) const;
+    virtual void PrintUInt32(uint32_t val, BaseTextGenerator* generator) const;
+    virtual void PrintInt64(int64_t val, BaseTextGenerator* generator) const;
+    virtual void PrintUInt64(uint64_t val, BaseTextGenerator* generator) const;
+    virtual void PrintFloat(float val, BaseTextGenerator* generator) const;
+    virtual void PrintDouble(double val, BaseTextGenerator* generator) const;
+    virtual void PrintString(const std::string& val,
+                             BaseTextGenerator* generator) const;
+    virtual void PrintBytes(const std::string& val,
+                            BaseTextGenerator* generator) const;
+    virtual void PrintEnum(int32_t val, const std::string& name,
+                           BaseTextGenerator* generator) const;
+    virtual void PrintFieldName(const Message& message, int field_index,
+                                int field_count, const Reflection* reflection,
+                                const FieldDescriptor* field,
+                                BaseTextGenerator* generator) const;
+    virtual void PrintFieldName(const Message& message,
+                                const Reflection* reflection,
+                                const FieldDescriptor* field,
+                                BaseTextGenerator* generator) const;
+    virtual void PrintMessageStart(const Message& message, int field_index,
+                                   int field_count, bool single_line_mode,
+                                   BaseTextGenerator* generator) const;
+    // Allows to override the logic on how to print the content of a message.
+    // Return false to use the default printing logic. Note that it is legal for
+    // this function to print something and then return false to use the default
+    // content printing (although at that point it would behave similarly to
+    // PrintMessageStart).
+    virtual bool PrintMessageContent(const Message& message, int field_index,
+                                     int field_count, bool single_line_mode,
+                                     BaseTextGenerator* generator) const;
+    virtual void PrintMessageEnd(const Message& message, int field_index,
+                                 int field_count, bool single_line_mode,
+                                 BaseTextGenerator* generator) const;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastFieldValuePrinter);
+  };
+
+  // Deprecated: please use FastFieldValuePrinter instead.
+  class PROTOBUF_EXPORT FieldValuePrinter {
+   public:
+    FieldValuePrinter();
+    virtual ~FieldValuePrinter();
+    virtual std::string PrintBool(bool val) const;
+    virtual std::string PrintInt32(int32_t val) const;
+    virtual std::string PrintUInt32(uint32_t val) const;
+    virtual std::string PrintInt64(int64_t val) const;
+    virtual std::string PrintUInt64(uint64_t val) const;
+    virtual std::string PrintFloat(float val) const;
+    virtual std::string PrintDouble(double val) const;
+    virtual std::string PrintString(const std::string& val) const;
+    virtual std::string PrintBytes(const std::string& val) const;
+    virtual std::string PrintEnum(int32_t val, const std::string& name) const;
+    virtual std::string PrintFieldName(const Message& message,
+                                       const Reflection* reflection,
+                                       const FieldDescriptor* field) const;
+    virtual std::string PrintMessageStart(const Message& message,
+                                          int field_index, int field_count,
+                                          bool single_line_mode) const;
+    virtual std::string PrintMessageEnd(const Message& message, int field_index,
+                                        int field_count,
+                                        bool single_line_mode) const;
+
+   private:
+    FastFieldValuePrinter delegate_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldValuePrinter);
+  };
+
+  class PROTOBUF_EXPORT MessagePrinter {
+   public:
+    MessagePrinter() {}
+    virtual ~MessagePrinter() {}
+    virtual void Print(const Message& message, bool single_line_mode,
+                       BaseTextGenerator* generator) const = 0;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessagePrinter);
+  };
+
+  // Interface that Printers or Parsers can use to find extensions, or types
+  // referenced in Any messages.
+  class PROTOBUF_EXPORT Finder {
+   public:
+    virtual ~Finder();
+
+    // Try to find an extension of *message by fully-qualified field
+    // name.  Returns nullptr if no extension is known for this name or number.
+    // The base implementation uses the extensions already known by the message.
+    virtual const FieldDescriptor* FindExtension(Message* message,
+                                                 const std::string& name) const;
+
+    // Similar to FindExtension, but uses a Descriptor and the extension number
+    // instead of using a Message and the name when doing the look up.
+    virtual const FieldDescriptor* FindExtensionByNumber(
+        const Descriptor* descriptor, int number) const;
+
+    // Find the message type for an Any proto.
+    // Returns nullptr if no message is known for this name.
+    // The base implementation only accepts prefixes of type.googleprod.com/ or
+    // type.googleapis.com/, and searches the DescriptorPool of the parent
+    // message.
+    virtual const Descriptor* FindAnyType(const Message& message,
+                                          const std::string& prefix,
+                                          const std::string& name) const;
+
+    // Find the message factory for the given extension field. This can be used
+    // to generalize the Parser to add extension fields to a message in the same
+    // way as the "input" message for the Parser.
+    virtual MessageFactory* FindExtensionFactory(
+        const FieldDescriptor* field) const;
+  };
+
+  // Class for those users which require more fine-grained control over how
+  // a protobuffer message is printed out.
+  class PROTOBUF_EXPORT Printer {
+   public:
+    Printer();
+
+    // Like TextFormat::Print
+    bool Print(const Message& message, io::ZeroCopyOutputStream* output) const;
+    // Like TextFormat::PrintUnknownFields
+    bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+                            io::ZeroCopyOutputStream* output) const;
+    // Like TextFormat::PrintToString
+    bool PrintToString(const Message& message, std::string* output) const;
+    // Like TextFormat::PrintUnknownFieldsToString
+    bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
+                                    std::string* output) const;
+    // Like TextFormat::PrintFieldValueToString
+    void PrintFieldValueToString(const Message& message,
+                                 const FieldDescriptor* field, int index,
+                                 std::string* output) const;
+
+    // Adjust the initial indent level of all output.  Each indent level is
+    // equal to two spaces.
+    void SetInitialIndentLevel(int indent_level) {
+      initial_indent_level_ = indent_level;
+    }
+
+    // If printing in single line mode, then the entire message will be output
+    // on a single line with no line breaks.
+    void SetSingleLineMode(bool single_line_mode) {
+      single_line_mode_ = single_line_mode;
+    }
+
+    bool IsInSingleLineMode() const { return single_line_mode_; }
+
+    // If use_field_number is true, uses field number instead of field name.
+    void SetUseFieldNumber(bool use_field_number) {
+      use_field_number_ = use_field_number;
+    }
+
+    // Set true to print repeated primitives in a format like:
+    //   field_name: [1, 2, 3, 4]
+    // instead of printing each value on its own line.  Short format applies
+    // only to primitive values -- i.e. everything except strings and
+    // sub-messages/groups.
+    void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) {
+      use_short_repeated_primitives_ = use_short_repeated_primitives;
+    }
+
+    // Set true to output UTF-8 instead of ASCII.  The only difference
+    // is that bytes >= 0x80 in string fields will not be escaped,
+    // because they are assumed to be part of UTF-8 multi-byte
+    // sequences. This will change the default FastFieldValuePrinter.
+    void SetUseUtf8StringEscaping(bool as_utf8);
+
+    // Set the default FastFieldValuePrinter that is used for all fields that
+    // don't have a field-specific printer registered.
+    // Takes ownership of the printer.
+    void SetDefaultFieldValuePrinter(const FastFieldValuePrinter* printer);
+
+    PROTOBUF_DEPRECATED_MSG("Please use FastFieldValuePrinter")
+    void SetDefaultFieldValuePrinter(const FieldValuePrinter* printer);
+
+    // Sets whether we want to hide unknown fields or not.
+    // Usually unknown fields are printed in a generic way that includes the
+    // tag number of the field instead of field name. However, sometimes it
+    // is useful to be able to print the message without unknown fields (e.g.
+    // for the python protobuf version to maintain consistency between its pure
+    // python and c++ implementations).
+    void SetHideUnknownFields(bool hide) { hide_unknown_fields_ = hide; }
+
+    // If print_message_fields_in_index_order is true, fields of a proto message
+    // will be printed using the order defined in source code instead of the
+    // field number, extensions will be printed at the end of the message
+    // and their relative order is determined by the extension number.
+    // By default, use the field number order.
+    void SetPrintMessageFieldsInIndexOrder(
+        bool print_message_fields_in_index_order) {
+      print_message_fields_in_index_order_ =
+          print_message_fields_in_index_order;
+    }
+
+    // If expand==true, expand google.protobuf.Any payloads. The output
+    // will be of form
+    //    [type_url] { <value_printed_in_text> }
+    //
+    // If expand==false, print Any using the default printer. The output will
+    // look like
+    //    type_url: "<type_url>"  value: "serialized_content"
+    void SetExpandAny(bool expand) { expand_any_ = expand; }
+
+    // Set how parser finds message for Any payloads.
+    void SetFinder(const Finder* finder) { finder_ = finder; }
+
+    // If non-zero, we truncate all string fields that are  longer than
+    // this threshold.  This is useful when the proto message has very long
+    // strings, e.g., dump of encoded image file.
+    //
+    // NOTE(hfgong):  Setting a non-zero value breaks round-trip safe
+    // property of TextFormat::Printer.  That is, from the printed message, we
+    // cannot fully recover the original string field any more.
+    void SetTruncateStringFieldLongerThan(
+        const int64_t truncate_string_field_longer_than) {
+      truncate_string_field_longer_than_ = truncate_string_field_longer_than;
+    }
+
+    // Register a custom field-specific FastFieldValuePrinter for fields
+    // with a particular FieldDescriptor.
+    // Returns "true" if the registration succeeded, or "false", if there is
+    // already a printer for that FieldDescriptor.
+    // Takes ownership of the printer on successful registration.
+    bool RegisterFieldValuePrinter(const FieldDescriptor* field,
+                                   const FastFieldValuePrinter* printer);
+
+    PROTOBUF_DEPRECATED_MSG("Please use FastFieldValuePrinter")
+    bool RegisterFieldValuePrinter(const FieldDescriptor* field,
+                                   const FieldValuePrinter* printer);
+
+    // Register a custom message-specific MessagePrinter for messages with a
+    // particular Descriptor.
+    // Returns "true" if the registration succeeded, or "false" if there is
+    // already a printer for that Descriptor.
+    bool RegisterMessagePrinter(const Descriptor* descriptor,
+                                const MessagePrinter* printer);
+
+   private:
+    friend std::string Message::DebugString() const;
+    friend std::string Message::ShortDebugString() const;
+    friend std::string Message::Utf8DebugString() const;
+
+    // Sets whether *DebugString should insert a silent marker.
+    void SetInsertSilentMarker(bool v) { insert_silent_marker_ = v; }
+
+    // Forward declaration of an internal class used to print the text
+    // output to the OutputStream (see text_format.cc for implementation).
+    class TextGenerator;
+
+    // Forward declaration of an internal class used to print field values for
+    // DebugString APIs (see text_format.cc for implementation).
+    class DebugStringFieldValuePrinter;
+
+    // Forward declaration of an internal class used to print UTF-8 escaped
+    // strings (see text_format.cc for implementation).
+    class FastFieldValuePrinterUtf8Escaping;
+
+    static const char* const kDoNotParse;
+
+    // Internal Print method, used for writing to the OutputStream via
+    // the TextGenerator class.
+    void Print(const Message& message, TextGenerator* generator) const;
+
+    // Print a single field.
+    void PrintField(const Message& message, const Reflection* reflection,
+                    const FieldDescriptor* field,
+                    TextGenerator* generator) const;
+
+    // Print a repeated primitive field in short form.
+    void PrintShortRepeatedField(const Message& message,
+                                 const Reflection* reflection,
+                                 const FieldDescriptor* field,
+                                 TextGenerator* generator) const;
+
+    // Print the name of a field -- i.e. everything that comes before the
+    // ':' for a single name/value pair.
+    void PrintFieldName(const Message& message, int field_index,
+                        int field_count, const Reflection* reflection,
+                        const FieldDescriptor* field,
+                        TextGenerator* generator) const;
+
+    // Outputs a textual representation of the value of the field supplied on
+    // the message supplied or the default value if not set.
+    void PrintFieldValue(const Message& message, const Reflection* reflection,
+                         const FieldDescriptor* field, int index,
+                         TextGenerator* generator) const;
+
+    // Print the fields in an UnknownFieldSet.  They are printed by tag number
+    // only.  Embedded messages are heuristically identified by attempting to
+    // parse them (subject to the recursion budget).
+    void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
+                            TextGenerator* generator,
+                            int recursion_budget) const;
+
+    bool PrintAny(const Message& message, TextGenerator* generator) const;
+
+    const FastFieldValuePrinter* GetFieldPrinter(
+        const FieldDescriptor* field) const {
+      auto it = custom_printers_.find(field);
+      return it == custom_printers_.end() ? default_field_value_printer_.get()
+                                          : it->second.get();
+    }
+
+    int initial_indent_level_;
+    bool single_line_mode_;
+    bool use_field_number_;
+    bool use_short_repeated_primitives_;
+    bool insert_silent_marker_;
+    bool hide_unknown_fields_;
+    bool print_message_fields_in_index_order_;
+    bool expand_any_;
+    int64_t truncate_string_field_longer_than_;
+
+    std::unique_ptr<const FastFieldValuePrinter> default_field_value_printer_;
+    typedef std::map<const FieldDescriptor*,
+                     std::unique_ptr<const FastFieldValuePrinter>>
+        CustomPrinterMap;
+    CustomPrinterMap custom_printers_;
+
+    typedef std::map<const Descriptor*, std::unique_ptr<const MessagePrinter>>
+        CustomMessagePrinterMap;
+    CustomMessagePrinterMap custom_message_printers_;
+
+    const Finder* finder_;
+  };
+
+  // Parses a text-format protocol message from the given input stream to
+  // the given message object. This function parses the human-readable
+  // serialization format written by Print(). Returns true on success. The
+  // message is cleared first, even if the function fails -- See Merge() to
+  // avoid this behavior.
+  //
+  // Example input: "user {\n id: 123 extra { gender: MALE language: 'en' }\n}"
+  //
+  // One common use for this function is parsing handwritten strings in test
+  // code.
+  //
+  // If you would like to read a protocol buffer serialized in the
+  // (non-human-readable) binary wire format, see
+  // google::protobuf::MessageLite::ParseFromString().
+  static bool Parse(io::ZeroCopyInputStream* input, Message* output);
+  // Like Parse(), but reads directly from a string.
+  static bool ParseFromString(ConstStringParam input, Message* output);
+
+  // Like Parse(), but the data is merged into the given message, as if
+  // using Message::MergeFrom().
+  static bool Merge(io::ZeroCopyInputStream* input, Message* output);
+  // Like Merge(), but reads directly from a string.
+  static bool MergeFromString(ConstStringParam input, Message* output);
+
+  // Parse the given text as a single field value and store it into the
+  // given field of the given message. If the field is a repeated field,
+  // the new value will be added to the end
+  static bool ParseFieldValueFromString(const std::string& input,
+                                        const FieldDescriptor* field,
+                                        Message* message);
+
+  // A location in the parsed text.
+  struct ParseLocation {
+    int line;
+    int column;
+
+    ParseLocation() : line(-1), column(-1) {}
+    ParseLocation(int line_param, int column_param)
+        : line(line_param), column(column_param) {}
+  };
+
+  // A range of locations in the parsed text, including `start` and excluding
+  // `end`.
+  struct ParseLocationRange {
+    ParseLocation start;
+    ParseLocation end;
+    ParseLocationRange() : start(), end() {}
+    ParseLocationRange(ParseLocation start_param, ParseLocation end_param)
+        : start(start_param), end(end_param) {}
+  };
+
+  // Data structure which is populated with the locations of each field
+  // value parsed from the text.
+  class PROTOBUF_EXPORT ParseInfoTree {
+   public:
+    ParseInfoTree() = default;
+    ParseInfoTree(const ParseInfoTree&) = delete;
+    ParseInfoTree& operator=(const ParseInfoTree&) = delete;
+
+    // Returns the parse location range for index-th value of the field in
+    // the parsed text. If none exists, returns a location with start and end
+    // line -1. Index should be -1 for not-repeated fields.
+    ParseLocationRange GetLocationRange(const FieldDescriptor* field,
+                                        int index) const;
+
+    // Returns the starting parse location for index-th value of the field in
+    // the parsed text. If none exists, returns a location with line = -1. Index
+    // should be -1 for not-repeated fields.
+    ParseLocation GetLocation(const FieldDescriptor* field, int index) const {
+      return GetLocationRange(field, index).start;
+    }
+
+    // Returns the parse info tree for the given field, which must be a message
+    // type. The nested information tree is owned by the root tree and will be
+    // deleted when it is deleted.
+    ParseInfoTree* GetTreeForNested(const FieldDescriptor* field,
+                                    int index) const;
+
+   private:
+    // Allow the text format parser to record information into the tree.
+    friend class TextFormat;
+
+    // Records the starting and ending locations of a single value for a field.
+    void RecordLocation(const FieldDescriptor* field, ParseLocationRange range);
+
+    // Create and records a nested tree for a nested message field.
+    ParseInfoTree* CreateNested(const FieldDescriptor* field);
+
+    // Defines the map from the index-th field descriptor to its parse location.
+    typedef std::map<const FieldDescriptor*, std::vector<ParseLocationRange>>
+        LocationMap;
+
+    // Defines the map from the index-th field descriptor to the nested parse
+    // info tree.
+    typedef std::map<const FieldDescriptor*,
+                     std::vector<std::unique_ptr<ParseInfoTree>>>
+        NestedMap;
+
+    LocationMap locations_;
+    NestedMap nested_;
+  };
+
+  // For more control over parsing, use this class.
+  class PROTOBUF_EXPORT Parser {
+   public:
+    Parser();
+    ~Parser();
+
+    // Like TextFormat::Parse().
+    bool Parse(io::ZeroCopyInputStream* input, Message* output);
+    // Like TextFormat::ParseFromString().
+    bool ParseFromString(ConstStringParam input, Message* output);
+    // Like TextFormat::Merge().
+    bool Merge(io::ZeroCopyInputStream* input, Message* output);
+    // Like TextFormat::MergeFromString().
+    bool MergeFromString(ConstStringParam input, Message* output);
+
+    // Set where to report parse errors.  If nullptr (the default), errors will
+    // be printed to stderr.
+    void RecordErrorsTo(io::ErrorCollector* error_collector) {
+      error_collector_ = error_collector;
+    }
+
+    // Set how parser finds extensions.  If nullptr (the default), the
+    // parser will use the standard Reflection object associated with
+    // the message being parsed.
+    void SetFinder(const Finder* finder) { finder_ = finder; }
+
+    // Sets where location information about the parse will be written. If
+    // nullptr
+    // (the default), then no location will be written.
+    void WriteLocationsTo(ParseInfoTree* tree) { parse_info_tree_ = tree; }
+
+    // Normally parsing fails if, after parsing, output->IsInitialized()
+    // returns false.  Call AllowPartialMessage(true) to skip this check.
+    void AllowPartialMessage(bool allow) { allow_partial_ = allow; }
+
+    // Allow field names to be matched case-insensitively.
+    // This is not advisable if there are fields that only differ in case, or
+    // if you want to enforce writing in the canonical form.
+    // This is 'false' by default.
+    void AllowCaseInsensitiveField(bool allow) {
+      allow_case_insensitive_field_ = allow;
+    }
+
+    // Like TextFormat::ParseFieldValueFromString
+    bool ParseFieldValueFromString(const std::string& input,
+                                   const FieldDescriptor* field,
+                                   Message* output);
+
+    // When an unknown extension is met, parsing will fail if this option is
+    // set to false (the default). If true, unknown extensions will be ignored
+    // and a warning message will be generated.
+    // Beware! Setting this option true may hide some errors (e.g. spelling
+    // error on extension name).  This allows data loss; unlike binary format,
+    // text format cannot preserve unknown extensions.  Avoid using this option
+    // if possible.
+    void AllowUnknownExtension(bool allow) { allow_unknown_extension_ = allow; }
+
+    // When an unknown field is met, parsing will fail if this option is set
+    // to false (the default). If true, unknown fields will be ignored and
+    // a warning message will be generated.
+    // Beware! Setting this option true may hide some errors (e.g. spelling
+    // error on field name). This allows data loss; unlike binary format, text
+    // format cannot preserve unknown fields.  Avoid using this option
+    // if possible.
+    void AllowUnknownField(bool allow) { allow_unknown_field_ = allow; }
+
+
+    void AllowFieldNumber(bool allow) { allow_field_number_ = allow; }
+
+    // Sets maximum recursion depth which parser can use. This is effectively
+    // the maximum allowed nesting of proto messages.
+    void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
+
+   private:
+    // Forward declaration of an internal class used to parse text
+    // representations (see text_format.cc for implementation).
+    class ParserImpl;
+
+    // Like TextFormat::Merge().  The provided implementation is used
+    // to do the parsing.
+    bool MergeUsingImpl(io::ZeroCopyInputStream* input, Message* output,
+                        ParserImpl* parser_impl);
+
+    io::ErrorCollector* error_collector_;
+    const Finder* finder_;
+    ParseInfoTree* parse_info_tree_;
+    bool allow_partial_;
+    bool allow_case_insensitive_field_;
+    bool allow_unknown_field_;
+    bool allow_unknown_extension_;
+    bool allow_unknown_enum_;
+    bool allow_field_number_;
+    bool allow_relaxed_whitespace_;
+    bool allow_singular_overwrites_;
+    int recursion_limit_;
+  };
+
+
+ private:
+  // Hack: ParseInfoTree declares TextFormat as a friend which should extend
+  // the friendship to TextFormat::Parser::ParserImpl, but unfortunately some
+  // old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide
+  // helpers for ParserImpl to call methods of ParseInfoTree.
+  static inline void RecordLocation(ParseInfoTree* info_tree,
+                                    const FieldDescriptor* field,
+                                    ParseLocationRange location);
+  static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
+                                            const FieldDescriptor* field);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
+};
+
+inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
+                                       const FieldDescriptor* field,
+                                       ParseLocationRange location) {
+  info_tree->RecordLocation(field, location);
+}
+
+inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
+    ParseInfoTree* info_tree, const FieldDescriptor* field) {
+  return info_tree->CreateNested(field);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_TEXT_FORMAT_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/timestamp.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/timestamp.pb.h
new file mode 100644
index 0000000..540194b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/timestamp.pb.h
@@ -0,0 +1,278 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftimestamp_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftimestamp_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ftimestamp_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ftimestamp_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Timestamp;
+struct TimestampDefaultTypeInternal;
+PROTOBUF_EXPORT extern TimestampDefaultTypeInternal _Timestamp_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Timestamp* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Timestamp>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT Timestamp final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Timestamp) */ {
+ public:
+  inline Timestamp() : Timestamp(nullptr) {}
+  ~Timestamp() override;
+  explicit PROTOBUF_CONSTEXPR Timestamp(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Timestamp(const Timestamp& from);
+  Timestamp(Timestamp&& from) noexcept
+    : Timestamp() {
+    *this = ::std::move(from);
+  }
+
+  inline Timestamp& operator=(const Timestamp& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Timestamp& operator=(Timestamp&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Timestamp& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Timestamp* internal_default_instance() {
+    return reinterpret_cast<const Timestamp*>(
+               &_Timestamp_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Timestamp& a, Timestamp& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Timestamp* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Timestamp* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Timestamp* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Timestamp>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Timestamp& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Timestamp& from) {
+    Timestamp::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Timestamp* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Timestamp";
+  }
+  protected:
+  explicit Timestamp(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kSecondsFieldNumber = 1,
+    kNanosFieldNumber = 2,
+  };
+  // int64 seconds = 1;
+  void clear_seconds();
+  int64_t seconds() const;
+  void set_seconds(int64_t value);
+  private:
+  int64_t _internal_seconds() const;
+  void _internal_set_seconds(int64_t value);
+  public:
+
+  // int32 nanos = 2;
+  void clear_nanos();
+  int32_t nanos() const;
+  void set_nanos(int32_t value);
+  private:
+  int32_t _internal_nanos() const;
+  void _internal_set_nanos(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Timestamp)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int64_t seconds_;
+    int32_t nanos_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftimestamp_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Timestamp
+
+// int64 seconds = 1;
+inline void Timestamp::clear_seconds() {
+  _impl_.seconds_ = int64_t{0};
+}
+inline int64_t Timestamp::_internal_seconds() const {
+  return _impl_.seconds_;
+}
+inline int64_t Timestamp::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.seconds)
+  return _internal_seconds();
+}
+inline void Timestamp::_internal_set_seconds(int64_t value) {
+  
+  _impl_.seconds_ = value;
+}
+inline void Timestamp::set_seconds(int64_t value) {
+  _internal_set_seconds(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.seconds)
+}
+
+// int32 nanos = 2;
+inline void Timestamp::clear_nanos() {
+  _impl_.nanos_ = 0;
+}
+inline int32_t Timestamp::_internal_nanos() const {
+  return _impl_.nanos_;
+}
+inline int32_t Timestamp::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.nanos)
+  return _internal_nanos();
+}
+inline void Timestamp::_internal_set_nanos(int32_t value) {
+  
+  _impl_.nanos_ = value;
+}
+inline void Timestamp::set_nanos(int32_t value) {
+  _internal_set_nanos(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.nanos)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftimestamp_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/type.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/type.pb.h
new file mode 100644
index 0000000..cb8105a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/type.pb.h
@@ -0,0 +1,2571 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftype_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftype_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/source_context.pb.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ftype_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ftype_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class Enum;
+struct EnumDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumDefaultTypeInternal _Enum_default_instance_;
+class EnumValue;
+struct EnumValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern EnumValueDefaultTypeInternal _EnumValue_default_instance_;
+class Field;
+struct FieldDefaultTypeInternal;
+PROTOBUF_EXPORT extern FieldDefaultTypeInternal _Field_default_instance_;
+class Option;
+struct OptionDefaultTypeInternal;
+PROTOBUF_EXPORT extern OptionDefaultTypeInternal _Option_default_instance_;
+class Type;
+struct TypeDefaultTypeInternal;
+PROTOBUF_EXPORT extern TypeDefaultTypeInternal _Type_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Enum* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Enum>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::EnumValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::EnumValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Field* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Field>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Option* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Option>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Type* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Type>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+enum Field_Kind : int {
+  Field_Kind_TYPE_UNKNOWN = 0,
+  Field_Kind_TYPE_DOUBLE = 1,
+  Field_Kind_TYPE_FLOAT = 2,
+  Field_Kind_TYPE_INT64 = 3,
+  Field_Kind_TYPE_UINT64 = 4,
+  Field_Kind_TYPE_INT32 = 5,
+  Field_Kind_TYPE_FIXED64 = 6,
+  Field_Kind_TYPE_FIXED32 = 7,
+  Field_Kind_TYPE_BOOL = 8,
+  Field_Kind_TYPE_STRING = 9,
+  Field_Kind_TYPE_GROUP = 10,
+  Field_Kind_TYPE_MESSAGE = 11,
+  Field_Kind_TYPE_BYTES = 12,
+  Field_Kind_TYPE_UINT32 = 13,
+  Field_Kind_TYPE_ENUM = 14,
+  Field_Kind_TYPE_SFIXED32 = 15,
+  Field_Kind_TYPE_SFIXED64 = 16,
+  Field_Kind_TYPE_SINT32 = 17,
+  Field_Kind_TYPE_SINT64 = 18,
+  Field_Kind_Field_Kind_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
+  Field_Kind_Field_Kind_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool Field_Kind_IsValid(int value);
+constexpr Field_Kind Field_Kind_Kind_MIN = Field_Kind_TYPE_UNKNOWN;
+constexpr Field_Kind Field_Kind_Kind_MAX = Field_Kind_TYPE_SINT64;
+constexpr int Field_Kind_Kind_ARRAYSIZE = Field_Kind_Kind_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Kind_descriptor();
+template<typename T>
+inline const std::string& Field_Kind_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, Field_Kind>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function Field_Kind_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    Field_Kind_descriptor(), enum_t_value);
+}
+inline bool Field_Kind_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Field_Kind* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<Field_Kind>(
+    Field_Kind_descriptor(), name, value);
+}
+enum Field_Cardinality : int {
+  Field_Cardinality_CARDINALITY_UNKNOWN = 0,
+  Field_Cardinality_CARDINALITY_OPTIONAL = 1,
+  Field_Cardinality_CARDINALITY_REQUIRED = 2,
+  Field_Cardinality_CARDINALITY_REPEATED = 3,
+  Field_Cardinality_Field_Cardinality_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
+  Field_Cardinality_Field_Cardinality_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool Field_Cardinality_IsValid(int value);
+constexpr Field_Cardinality Field_Cardinality_Cardinality_MIN = Field_Cardinality_CARDINALITY_UNKNOWN;
+constexpr Field_Cardinality Field_Cardinality_Cardinality_MAX = Field_Cardinality_CARDINALITY_REPEATED;
+constexpr int Field_Cardinality_Cardinality_ARRAYSIZE = Field_Cardinality_Cardinality_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Cardinality_descriptor();
+template<typename T>
+inline const std::string& Field_Cardinality_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, Field_Cardinality>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function Field_Cardinality_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    Field_Cardinality_descriptor(), enum_t_value);
+}
+inline bool Field_Cardinality_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Field_Cardinality* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<Field_Cardinality>(
+    Field_Cardinality_descriptor(), name, value);
+}
+enum Syntax : int {
+  SYNTAX_PROTO2 = 0,
+  SYNTAX_PROTO3 = 1,
+  Syntax_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
+  Syntax_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
+};
+PROTOBUF_EXPORT bool Syntax_IsValid(int value);
+constexpr Syntax Syntax_MIN = SYNTAX_PROTO2;
+constexpr Syntax Syntax_MAX = SYNTAX_PROTO3;
+constexpr int Syntax_ARRAYSIZE = Syntax_MAX + 1;
+
+PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Syntax_descriptor();
+template<typename T>
+inline const std::string& Syntax_Name(T enum_t_value) {
+  static_assert(::std::is_same<T, Syntax>::value ||
+    ::std::is_integral<T>::value,
+    "Incorrect type passed to function Syntax_Name.");
+  return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
+    Syntax_descriptor(), enum_t_value);
+}
+inline bool Syntax_Parse(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Syntax* value) {
+  return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<Syntax>(
+    Syntax_descriptor(), name, value);
+}
+// ===================================================================
+
+class PROTOBUF_EXPORT Type final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Type) */ {
+ public:
+  inline Type() : Type(nullptr) {}
+  ~Type() override;
+  explicit PROTOBUF_CONSTEXPR Type(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Type(const Type& from);
+  Type(Type&& from) noexcept
+    : Type() {
+    *this = ::std::move(from);
+  }
+
+  inline Type& operator=(const Type& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Type& operator=(Type&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Type& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Type* internal_default_instance() {
+    return reinterpret_cast<const Type*>(
+               &_Type_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(Type& a, Type& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Type* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Type* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Type* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Type>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Type& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Type& from) {
+    Type::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Type* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Type";
+  }
+  protected:
+  explicit Type(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kFieldsFieldNumber = 2,
+    kOneofsFieldNumber = 3,
+    kOptionsFieldNumber = 4,
+    kNameFieldNumber = 1,
+    kSourceContextFieldNumber = 5,
+    kSyntaxFieldNumber = 6,
+  };
+  // repeated .google.protobuf.Field fields = 2;
+  int fields_size() const;
+  private:
+  int _internal_fields_size() const;
+  public:
+  void clear_fields();
+  ::PROTOBUF_NAMESPACE_ID::Field* mutable_fields(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >*
+      mutable_fields();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Field& _internal_fields(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Field* _internal_add_fields();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Field& fields(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Field* add_fields();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >&
+      fields() const;
+
+  // repeated string oneofs = 3;
+  int oneofs_size() const;
+  private:
+  int _internal_oneofs_size() const;
+  public:
+  void clear_oneofs();
+  const std::string& oneofs(int index) const;
+  std::string* mutable_oneofs(int index);
+  void set_oneofs(int index, const std::string& value);
+  void set_oneofs(int index, std::string&& value);
+  void set_oneofs(int index, const char* value);
+  void set_oneofs(int index, const char* value, size_t size);
+  std::string* add_oneofs();
+  void add_oneofs(const std::string& value);
+  void add_oneofs(std::string&& value);
+  void add_oneofs(const char* value);
+  void add_oneofs(const char* value, size_t size);
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& oneofs() const;
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_oneofs();
+  private:
+  const std::string& _internal_oneofs(int index) const;
+  std::string* _internal_add_oneofs();
+  public:
+
+  // repeated .google.protobuf.Option options = 4;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // .google.protobuf.SourceContext source_context = 5;
+  bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
+  void clear_source_context();
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
+  void set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& _internal_source_context() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _internal_mutable_source_context();
+  public:
+  void unsafe_arena_set_allocated_source_context(
+      ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* unsafe_arena_release_source_context();
+
+  // .google.protobuf.Syntax syntax = 6;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Type)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field > fields_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> oneofs_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Field final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Field) */ {
+ public:
+  inline Field() : Field(nullptr) {}
+  ~Field() override;
+  explicit PROTOBUF_CONSTEXPR Field(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Field(const Field& from);
+  Field(Field&& from) noexcept
+    : Field() {
+    *this = ::std::move(from);
+  }
+
+  inline Field& operator=(const Field& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Field& operator=(Field&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Field& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Field* internal_default_instance() {
+    return reinterpret_cast<const Field*>(
+               &_Field_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(Field& a, Field& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Field* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Field* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Field* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Field>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Field& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Field& from) {
+    Field::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Field* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Field";
+  }
+  protected:
+  explicit Field(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  typedef Field_Kind Kind;
+  static constexpr Kind TYPE_UNKNOWN =
+    Field_Kind_TYPE_UNKNOWN;
+  static constexpr Kind TYPE_DOUBLE =
+    Field_Kind_TYPE_DOUBLE;
+  static constexpr Kind TYPE_FLOAT =
+    Field_Kind_TYPE_FLOAT;
+  static constexpr Kind TYPE_INT64 =
+    Field_Kind_TYPE_INT64;
+  static constexpr Kind TYPE_UINT64 =
+    Field_Kind_TYPE_UINT64;
+  static constexpr Kind TYPE_INT32 =
+    Field_Kind_TYPE_INT32;
+  static constexpr Kind TYPE_FIXED64 =
+    Field_Kind_TYPE_FIXED64;
+  static constexpr Kind TYPE_FIXED32 =
+    Field_Kind_TYPE_FIXED32;
+  static constexpr Kind TYPE_BOOL =
+    Field_Kind_TYPE_BOOL;
+  static constexpr Kind TYPE_STRING =
+    Field_Kind_TYPE_STRING;
+  static constexpr Kind TYPE_GROUP =
+    Field_Kind_TYPE_GROUP;
+  static constexpr Kind TYPE_MESSAGE =
+    Field_Kind_TYPE_MESSAGE;
+  static constexpr Kind TYPE_BYTES =
+    Field_Kind_TYPE_BYTES;
+  static constexpr Kind TYPE_UINT32 =
+    Field_Kind_TYPE_UINT32;
+  static constexpr Kind TYPE_ENUM =
+    Field_Kind_TYPE_ENUM;
+  static constexpr Kind TYPE_SFIXED32 =
+    Field_Kind_TYPE_SFIXED32;
+  static constexpr Kind TYPE_SFIXED64 =
+    Field_Kind_TYPE_SFIXED64;
+  static constexpr Kind TYPE_SINT32 =
+    Field_Kind_TYPE_SINT32;
+  static constexpr Kind TYPE_SINT64 =
+    Field_Kind_TYPE_SINT64;
+  static inline bool Kind_IsValid(int value) {
+    return Field_Kind_IsValid(value);
+  }
+  static constexpr Kind Kind_MIN =
+    Field_Kind_Kind_MIN;
+  static constexpr Kind Kind_MAX =
+    Field_Kind_Kind_MAX;
+  static constexpr int Kind_ARRAYSIZE =
+    Field_Kind_Kind_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Kind_descriptor() {
+    return Field_Kind_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Kind_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Kind>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Kind_Name.");
+    return Field_Kind_Name(enum_t_value);
+  }
+  static inline bool Kind_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Kind* value) {
+    return Field_Kind_Parse(name, value);
+  }
+
+  typedef Field_Cardinality Cardinality;
+  static constexpr Cardinality CARDINALITY_UNKNOWN =
+    Field_Cardinality_CARDINALITY_UNKNOWN;
+  static constexpr Cardinality CARDINALITY_OPTIONAL =
+    Field_Cardinality_CARDINALITY_OPTIONAL;
+  static constexpr Cardinality CARDINALITY_REQUIRED =
+    Field_Cardinality_CARDINALITY_REQUIRED;
+  static constexpr Cardinality CARDINALITY_REPEATED =
+    Field_Cardinality_CARDINALITY_REPEATED;
+  static inline bool Cardinality_IsValid(int value) {
+    return Field_Cardinality_IsValid(value);
+  }
+  static constexpr Cardinality Cardinality_MIN =
+    Field_Cardinality_Cardinality_MIN;
+  static constexpr Cardinality Cardinality_MAX =
+    Field_Cardinality_Cardinality_MAX;
+  static constexpr int Cardinality_ARRAYSIZE =
+    Field_Cardinality_Cardinality_ARRAYSIZE;
+  static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
+  Cardinality_descriptor() {
+    return Field_Cardinality_descriptor();
+  }
+  template<typename T>
+  static inline const std::string& Cardinality_Name(T enum_t_value) {
+    static_assert(::std::is_same<T, Cardinality>::value ||
+      ::std::is_integral<T>::value,
+      "Incorrect type passed to function Cardinality_Name.");
+    return Field_Cardinality_Name(enum_t_value);
+  }
+  static inline bool Cardinality_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
+      Cardinality* value) {
+    return Field_Cardinality_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 9,
+    kNameFieldNumber = 4,
+    kTypeUrlFieldNumber = 6,
+    kJsonNameFieldNumber = 10,
+    kDefaultValueFieldNumber = 11,
+    kKindFieldNumber = 1,
+    kCardinalityFieldNumber = 2,
+    kNumberFieldNumber = 3,
+    kOneofIndexFieldNumber = 7,
+    kPackedFieldNumber = 8,
+  };
+  // repeated .google.protobuf.Option options = 9;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 4;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // string type_url = 6;
+  void clear_type_url();
+  const std::string& type_url() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_type_url(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_type_url();
+  PROTOBUF_NODISCARD std::string* release_type_url();
+  void set_allocated_type_url(std::string* type_url);
+  private:
+  const std::string& _internal_type_url() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_url(const std::string& value);
+  std::string* _internal_mutable_type_url();
+  public:
+
+  // string json_name = 10;
+  void clear_json_name();
+  const std::string& json_name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_json_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_json_name();
+  PROTOBUF_NODISCARD std::string* release_json_name();
+  void set_allocated_json_name(std::string* json_name);
+  private:
+  const std::string& _internal_json_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_json_name(const std::string& value);
+  std::string* _internal_mutable_json_name();
+  public:
+
+  // string default_value = 11;
+  void clear_default_value();
+  const std::string& default_value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_default_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_default_value();
+  PROTOBUF_NODISCARD std::string* release_default_value();
+  void set_allocated_default_value(std::string* default_value);
+  private:
+  const std::string& _internal_default_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_default_value(const std::string& value);
+  std::string* _internal_mutable_default_value();
+  public:
+
+  // .google.protobuf.Field.Kind kind = 1;
+  void clear_kind();
+  ::PROTOBUF_NAMESPACE_ID::Field_Kind kind() const;
+  void set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Field_Kind _internal_kind() const;
+  void _internal_set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value);
+  public:
+
+  // .google.protobuf.Field.Cardinality cardinality = 2;
+  void clear_cardinality();
+  ::PROTOBUF_NAMESPACE_ID::Field_Cardinality cardinality() const;
+  void set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Field_Cardinality _internal_cardinality() const;
+  void _internal_set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value);
+  public:
+
+  // int32 number = 3;
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // int32 oneof_index = 7;
+  void clear_oneof_index();
+  int32_t oneof_index() const;
+  void set_oneof_index(int32_t value);
+  private:
+  int32_t _internal_oneof_index() const;
+  void _internal_set_oneof_index(int32_t value);
+  public:
+
+  // bool packed = 8;
+  void clear_packed();
+  bool packed() const;
+  void set_packed(bool value);
+  private:
+  bool _internal_packed() const;
+  void _internal_set_packed(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Field)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_url_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr json_name_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr default_value_;
+    int kind_;
+    int cardinality_;
+    int32_t number_;
+    int32_t oneof_index_;
+    bool packed_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Enum final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Enum) */ {
+ public:
+  inline Enum() : Enum(nullptr) {}
+  ~Enum() override;
+  explicit PROTOBUF_CONSTEXPR Enum(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Enum(const Enum& from);
+  Enum(Enum&& from) noexcept
+    : Enum() {
+    *this = ::std::move(from);
+  }
+
+  inline Enum& operator=(const Enum& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Enum& operator=(Enum&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Enum& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Enum* internal_default_instance() {
+    return reinterpret_cast<const Enum*>(
+               &_Enum_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Enum& a, Enum& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Enum* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Enum* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Enum* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Enum>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Enum& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Enum& from) {
+    Enum::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Enum* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Enum";
+  }
+  protected:
+  explicit Enum(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kEnumvalueFieldNumber = 2,
+    kOptionsFieldNumber = 3,
+    kNameFieldNumber = 1,
+    kSourceContextFieldNumber = 4,
+    kSyntaxFieldNumber = 5,
+  };
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  int enumvalue_size() const;
+  private:
+  int _internal_enumvalue_size() const;
+  public:
+  void clear_enumvalue();
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* mutable_enumvalue(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >*
+      mutable_enumvalue();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValue& _internal_enumvalue(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* _internal_add_enumvalue();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::EnumValue& enumvalue(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* add_enumvalue();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >&
+      enumvalue() const;
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // .google.protobuf.SourceContext source_context = 4;
+  bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
+  void clear_source_context();
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
+  void set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext& _internal_source_context() const;
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _internal_mutable_source_context();
+  public:
+  void unsafe_arena_set_allocated_source_context(
+      ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context);
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* unsafe_arena_release_source_context();
+
+  // .google.protobuf.Syntax syntax = 5;
+  void clear_syntax();
+  ::PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
+  void set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::Syntax _internal_syntax() const;
+  void _internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Enum)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue > enumvalue_;
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
+    int syntax_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT EnumValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValue) */ {
+ public:
+  inline EnumValue() : EnumValue(nullptr) {}
+  ~EnumValue() override;
+  explicit PROTOBUF_CONSTEXPR EnumValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  EnumValue(const EnumValue& from);
+  EnumValue(EnumValue&& from) noexcept
+    : EnumValue() {
+    *this = ::std::move(from);
+  }
+
+  inline EnumValue& operator=(const EnumValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline EnumValue& operator=(EnumValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const EnumValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const EnumValue* internal_default_instance() {
+    return reinterpret_cast<const EnumValue*>(
+               &_EnumValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(EnumValue& a, EnumValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(EnumValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  EnumValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<EnumValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const EnumValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const EnumValue& from) {
+    EnumValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(EnumValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValue";
+  }
+  protected:
+  explicit EnumValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kOptionsFieldNumber = 3,
+    kNameFieldNumber = 1,
+    kNumberFieldNumber = 2,
+  };
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  private:
+  int _internal_options_size() const;
+  public:
+  void clear_options();
+  ::PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
+  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+      mutable_options();
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Option& _internal_options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* _internal_add_options();
+  public:
+  const ::PROTOBUF_NAMESPACE_ID::Option& options(int index) const;
+  ::PROTOBUF_NAMESPACE_ID::Option* add_options();
+  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+      options() const;
+
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // int32 number = 2;
+  void clear_number();
+  int32_t number() const;
+  void set_number(int32_t value);
+  private:
+  int32_t _internal_number() const;
+  void _internal_set_number(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    int32_t number_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Option final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Option) */ {
+ public:
+  inline Option() : Option(nullptr) {}
+  ~Option() override;
+  explicit PROTOBUF_CONSTEXPR Option(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Option(const Option& from);
+  Option(Option&& from) noexcept
+    : Option() {
+    *this = ::std::move(from);
+  }
+
+  inline Option& operator=(const Option& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Option& operator=(Option&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Option& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Option* internal_default_instance() {
+    return reinterpret_cast<const Option*>(
+               &_Option_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    4;
+
+  friend void swap(Option& a, Option& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Option* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Option* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Option* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Option>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Option& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Option& from) {
+    Option::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Option* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Option";
+  }
+  protected:
+  explicit Option(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kNameFieldNumber = 1,
+    kValueFieldNumber = 2,
+  };
+  // string name = 1;
+  void clear_name();
+  const std::string& name() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_name(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_name();
+  PROTOBUF_NODISCARD std::string* release_name();
+  void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
+
+  // .google.protobuf.Any value = 2;
+  bool has_value() const;
+  private:
+  bool _internal_has_value() const;
+  public:
+  void clear_value();
+  const ::PROTOBUF_NAMESPACE_ID::Any& value() const;
+  PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::Any* release_value();
+  ::PROTOBUF_NAMESPACE_ID::Any* mutable_value();
+  void set_allocated_value(::PROTOBUF_NAMESPACE_ID::Any* value);
+  private:
+  const ::PROTOBUF_NAMESPACE_ID::Any& _internal_value() const;
+  ::PROTOBUF_NAMESPACE_ID::Any* _internal_mutable_value();
+  public:
+  void unsafe_arena_set_allocated_value(
+      ::PROTOBUF_NAMESPACE_ID::Any* value);
+  ::PROTOBUF_NAMESPACE_ID::Any* unsafe_arena_release_value();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Option)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+    ::PROTOBUF_NAMESPACE_ID::Any* value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2ftype_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Type
+
+// string name = 1;
+inline void Type::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Type::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Type::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.name)
+}
+inline std::string* Type::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.name)
+  return _s;
+}
+inline const std::string& Type::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Type::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Type::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Type::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.name)
+  return _impl_.name_.Release();
+}
+inline void Type::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.name)
+}
+
+// repeated .google.protobuf.Field fields = 2;
+inline int Type::_internal_fields_size() const {
+  return _impl_.fields_.size();
+}
+inline int Type::fields_size() const {
+  return _internal_fields_size();
+}
+inline void Type::clear_fields() {
+  _impl_.fields_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field* Type::mutable_fields(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.fields)
+  return _impl_.fields_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >*
+Type::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.fields)
+  return &_impl_.fields_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Field& Type::_internal_fields(int index) const {
+  return _impl_.fields_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Field& Type::fields(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.fields)
+  return _internal_fields(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field* Type::_internal_add_fields() {
+  return _impl_.fields_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field* Type::add_fields() {
+  ::PROTOBUF_NAMESPACE_ID::Field* _add = _internal_add_fields();
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.fields)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Field >&
+Type::fields() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.fields)
+  return _impl_.fields_;
+}
+
+// repeated string oneofs = 3;
+inline int Type::_internal_oneofs_size() const {
+  return _impl_.oneofs_.size();
+}
+inline int Type::oneofs_size() const {
+  return _internal_oneofs_size();
+}
+inline void Type::clear_oneofs() {
+  _impl_.oneofs_.Clear();
+}
+inline std::string* Type::add_oneofs() {
+  std::string* _s = _internal_add_oneofs();
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs)
+  return _s;
+}
+inline const std::string& Type::_internal_oneofs(int index) const {
+  return _impl_.oneofs_.Get(index);
+}
+inline const std::string& Type::oneofs(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.oneofs)
+  return _internal_oneofs(index);
+}
+inline std::string* Type::mutable_oneofs(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.oneofs)
+  return _impl_.oneofs_.Mutable(index);
+}
+inline void Type::set_oneofs(int index, const std::string& value) {
+  _impl_.oneofs_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.oneofs)
+}
+inline void Type::set_oneofs(int index, std::string&& value) {
+  _impl_.oneofs_.Mutable(index)->assign(std::move(value));
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.oneofs)
+}
+inline void Type::set_oneofs(int index, const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.oneofs_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Type.oneofs)
+}
+inline void Type::set_oneofs(int index, const char* value, size_t size) {
+  _impl_.oneofs_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs)
+}
+inline std::string* Type::_internal_add_oneofs() {
+  return _impl_.oneofs_.Add();
+}
+inline void Type::add_oneofs(const std::string& value) {
+  _impl_.oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(std::string&& value) {
+  _impl_.oneofs_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(const char* value) {
+  GOOGLE_DCHECK(value != nullptr);
+  _impl_.oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(const char* value, size_t size) {
+  _impl_.oneofs_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.Type.oneofs)
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
+Type::oneofs() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.oneofs)
+  return _impl_.oneofs_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
+Type::mutable_oneofs() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.oneofs)
+  return &_impl_.oneofs_;
+}
+
+// repeated .google.protobuf.Option options = 4;
+inline int Type::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Type::options_size() const {
+  return _internal_options_size();
+}
+inline void Type::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Type::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Type::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Type::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Type::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Type::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Type::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Type::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.options)
+  return _impl_.options_;
+}
+
+// .google.protobuf.SourceContext source_context = 5;
+inline bool Type::_internal_has_source_context() const {
+  return this != internal_default_instance() && _impl_.source_context_ != nullptr;
+}
+inline bool Type::has_source_context() const {
+  return _internal_has_source_context();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Type::_internal_source_context() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext* p = _impl_.source_context_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceContext&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Type::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.source_context)
+  return _internal_source_context();
+}
+inline void Type::unsafe_arena_set_allocated_source_context(
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  _impl_.source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Type.source_context)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::release_source_context() {
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::unsafe_arena_release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context)
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::_internal_mutable_source_context() {
+  
+  if (_impl_.source_context_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(GetArenaForAllocation());
+    _impl_.source_context_ = p;
+  }
+  return _impl_.source_context_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Type::mutable_source_context() {
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _msg = _internal_mutable_source_context();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.source_context)
+  return _msg;
+}
+inline void Type::set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  if (source_context) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(source_context));
+    if (message_arena != submessage_arena) {
+      source_context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_context, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.source_context_ = source_context;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.source_context)
+}
+
+// .google.protobuf.Syntax syntax = 6;
+inline void Type::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Type::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Type::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.syntax)
+  return _internal_syntax();
+}
+inline void Type::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Type::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Field
+
+// .google.protobuf.Field.Kind kind = 1;
+inline void Field::clear_kind() {
+  _impl_.kind_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Kind Field::_internal_kind() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Field_Kind >(_impl_.kind_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Kind Field::kind() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.kind)
+  return _internal_kind();
+}
+inline void Field::_internal_set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value) {
+  
+  _impl_.kind_ = value;
+}
+inline void Field::set_kind(::PROTOBUF_NAMESPACE_ID::Field_Kind value) {
+  _internal_set_kind(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.kind)
+}
+
+// .google.protobuf.Field.Cardinality cardinality = 2;
+inline void Field::clear_cardinality() {
+  _impl_.cardinality_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Cardinality Field::_internal_cardinality() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Field_Cardinality >(_impl_.cardinality_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Field_Cardinality Field::cardinality() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.cardinality)
+  return _internal_cardinality();
+}
+inline void Field::_internal_set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value) {
+  
+  _impl_.cardinality_ = value;
+}
+inline void Field::set_cardinality(::PROTOBUF_NAMESPACE_ID::Field_Cardinality value) {
+  _internal_set_cardinality(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.cardinality)
+}
+
+// int32 number = 3;
+inline void Field::clear_number() {
+  _impl_.number_ = 0;
+}
+inline int32_t Field::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t Field::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.number)
+  return _internal_number();
+}
+inline void Field::_internal_set_number(int32_t value) {
+  
+  _impl_.number_ = value;
+}
+inline void Field::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.number)
+}
+
+// string name = 4;
+inline void Field::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Field::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.name)
+}
+inline std::string* Field::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.name)
+  return _s;
+}
+inline const std::string& Field::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Field::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.name)
+  return _impl_.name_.Release();
+}
+inline void Field::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.name)
+}
+
+// string type_url = 6;
+inline void Field::clear_type_url() {
+  _impl_.type_url_.ClearToEmpty();
+}
+inline const std::string& Field::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.type_url)
+  return _internal_type_url();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_type_url(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.type_url)
+}
+inline std::string* Field::mutable_type_url() {
+  std::string* _s = _internal_mutable_type_url();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.type_url)
+  return _s;
+}
+inline const std::string& Field::_internal_type_url() const {
+  return _impl_.type_url_.Get();
+}
+inline void Field::_internal_set_type_url(const std::string& value) {
+  
+  _impl_.type_url_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_type_url() {
+  
+  return _impl_.type_url_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url)
+  return _impl_.type_url_.Release();
+}
+inline void Field::set_allocated_type_url(std::string* type_url) {
+  if (type_url != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.type_url_.SetAllocated(type_url, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.type_url_.IsDefault()) {
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.type_url)
+}
+
+// int32 oneof_index = 7;
+inline void Field::clear_oneof_index() {
+  _impl_.oneof_index_ = 0;
+}
+inline int32_t Field::_internal_oneof_index() const {
+  return _impl_.oneof_index_;
+}
+inline int32_t Field::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.oneof_index)
+  return _internal_oneof_index();
+}
+inline void Field::_internal_set_oneof_index(int32_t value) {
+  
+  _impl_.oneof_index_ = value;
+}
+inline void Field::set_oneof_index(int32_t value) {
+  _internal_set_oneof_index(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.oneof_index)
+}
+
+// bool packed = 8;
+inline void Field::clear_packed() {
+  _impl_.packed_ = false;
+}
+inline bool Field::_internal_packed() const {
+  return _impl_.packed_;
+}
+inline bool Field::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.packed)
+  return _internal_packed();
+}
+inline void Field::_internal_set_packed(bool value) {
+  
+  _impl_.packed_ = value;
+}
+inline void Field::set_packed(bool value) {
+  _internal_set_packed(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.packed)
+}
+
+// repeated .google.protobuf.Option options = 9;
+inline int Field::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Field::options_size() const {
+  return _internal_options_size();
+}
+inline void Field::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Field::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Field::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Field::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Field::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Field::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Field::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Field.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Field::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Field.options)
+  return _impl_.options_;
+}
+
+// string json_name = 10;
+inline void Field::clear_json_name() {
+  _impl_.json_name_.ClearToEmpty();
+}
+inline const std::string& Field::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.json_name)
+  return _internal_json_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_json_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.json_name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.json_name)
+}
+inline std::string* Field::mutable_json_name() {
+  std::string* _s = _internal_mutable_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.json_name)
+  return _s;
+}
+inline const std::string& Field::_internal_json_name() const {
+  return _impl_.json_name_.Get();
+}
+inline void Field::_internal_set_json_name(const std::string& value) {
+  
+  _impl_.json_name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_json_name() {
+  
+  return _impl_.json_name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name)
+  return _impl_.json_name_.Release();
+}
+inline void Field::set_allocated_json_name(std::string* json_name) {
+  if (json_name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.json_name_.SetAllocated(json_name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.json_name_.IsDefault()) {
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
+}
+
+// string default_value = 11;
+inline void Field::clear_default_value() {
+  _impl_.default_value_.ClearToEmpty();
+}
+inline const std::string& Field::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+  return _internal_default_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Field::set_default_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.default_value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+inline std::string* Field::mutable_default_value() {
+  std::string* _s = _internal_mutable_default_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+  return _s;
+}
+inline const std::string& Field::_internal_default_value() const {
+  return _impl_.default_value_.Get();
+}
+inline void Field::_internal_set_default_value(const std::string& value) {
+  
+  _impl_.default_value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Field::_internal_mutable_default_value() {
+  
+  return _impl_.default_value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Field::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value)
+  return _impl_.default_value_.Release();
+}
+inline void Field::set_allocated_default_value(std::string* default_value) {
+  if (default_value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.default_value_.SetAllocated(default_value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.default_value_.IsDefault()) {
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
+// -------------------------------------------------------------------
+
+// Enum
+
+// string name = 1;
+inline void Enum::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Enum::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Enum::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.name)
+}
+inline std::string* Enum::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.name)
+  return _s;
+}
+inline const std::string& Enum::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Enum::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Enum::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Enum::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.name)
+  return _impl_.name_.Release();
+}
+inline void Enum::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.name)
+}
+
+// repeated .google.protobuf.EnumValue enumvalue = 2;
+inline int Enum::_internal_enumvalue_size() const {
+  return _impl_.enumvalue_.size();
+}
+inline int Enum::enumvalue_size() const {
+  return _internal_enumvalue_size();
+}
+inline void Enum::clear_enumvalue() {
+  _impl_.enumvalue_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValue* Enum::mutable_enumvalue(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.enumvalue)
+  return _impl_.enumvalue_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >*
+Enum::mutable_enumvalue() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.enumvalue)
+  return &_impl_.enumvalue_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValue& Enum::_internal_enumvalue(int index) const {
+  return _impl_.enumvalue_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::EnumValue& Enum::enumvalue(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.enumvalue)
+  return _internal_enumvalue(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValue* Enum::_internal_add_enumvalue() {
+  return _impl_.enumvalue_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::EnumValue* Enum::add_enumvalue() {
+  ::PROTOBUF_NAMESPACE_ID::EnumValue* _add = _internal_add_enumvalue();
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.enumvalue)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue >&
+Enum::enumvalue() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue)
+  return _impl_.enumvalue_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int Enum::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int Enum::options_size() const {
+  return _internal_options_size();
+}
+inline void Enum::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Enum::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+Enum::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Enum::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& Enum::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Enum::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* Enum::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+Enum::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.options)
+  return _impl_.options_;
+}
+
+// .google.protobuf.SourceContext source_context = 4;
+inline bool Enum::_internal_has_source_context() const {
+  return this != internal_default_instance() && _impl_.source_context_ != nullptr;
+}
+inline bool Enum::has_source_context() const {
+  return _internal_has_source_context();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Enum::_internal_source_context() const {
+  const ::PROTOBUF_NAMESPACE_ID::SourceContext* p = _impl_.source_context_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::SourceContext&>(
+      ::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::SourceContext& Enum::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.source_context)
+  return _internal_source_context();
+}
+inline void Enum::unsafe_arena_set_allocated_source_context(
+    ::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  _impl_.source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Enum.source_context)
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::release_source_context() {
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::unsafe_arena_release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context)
+  
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* temp = _impl_.source_context_;
+  _impl_.source_context_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::_internal_mutable_source_context() {
+  
+  if (_impl_.source_context_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::SourceContext>(GetArenaForAllocation());
+    _impl_.source_context_ = p;
+  }
+  return _impl_.source_context_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::SourceContext* Enum::mutable_source_context() {
+  ::PROTOBUF_NAMESPACE_ID::SourceContext* _msg = _internal_mutable_source_context();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.source_context)
+  return _msg;
+}
+inline void Enum::set_allocated_source_context(::PROTOBUF_NAMESPACE_ID::SourceContext* source_context) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.source_context_);
+  }
+  if (source_context) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(source_context));
+    if (message_arena != submessage_arena) {
+      source_context = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, source_context, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.source_context_ = source_context;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.source_context)
+}
+
+// .google.protobuf.Syntax syntax = 5;
+inline void Enum::clear_syntax() {
+  _impl_.syntax_ = 0;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Enum::_internal_syntax() const {
+  return static_cast< ::PROTOBUF_NAMESPACE_ID::Syntax >(_impl_.syntax_);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Syntax Enum::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.syntax)
+  return _internal_syntax();
+}
+inline void Enum::_internal_set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  
+  _impl_.syntax_ = value;
+}
+inline void Enum::set_syntax(::PROTOBUF_NAMESPACE_ID::Syntax value) {
+  _internal_set_syntax(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// EnumValue
+
+// string name = 1;
+inline void EnumValue::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& EnumValue::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void EnumValue::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.name)
+}
+inline std::string* EnumValue::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.name)
+  return _s;
+}
+inline const std::string& EnumValue::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void EnumValue::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* EnumValue::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* EnumValue::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name)
+  return _impl_.name_.Release();
+}
+inline void EnumValue::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValue.name)
+}
+
+// int32 number = 2;
+inline void EnumValue::clear_number() {
+  _impl_.number_ = 0;
+}
+inline int32_t EnumValue::_internal_number() const {
+  return _impl_.number_;
+}
+inline int32_t EnumValue::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.number)
+  return _internal_number();
+}
+inline void EnumValue::_internal_set_number(int32_t value) {
+  
+  _impl_.number_ = value;
+}
+inline void EnumValue::set_number(int32_t value) {
+  _internal_set_number(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.number)
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int EnumValue::_internal_options_size() const {
+  return _impl_.options_.size();
+}
+inline int EnumValue::options_size() const {
+  return _internal_options_size();
+}
+inline void EnumValue::clear_options() {
+  _impl_.options_.Clear();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* EnumValue::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.options)
+  return _impl_.options_.Mutable(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >*
+EnumValue::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValue.options)
+  return &_impl_.options_;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& EnumValue::_internal_options(int index) const {
+  return _impl_.options_.Get(index);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Option& EnumValue::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.options)
+  return _internal_options(index);
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* EnumValue::_internal_add_options() {
+  return _impl_.options_.Add();
+}
+inline ::PROTOBUF_NAMESPACE_ID::Option* EnumValue::add_options() {
+  ::PROTOBUF_NAMESPACE_ID::Option* _add = _internal_add_options();
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValue.options)
+  return _add;
+}
+inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option >&
+EnumValue::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options)
+  return _impl_.options_;
+}
+
+// -------------------------------------------------------------------
+
+// Option
+
+// string name = 1;
+inline void Option::clear_name() {
+  _impl_.name_.ClearToEmpty();
+}
+inline const std::string& Option::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.name)
+  return _internal_name();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void Option::set_name(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.Option.name)
+}
+inline std::string* Option::mutable_name() {
+  std::string* _s = _internal_mutable_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.name)
+  return _s;
+}
+inline const std::string& Option::_internal_name() const {
+  return _impl_.name_.Get();
+}
+inline void Option::_internal_set_name(const std::string& value) {
+  
+  _impl_.name_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Option::_internal_mutable_name() {
+  
+  return _impl_.name_.Mutable(GetArenaForAllocation());
+}
+inline std::string* Option::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.name)
+  return _impl_.name_.Release();
+}
+inline void Option::set_allocated_name(std::string* name) {
+  if (name != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.name_.SetAllocated(name, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.name_.IsDefault()) {
+    _impl_.name_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.name)
+}
+
+// .google.protobuf.Any value = 2;
+inline bool Option::_internal_has_value() const {
+  return this != internal_default_instance() && _impl_.value_ != nullptr;
+}
+inline bool Option::has_value() const {
+  return _internal_has_value();
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Any& Option::_internal_value() const {
+  const ::PROTOBUF_NAMESPACE_ID::Any* p = _impl_.value_;
+  return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Any&>(
+      ::PROTOBUF_NAMESPACE_ID::_Any_default_instance_);
+}
+inline const ::PROTOBUF_NAMESPACE_ID::Any& Option::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.value)
+  return _internal_value();
+}
+inline void Option::unsafe_arena_set_allocated_value(
+    ::PROTOBUF_NAMESPACE_ID::Any* value) {
+  if (GetArenaForAllocation() == nullptr) {
+    delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.value_);
+  }
+  _impl_.value_ = value;
+  if (value) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.Option.value)
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::release_value() {
+  
+  ::PROTOBUF_NAMESPACE_ID::Any* temp = _impl_.value_;
+  _impl_.value_ = nullptr;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  auto* old =  reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
+  temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  if (GetArenaForAllocation() == nullptr) { delete old; }
+#else  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (GetArenaForAllocation() != nullptr) {
+    temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
+  }
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::unsafe_arena_release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.value)
+  
+  ::PROTOBUF_NAMESPACE_ID::Any* temp = _impl_.value_;
+  _impl_.value_ = nullptr;
+  return temp;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::_internal_mutable_value() {
+  
+  if (_impl_.value_ == nullptr) {
+    auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Any>(GetArenaForAllocation());
+    _impl_.value_ = p;
+  }
+  return _impl_.value_;
+}
+inline ::PROTOBUF_NAMESPACE_ID::Any* Option::mutable_value() {
+  ::PROTOBUF_NAMESPACE_ID::Any* _msg = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.value)
+  return _msg;
+}
+inline void Option::set_allocated_value(::PROTOBUF_NAMESPACE_ID::Any* value) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  if (message_arena == nullptr) {
+    delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.value_);
+  }
+  if (value) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+        ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
+                reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(value));
+    if (message_arena != submessage_arena) {
+      value = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, value, submessage_arena);
+    }
+    
+  } else {
+    
+  }
+  _impl_.value_ = value;
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.value)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+PROTOBUF_NAMESPACE_OPEN
+
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::Field_Kind> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::Field_Kind>() {
+  return ::PROTOBUF_NAMESPACE_ID::Field_Kind_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::Field_Cardinality> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::Field_Cardinality>() {
+  return ::PROTOBUF_NAMESPACE_ID::Field_Cardinality_descriptor();
+}
+template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::Syntax> : ::std::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::Syntax>() {
+  return ::PROTOBUF_NAMESPACE_ID::Syntax_descriptor();
+}
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ftype_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/unknown_field_set.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/unknown_field_set.h
new file mode 100644
index 0000000..9aa2cbb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/unknown_field_set.h
@@ -0,0 +1,407 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Contains classes used to keep track of unrecognized fields seen while
+// parsing a protocol message.
+
+#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
+#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
+
+
+#include <assert.h>
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+class InternalMetadata;           // metadata_lite.h
+class WireFormat;                 // wire_format.h
+class MessageSetFieldSkipperUsingCord;
+// extension_set_heavy.cc
+}  // namespace internal
+
+class Message;       // message.h
+class UnknownField;  // below
+
+// An UnknownFieldSet contains fields that were encountered while parsing a
+// message but were not defined by its type.  Keeping track of these can be
+// useful, especially in that they may be written if the message is serialized
+// again without being cleared in between.  This means that software which
+// simply receives messages and forwards them to other servers does not need
+// to be updated every time a new field is added to the message definition.
+//
+// To get the UnknownFieldSet attached to any message, call
+// Reflection::GetUnknownFields().
+//
+// This class is necessarily tied to the protocol buffer wire format, unlike
+// the Reflection interface which is independent of any serialization scheme.
+class PROTOBUF_EXPORT UnknownFieldSet {
+ public:
+  UnknownFieldSet();
+  ~UnknownFieldSet();
+
+  // Remove all fields.
+  inline void Clear();
+
+  // Remove all fields and deallocate internal data objects
+  void ClearAndFreeMemory();
+
+  // Is this set empty?
+  inline bool empty() const;
+
+  // Merge the contents of some other UnknownFieldSet with this one.
+  void MergeFrom(const UnknownFieldSet& other);
+
+  // Similar to above, but this function will destroy the contents of other.
+  void MergeFromAndDestroy(UnknownFieldSet* other);
+
+  // Merge the contents an UnknownFieldSet with the UnknownFieldSet in
+  // *metadata, if there is one.  If *metadata doesn't have an UnknownFieldSet
+  // then add one to it and make it be a copy of the first arg.
+  static void MergeToInternalMetadata(const UnknownFieldSet& other,
+                                      internal::InternalMetadata* metadata);
+
+  // Swaps the contents of some other UnknownFieldSet with this one.
+  inline void Swap(UnknownFieldSet* x);
+
+  // Computes (an estimate of) the total number of bytes currently used for
+  // storing the unknown fields in memory. Does NOT include
+  // sizeof(*this) in the calculation.
+  size_t SpaceUsedExcludingSelfLong() const;
+
+  int SpaceUsedExcludingSelf() const {
+    return internal::ToIntSize(SpaceUsedExcludingSelfLong());
+  }
+
+  // Version of SpaceUsed() including sizeof(*this).
+  size_t SpaceUsedLong() const;
+
+  int SpaceUsed() const { return internal::ToIntSize(SpaceUsedLong()); }
+
+  // Returns the number of fields present in the UnknownFieldSet.
+  inline int field_count() const;
+  // Get a field in the set, where 0 <= index < field_count().  The fields
+  // appear in the order in which they were added.
+  inline const UnknownField& field(int index) const;
+  // Get a mutable pointer to a field in the set, where
+  // 0 <= index < field_count().  The fields appear in the order in which
+  // they were added.
+  inline UnknownField* mutable_field(int index);
+
+  // Adding fields ---------------------------------------------------
+
+  void AddVarint(int number, uint64_t value);
+  void AddFixed32(int number, uint32_t value);
+  void AddFixed64(int number, uint64_t value);
+  void AddLengthDelimited(int number, const std::string& value);
+  std::string* AddLengthDelimited(int number);
+  UnknownFieldSet* AddGroup(int number);
+
+  // Adds an unknown field from another set.
+  void AddField(const UnknownField& field);
+
+  // Delete fields with indices in the range [start .. start+num-1].
+  // Caution: implementation moves all fields with indices [start+num .. ].
+  void DeleteSubrange(int start, int num);
+
+  // Delete all fields with a specific field number. The order of left fields
+  // is preserved.
+  // Caution: implementation moves all fields after the first deleted field.
+  void DeleteByNumber(int number);
+
+  // Parsing helpers -------------------------------------------------
+  // These work exactly like the similarly-named methods of Message.
+
+  bool MergeFromCodedStream(io::CodedInputStream* input);
+  bool ParseFromCodedStream(io::CodedInputStream* input);
+  bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
+  bool ParseFromArray(const void* data, int size);
+  inline bool ParseFromString(const std::string& data) {
+    return ParseFromArray(data.data(), static_cast<int>(data.size()));
+  }
+
+  // Merges this message's unknown field data (if any).  This works whether
+  // the message is a lite or full proto (for legacy reasons, lite and full
+  // return different types for MessageType::unknown_fields()).
+  template <typename MessageType>
+  bool MergeFromMessage(const MessageType& message);
+
+  // Serialization.
+  bool SerializeToString(std::string* output) const;
+  bool SerializeToCodedStream(io::CodedOutputStream* output) const;
+  static const UnknownFieldSet& default_instance();
+
+ private:
+  // For InternalMergeFrom
+  friend class UnknownField;
+  // Merges from other UnknownFieldSet. This method assumes, that this object
+  // is newly created and has no fields.
+  void InternalMergeFrom(const UnknownFieldSet& other);
+  void ClearFallback();
+
+  template <typename MessageType,
+            typename std::enable_if<
+                std::is_base_of<Message, MessageType>::value, int>::type = 0>
+  bool InternalMergeFromMessage(const MessageType& message) {
+    MergeFrom(message.GetReflection()->GetUnknownFields(message));
+    return true;
+  }
+
+  template <typename MessageType,
+            typename std::enable_if<
+                std::is_base_of<MessageLite, MessageType>::value &&
+                    !std::is_base_of<Message, MessageType>::value,
+                int>::type = 0>
+  bool InternalMergeFromMessage(const MessageType& message) {
+    const auto& unknown_fields = message.unknown_fields();
+    io::ArrayInputStream array_stream(unknown_fields.data(),
+                                      unknown_fields.size());
+    io::CodedInputStream coded_stream(&array_stream);
+    return MergeFromCodedStream(&coded_stream);
+  }
+
+  std::vector<UnknownField> fields_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
+};
+
+namespace internal {
+
+inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* unknown) {
+  unknown->AddVarint(num, val);
+}
+inline void WriteLengthDelimited(uint32_t num, StringPiece val,
+                                 UnknownFieldSet* unknown) {
+  unknown->AddLengthDelimited(num)->assign(val.data(), val.size());
+}
+
+PROTOBUF_EXPORT
+const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
+                              ParseContext* ctx);
+PROTOBUF_EXPORT
+const char* UnknownFieldParse(uint64_t tag, UnknownFieldSet* unknown,
+                              const char* ptr, ParseContext* ctx);
+
+}  // namespace internal
+
+// Represents one field in an UnknownFieldSet.
+class PROTOBUF_EXPORT UnknownField {
+ public:
+  enum Type {
+    TYPE_VARINT,
+    TYPE_FIXED32,
+    TYPE_FIXED64,
+    TYPE_LENGTH_DELIMITED,
+    TYPE_GROUP
+  };
+
+  // The field's field number, as seen on the wire.
+  inline int number() const;
+
+  // The field type.
+  inline Type type() const;
+
+  // Accessors -------------------------------------------------------
+  // Each method works only for UnknownFields of the corresponding type.
+
+  inline uint64_t varint() const;
+  inline uint32_t fixed32() const;
+  inline uint64_t fixed64() const;
+  inline const std::string& length_delimited() const;
+  inline const UnknownFieldSet& group() const;
+
+  inline void set_varint(uint64_t value);
+  inline void set_fixed32(uint32_t value);
+  inline void set_fixed64(uint64_t value);
+  inline void set_length_delimited(const std::string& value);
+  inline std::string* mutable_length_delimited();
+  inline UnknownFieldSet* mutable_group();
+
+  inline size_t GetLengthDelimitedSize() const;
+  uint8_t* InternalSerializeLengthDelimitedNoTag(
+      uint8_t* target, io::EpsCopyOutputStream* stream) const;
+
+
+  // If this UnknownField contains a pointer, delete it.
+  void Delete();
+
+  // Make a deep copy of any pointers in this UnknownField.
+  void DeepCopy(const UnknownField& other);
+
+  // Set the wire type of this UnknownField. Should only be used when this
+  // UnknownField is being created.
+  inline void SetType(Type type);
+
+  union LengthDelimited {
+    std::string* string_value;
+  };
+
+  uint32_t number_;
+  uint32_t type_;
+  union {
+    uint64_t varint_;
+    uint32_t fixed32_;
+    uint64_t fixed64_;
+    mutable union LengthDelimited length_delimited_;
+    UnknownFieldSet* group_;
+  } data_;
+};
+
+// ===================================================================
+// inline implementations
+
+inline UnknownFieldSet::UnknownFieldSet() {}
+
+inline UnknownFieldSet::~UnknownFieldSet() { Clear(); }
+
+inline void UnknownFieldSet::ClearAndFreeMemory() { Clear(); }
+
+inline void UnknownFieldSet::Clear() {
+  if (!fields_.empty()) {
+    ClearFallback();
+  }
+}
+
+inline bool UnknownFieldSet::empty() const { return fields_.empty(); }
+
+inline void UnknownFieldSet::Swap(UnknownFieldSet* x) {
+  fields_.swap(x->fields_);
+}
+
+inline int UnknownFieldSet::field_count() const {
+  return static_cast<int>(fields_.size());
+}
+inline const UnknownField& UnknownFieldSet::field(int index) const {
+  return (fields_)[static_cast<size_t>(index)];
+}
+inline UnknownField* UnknownFieldSet::mutable_field(int index) {
+  return &(fields_)[static_cast<size_t>(index)];
+}
+
+inline void UnknownFieldSet::AddLengthDelimited(int number,
+                                                const std::string& value) {
+  AddLengthDelimited(number)->assign(value);
+}
+
+
+
+
+inline int UnknownField::number() const { return static_cast<int>(number_); }
+inline UnknownField::Type UnknownField::type() const {
+  return static_cast<Type>(type_);
+}
+
+inline uint64_t UnknownField::varint() const {
+  assert(type() == TYPE_VARINT);
+  return data_.varint_;
+}
+inline uint32_t UnknownField::fixed32() const {
+  assert(type() == TYPE_FIXED32);
+  return data_.fixed32_;
+}
+inline uint64_t UnknownField::fixed64() const {
+  assert(type() == TYPE_FIXED64);
+  return data_.fixed64_;
+}
+inline const std::string& UnknownField::length_delimited() const {
+  assert(type() == TYPE_LENGTH_DELIMITED);
+  return *data_.length_delimited_.string_value;
+}
+inline const UnknownFieldSet& UnknownField::group() const {
+  assert(type() == TYPE_GROUP);
+  return *data_.group_;
+}
+
+inline void UnknownField::set_varint(uint64_t value) {
+  assert(type() == TYPE_VARINT);
+  data_.varint_ = value;
+}
+inline void UnknownField::set_fixed32(uint32_t value) {
+  assert(type() == TYPE_FIXED32);
+  data_.fixed32_ = value;
+}
+inline void UnknownField::set_fixed64(uint64_t value) {
+  assert(type() == TYPE_FIXED64);
+  data_.fixed64_ = value;
+}
+inline void UnknownField::set_length_delimited(const std::string& value) {
+  assert(type() == TYPE_LENGTH_DELIMITED);
+  data_.length_delimited_.string_value->assign(value);
+}
+inline std::string* UnknownField::mutable_length_delimited() {
+  assert(type() == TYPE_LENGTH_DELIMITED);
+  return data_.length_delimited_.string_value;
+}
+inline UnknownFieldSet* UnknownField::mutable_group() {
+  assert(type() == TYPE_GROUP);
+  return data_.group_;
+}
+template <typename MessageType>
+bool UnknownFieldSet::MergeFromMessage(const MessageType& message) {
+  // SFINAE will route to the right version.
+  return InternalMergeFromMessage(message);
+}
+
+
+inline size_t UnknownField::GetLengthDelimitedSize() const {
+  GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+  return data_.length_delimited_.string_value->size();
+}
+
+inline void UnknownField::SetType(Type type) {
+  type_ = type;
+}
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/delimited_message_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/delimited_message_util.h
new file mode 100644
index 0000000..78625cf
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/delimited_message_util.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Adapted from the patch of kenton@google.com (Kenton Varda)
+// See https://github.com/protocolbuffers/protobuf/pull/710 for details.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_DELIMITED_MESSAGE_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_DELIMITED_MESSAGE_UTIL_H__
+
+
+#include <ostream>
+
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Write a single size-delimited message from the given stream. Delimited
+// format allows a single file or stream to contain multiple messages,
+// whereas normally writing multiple non-delimited messages to the same
+// stream would cause them to be merged. A delimited message is a varint
+// encoding the message size followed by a message of exactly that size.
+//
+// Note that if you want to *read* a delimited message from a file descriptor
+// or istream, you will need to construct an io::FileInputStream or
+// io::OstreamInputStream (implementations of io::ZeroCopyStream) and use the
+// utility function ParseDelimitedFromZeroCopyStream(). You must then
+// continue to use the same ZeroCopyInputStream to read all further data from
+// the stream until EOF. This is because these ZeroCopyInputStream
+// implementations are buffered: they read a big chunk of data at a time,
+// then parse it. As a result, they may read past the end of the delimited
+// message. There is no way for them to push the extra data back into the
+// underlying source, so instead you must keep using the same stream object.
+bool PROTOBUF_EXPORT SerializeDelimitedToFileDescriptor(
+    const MessageLite& message, int file_descriptor);
+
+bool PROTOBUF_EXPORT SerializeDelimitedToOstream(const MessageLite& message,
+                                                 std::ostream* output);
+
+// Read a single size-delimited message from the given stream. Delimited
+// format allows a single file or stream to contain multiple messages,
+// whereas normally parsing consumes the entire input. A delimited message
+// is a varint encoding the message size followed by a message of exactly
+// that size.
+//
+// If |clean_eof| is not NULL, then it will be set to indicate whether the
+// stream ended cleanly. That is, if the stream ends without this method
+// having read any data at all from it, then *clean_eof will be set true,
+// otherwise it will be set false. Note that these methods return false
+// on EOF, but they also return false on other errors, so |clean_eof| is
+// needed to distinguish a clean end from errors.
+bool PROTOBUF_EXPORT ParseDelimitedFromZeroCopyStream(
+    MessageLite* message, io::ZeroCopyInputStream* input, bool* clean_eof);
+
+bool PROTOBUF_EXPORT ParseDelimitedFromCodedStream(MessageLite* message,
+                                                   io::CodedInputStream* input,
+                                                   bool* clean_eof);
+
+// Write a single size-delimited message from the given stream. Delimited
+// format allows a single file or stream to contain multiple messages,
+// whereas normally writing multiple non-delimited messages to the same
+// stream would cause them to be merged. A delimited message is a varint
+// encoding the message size followed by a message of exactly that size.
+bool PROTOBUF_EXPORT SerializeDelimitedToZeroCopyStream(
+    const MessageLite& message, io::ZeroCopyOutputStream* output);
+
+bool PROTOBUF_EXPORT SerializeDelimitedToCodedStream(
+    const MessageLite& message, io::CodedOutputStream* output);
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_DELIMITED_MESSAGE_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/field_comparator.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/field_comparator.h
new file mode 100644
index 0000000..5706da3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/field_comparator.h
@@ -0,0 +1,288 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines classes for field comparison.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
+#define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
+
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class EnumValueDescriptor;
+class FieldDescriptor;
+
+namespace util {
+
+class FieldContext;
+class MessageDifferencer;
+
+// Base class specifying the interface for comparing protocol buffer fields.
+// Regular users should consider using or subclassing DefaultFieldComparator
+// rather than this interface.
+// Currently, this does not support comparing unknown fields.
+class PROTOBUF_EXPORT FieldComparator {
+ public:
+  FieldComparator();
+  virtual ~FieldComparator();
+
+  enum ComparisonResult {
+    SAME,       // Compared fields are equal. In case of comparing submessages,
+                // user should not recursively compare their contents.
+    DIFFERENT,  // Compared fields are different. In case of comparing
+                // submessages, user should not recursively compare their
+                // contents.
+    RECURSE,    // Compared submessages need to be compared recursively.
+                // FieldComparator does not specify the semantics of recursive
+                // comparison. This value should not be returned for simple
+                // values.
+  };
+
+  // Compares the values of a field in two protocol buffer messages.
+  // Returns SAME or DIFFERENT for simple values, and SAME, DIFFERENT or RECURSE
+  // for submessages. Returning RECURSE for fields not being submessages is
+  // illegal.
+  // In case the given FieldDescriptor points to a repeated field, the indices
+  // need to be valid. Otherwise they should be ignored.
+  //
+  // FieldContext contains information about the specific instances of the
+  // fields being compared, versus FieldDescriptor which only contains general
+  // type information about the fields.
+  virtual ComparisonResult Compare(const Message& message_1,
+                                   const Message& message_2,
+                                   const FieldDescriptor* field, int index_1,
+                                   int index_2,
+                                   const util::FieldContext* field_context) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator);
+};
+
+// Basic implementation of FieldComparator.  Supports three modes of floating
+// point value comparison: exact, approximate using MathUtil::AlmostEqual
+// method, and arbitrarily precise using MathUtil::WithinFractionOrMargin.
+class PROTOBUF_EXPORT SimpleFieldComparator : public FieldComparator {
+ public:
+  enum FloatComparison {
+    EXACT,        // Floats and doubles are compared exactly.
+    APPROXIMATE,  // Floats and doubles are compared using the
+                  // MathUtil::AlmostEqual method or
+                  // MathUtil::WithinFractionOrMargin method.
+    // TODO(ksroka): Introduce third value to differentiate uses of AlmostEqual
+    //               and WithinFractionOrMargin.
+  };
+
+  // Creates new comparator with float comparison set to EXACT.
+  SimpleFieldComparator();
+
+  ~SimpleFieldComparator() override;
+
+  void set_float_comparison(FloatComparison float_comparison) {
+    float_comparison_ = float_comparison;
+  }
+
+  FloatComparison float_comparison() const { return float_comparison_; }
+
+  // Set whether the FieldComparator shall treat floats or doubles that are both
+  // NaN as equal (treat_nan_as_equal = true) or as different
+  // (treat_nan_as_equal = false). Default is treating NaNs always as different.
+  void set_treat_nan_as_equal(bool treat_nan_as_equal) {
+    treat_nan_as_equal_ = treat_nan_as_equal;
+  }
+
+  bool treat_nan_as_equal() const { return treat_nan_as_equal_; }
+
+  // Sets the fraction and margin for the float comparison of a given field.
+  // Uses MathUtil::WithinFractionOrMargin to compare the values.
+  //
+  // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
+  //           field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
+  // REQUIRES: float_comparison_ == APPROXIMATE
+  void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
+                            double margin);
+
+  // Sets the fraction and margin for the float comparison of all float and
+  // double fields, unless a field has been given a specific setting via
+  // SetFractionAndMargin() above.
+  // Uses MathUtil::WithinFractionOrMargin to compare the values.
+  //
+  // REQUIRES: float_comparison_ == APPROXIMATE
+  void SetDefaultFractionAndMargin(double fraction, double margin);
+
+ protected:
+  // Returns the comparison result for the given field in two messages.
+  //
+  // This function is called directly by DefaultFieldComparator::Compare.
+  // Subclasses can call this function to compare fields they do not need to
+  // handle specially.
+  ComparisonResult SimpleCompare(const Message& message_1,
+                                 const Message& message_2,
+                                 const FieldDescriptor* field, int index_1,
+                                 int index_2,
+                                 const util::FieldContext* field_context);
+
+  // Compare using the provided message_differencer. For example, a subclass can
+  // use this method to compare some field in a certain way using the same
+  // message_differencer instance and the field context.
+  bool CompareWithDifferencer(MessageDifferencer* differencer,
+                              const Message& message1, const Message& message2,
+                              const util::FieldContext* field_context);
+
+  // Returns FieldComparator::SAME if boolean_result is true and
+  // FieldComparator::DIFFERENT otherwise.
+  ComparisonResult ResultFromBoolean(bool boolean_result) const;
+
+ private:
+  // Defines the tolerance for floating point comparison (fraction and margin).
+  struct Tolerance {
+    double fraction;
+    double margin;
+    Tolerance() : fraction(0.0), margin(0.0) {}
+    Tolerance(double f, double m) : fraction(f), margin(m) {}
+  };
+
+  // Defines the map to store the tolerances for floating point comparison.
+  typedef std::map<const FieldDescriptor*, Tolerance> ToleranceMap;
+
+  friend class MessageDifferencer;
+  // The following methods get executed when CompareFields is called for the
+  // basic types (instead of submessages). They return true on success. One
+  // can use ResultFromBoolean() to convert that boolean to a ComparisonResult
+  // value.
+  bool CompareBool(const FieldDescriptor& /* unused */, bool value_1,
+                   bool value_2) {
+    return value_1 == value_2;
+  }
+
+  // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
+  // CompareFloat.
+  bool CompareDouble(const FieldDescriptor& field, double value_1,
+                     double value_2);
+
+  bool CompareEnum(const FieldDescriptor& field,
+                   const EnumValueDescriptor* value_1,
+                   const EnumValueDescriptor* value_2);
+
+  // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
+  // CompareFloat.
+  bool CompareFloat(const FieldDescriptor& field, float value_1, float value_2);
+
+  bool CompareInt32(const FieldDescriptor& /* unused */, int32_t value_1,
+                    int32_t value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareInt64(const FieldDescriptor& /* unused */, int64_t value_1,
+                    int64_t value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareString(const FieldDescriptor& /* unused */,
+                     const std::string& value_1, const std::string& value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareUInt32(const FieldDescriptor& /* unused */, uint32_t value_1,
+                     uint32_t value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareUInt64(const FieldDescriptor& /* unused */, uint64_t value_1,
+                     uint64_t value_2) {
+    return value_1 == value_2;
+  }
+
+  // This function is used by CompareDouble and CompareFloat to avoid code
+  // duplication. There are no checks done against types of the values passed,
+  // but it's likely to fail if passed non-numeric arguments.
+  template <typename T>
+  bool CompareDoubleOrFloat(const FieldDescriptor& field, T value_1, T value_2);
+
+  FloatComparison float_comparison_;
+
+  // If true, floats and doubles that are both NaN are considered to be
+  // equal. Otherwise, two floats or doubles that are NaN are considered to be
+  // different.
+  bool treat_nan_as_equal_;
+
+  // True iff default_tolerance_ has been explicitly set.
+  //
+  // If false, then the default tolerance for floats and doubles is that which
+  // is used by MathUtil::AlmostEquals().
+  bool has_default_tolerance_;
+
+  // Default float/double tolerance. Only meaningful if
+  // has_default_tolerance_ == true.
+  Tolerance default_tolerance_;
+
+  // Field-specific float/double tolerances, which override any default for
+  // those particular fields.
+  ToleranceMap map_tolerance_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleFieldComparator);
+};
+
+// Default field comparison: use the basic implementation of FieldComparator.
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+class PROTOBUF_EXPORT DefaultFieldComparator final
+    : public SimpleFieldComparator
+#else   // PROTOBUF_FUTURE_BREAKING_CHANGES
+class PROTOBUF_EXPORT DefaultFieldComparator : public SimpleFieldComparator
+#endif  // PROTOBUF_FUTURE_BREAKING_CHANGES
+{
+ public:
+  ComparisonResult Compare(const Message& message_1, const Message& message_2,
+                           const FieldDescriptor* field, int index_1,
+                           int index_2,
+                           const util::FieldContext* field_context) override {
+    return SimpleCompare(message_1, message_2, field, index_1, index_2,
+                         field_context);
+  }
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/field_mask_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/field_mask_util.h
new file mode 100644
index 0000000..d51a332
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/field_mask_util.h
@@ -0,0 +1,263 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines utilities for the FieldMask well known type.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
+
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+class PROTOBUF_EXPORT FieldMaskUtil {
+  typedef google::protobuf::FieldMask FieldMask;
+
+ public:
+  // Converts FieldMask to/from string, formatted by separating each path
+  // with a comma (e.g., "foo_bar,baz.quz").
+  static std::string ToString(const FieldMask& mask);
+  static void FromString(StringPiece str, FieldMask* out);
+
+  // Populates the FieldMask with the paths corresponding to the fields with the
+  // given numbers, after checking that all field numbers are valid.
+  template <typename T>
+  static void FromFieldNumbers(const std::vector<int64_t>& field_numbers,
+                               FieldMask* out) {
+    for (const auto field_number : field_numbers) {
+      const FieldDescriptor* field_desc =
+          T::descriptor()->FindFieldByNumber(field_number);
+      GOOGLE_CHECK(field_desc != nullptr)
+          << "Invalid field number for " << T::descriptor()->full_name() << ": "
+          << field_number;
+      AddPathToFieldMask<T>(field_desc->lowercase_name(), out);
+    }
+  }
+
+  // Converts FieldMask to/from string, formatted according to proto3 JSON
+  // spec for FieldMask (e.g., "fooBar,baz.quz"). If the field name is not
+  // style conforming (i.e., not snake_case when converted to string, or not
+  // camelCase when converted from string), the conversion will fail.
+  static bool ToJsonString(const FieldMask& mask, std::string* out);
+  static bool FromJsonString(StringPiece str, FieldMask* out);
+
+  // Get the descriptors of the fields which the given path from the message
+  // descriptor traverses, if field_descriptors is not null.
+  // Return false if the path is not valid, and the content of field_descriptors
+  // is unspecified.
+  static bool GetFieldDescriptors(
+      const Descriptor* descriptor, StringPiece path,
+      std::vector<const FieldDescriptor*>* field_descriptors);
+
+  // Checks whether the given path is valid for type T.
+  template <typename T>
+  static bool IsValidPath(StringPiece path) {
+    return GetFieldDescriptors(T::descriptor(), path, nullptr);
+  }
+
+  // Checks whether the given FieldMask is valid for type T.
+  template <typename T>
+  static bool IsValidFieldMask(const FieldMask& mask) {
+    for (int i = 0; i < mask.paths_size(); ++i) {
+      if (!GetFieldDescriptors(T::descriptor(), mask.paths(i), nullptr)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Adds a path to FieldMask after checking whether the given path is valid.
+  // This method check-fails if the path is not a valid path for type T.
+  template <typename T>
+  static void AddPathToFieldMask(StringPiece path, FieldMask* mask) {
+    GOOGLE_CHECK(IsValidPath<T>(path)) << path;
+    mask->add_paths(std::string(path));
+  }
+
+  // Creates a FieldMask with all fields of type T. This FieldMask only
+  // contains fields of T but not any sub-message fields.
+  template <typename T>
+  static FieldMask GetFieldMaskForAllFields() {
+    FieldMask out;
+    GetFieldMaskForAllFields(T::descriptor(), &out);
+    return out;
+  }
+  template <typename T>
+  PROTOBUF_DEPRECATED_MSG("Use *out = GetFieldMaskForAllFields() instead")
+  static void GetFieldMaskForAllFields(FieldMask* out) {
+    GetFieldMaskForAllFields(T::descriptor(), out);
+  }
+  // This flavor takes the protobuf type descriptor as an argument.
+  // Useful when the type is not known at compile time.
+  static void GetFieldMaskForAllFields(const Descriptor* descriptor,
+                                       FieldMask* out);
+
+  // Converts a FieldMask to the canonical form. It will:
+  //   1. Remove paths that are covered by another path. For example,
+  //      "foo.bar" is covered by "foo" and will be removed if "foo"
+  //      is also in the FieldMask.
+  //   2. Sort all paths in alphabetical order.
+  static void ToCanonicalForm(const FieldMask& mask, FieldMask* out);
+
+  // Creates an union of two FieldMasks.
+  static void Union(const FieldMask& mask1, const FieldMask& mask2,
+                    FieldMask* out);
+
+  // Creates an intersection of two FieldMasks.
+  static void Intersect(const FieldMask& mask1, const FieldMask& mask2,
+                        FieldMask* out);
+
+  // Subtracts mask2 from mask1 base of type T.
+  template <typename T>
+  static void Subtract(const FieldMask& mask1, const FieldMask& mask2,
+                       FieldMask* out) {
+    Subtract(T::descriptor(), mask1, mask2, out);
+  }
+  // This flavor takes the protobuf type descriptor as an argument.
+  // Useful when the type is not known at compile time.
+  static void Subtract(const Descriptor* descriptor, const FieldMask& mask1,
+                       const FieldMask& mask2, FieldMask* out);
+
+  // Returns true if path is covered by the given FieldMask. Note that path
+  // "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc.
+  // Also note that parent paths are not covered by explicit child path, i.e.
+  // "foo.bar" does NOT cover "foo", even if "bar" is the only child.
+  static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask);
+
+  class MergeOptions;
+  // Merges fields specified in a FieldMask into another message.
+  static void MergeMessageTo(const Message& source, const FieldMask& mask,
+                             const MergeOptions& options, Message* destination);
+
+  class TrimOptions;
+  // Removes from 'message' any field that is not represented in the given
+  // FieldMask. If the FieldMask is empty, does nothing.
+  // Returns true if the message is modified.
+  static bool TrimMessage(const FieldMask& mask, Message* message);
+
+  // Removes from 'message' any field that is not represented in the given
+  // FieldMask with customized TrimOptions.
+  // If the FieldMask is empty, does nothing.
+  // Returns true if the message is modified.
+  static bool TrimMessage(const FieldMask& mask, Message* message,
+                          const TrimOptions& options);
+
+ private:
+  friend class SnakeCaseCamelCaseTest;
+  // Converts a field name from snake_case to camelCase:
+  //   1. Every character after "_" will be converted to uppercase.
+  //   2. All "_"s are removed.
+  // The conversion will fail if:
+  //   1. The field name contains uppercase letters.
+  //   2. Any character after a "_" is not a lowercase letter.
+  // If the conversion succeeds, it's guaranteed that the resulted
+  // camelCase name will yield the original snake_case name when
+  // converted using CamelCaseToSnakeCase().
+  //
+  // Note that the input can contain characters not allowed in C identifiers.
+  // For example, "foo_bar,baz_quz" will be converted to "fooBar,bazQuz"
+  // successfully.
+  static bool SnakeCaseToCamelCase(StringPiece input,
+                                   std::string* output);
+  // Converts a field name from camelCase to snake_case:
+  //   1. Every uppercase letter is converted to lowercase with an additional
+  //      preceding "_".
+  // The conversion will fail if:
+  //   1. The field name contains "_"s.
+  // If the conversion succeeds, it's guaranteed that the resulted
+  // snake_case name will yield the original camelCase name when
+  // converted using SnakeCaseToCamelCase().
+  //
+  // Note that the input can contain characters not allowed in C identifiers.
+  // For example, "fooBar,bazQuz" will be converted to "foo_bar,baz_quz"
+  // successfully.
+  static bool CamelCaseToSnakeCase(StringPiece input,
+                                   std::string* output);
+};
+
+class PROTOBUF_EXPORT FieldMaskUtil::MergeOptions {
+ public:
+  MergeOptions()
+      : replace_message_fields_(false), replace_repeated_fields_(false) {}
+  // When merging message fields, the default behavior is to merge the
+  // content of two message fields together. If you instead want to use
+  // the field from the source message to replace the corresponding field
+  // in the destination message, set this flag to true. When this flag is set,
+  // specified submessage fields that are missing in source will be cleared in
+  // destination.
+  void set_replace_message_fields(bool value) {
+    replace_message_fields_ = value;
+  }
+  bool replace_message_fields() const { return replace_message_fields_; }
+  // The default merging behavior will append entries from the source
+  // repeated field to the destination repeated field. If you only want
+  // to keep the entries from the source repeated field, set this flag
+  // to true.
+  void set_replace_repeated_fields(bool value) {
+    replace_repeated_fields_ = value;
+  }
+  bool replace_repeated_fields() const { return replace_repeated_fields_; }
+
+ private:
+  bool replace_message_fields_;
+  bool replace_repeated_fields_;
+};
+
+class PROTOBUF_EXPORT FieldMaskUtil::TrimOptions {
+ public:
+  TrimOptions() : keep_required_fields_(false) {}
+  // When trimming message fields, the default behavior is to trim required
+  // fields of the present message if they are not specified in the field mask.
+  // If you instead want to keep required fields of the present message even
+  // when they are not specified in the field mask, set this flag to true.
+  void set_keep_required_fields(bool value) { keep_required_fields_ = value; }
+  bool keep_required_fields() const { return keep_required_fields_; }
+
+ private:
+  bool keep_required_fields_;
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/constants.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/constants.h
new file mode 100644
index 0000000..8bded86
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/constants.h
@@ -0,0 +1,101 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+
+// This file contains constants used by //net/proto2/util/converter.
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+// Prefix for type URLs.
+const char kTypeServiceBaseUrl[] = "type.googleapis.com";
+
+// Format string for RFC3339 timestamp formatting.
+const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S";
+
+// Same as above, but the year value is not zero-padded i.e. this accepts
+// timestamps like "1-01-0001T23:59:59Z" instead of "0001-01-0001T23:59:59Z".
+const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S";
+
+// Minimum seconds allowed in a google.protobuf.Timestamp value.
+const int64_t kTimestampMinSeconds = -62135596800LL;
+
+// Maximum seconds allowed in a google.protobuf.Timestamp value.
+const int64_t kTimestampMaxSeconds = 253402300799LL;
+
+// Minimum seconds allowed in a google.protobuf.Duration value.
+const int64_t kDurationMinSeconds = -315576000000LL;
+
+// Maximum seconds allowed in a google.protobuf.Duration value.
+const int64_t kDurationMaxSeconds = 315576000000LL;
+
+// Nano seconds in a second.
+const int32_t kNanosPerSecond = 1000000000;
+
+// Type url representing NULL values in google.protobuf.Struct type.
+const char kStructNullValueTypeUrl[] =
+    "type.googleapis.com/google.protobuf.NullValue";
+
+// Type string for google.protobuf.Struct
+const char kStructType[] = "google.protobuf.Struct";
+
+// Type string for struct.proto's google.protobuf.Value value type.
+const char kStructValueType[] = "google.protobuf.Value";
+
+// Type string for struct.proto's google.protobuf.ListValue value type.
+const char kStructListValueType[] = "google.protobuf.ListValue";
+
+// Type string for google.protobuf.Timestamp
+const char kTimestampType[] = "google.protobuf.Timestamp";
+
+// Type string for google.protobuf.Duration
+const char kDurationType[] = "google.protobuf.Duration";
+
+// Type URL for struct value type google.protobuf.Value
+const char kStructValueTypeUrl[] = "type.googleapis.com/google.protobuf.Value";
+
+// Type string for google.protobuf.Any
+const char kAnyType[] = "google.protobuf.Any";
+
+// The protobuf option name of jspb.message_id;
+const char kOptionJspbMessageId[] = "jspb.message_id";
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/datapiece.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/datapiece.h
new file mode 100644
index 0000000..6d08349
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/datapiece.h
@@ -0,0 +1,219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
+
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+class ProtoWriter;
+
+// Container for a single piece of data together with its data type.
+//
+// For primitive types (int32, int64, uint32, uint64, double, float, bool),
+// the data is stored by value.
+//
+// For string, a StringPiece is stored. For Cord, a pointer to Cord is stored.
+// Just like StringPiece, the DataPiece class does not own the storage for
+// the actual string or Cord, so it is the user's responsibility to guarantee
+// that the underlying storage is still valid when the DataPiece is accessed.
+class PROTOBUF_EXPORT DataPiece {
+ public:
+  // Identifies data type of the value.
+  // These are the types supported by DataPiece.
+  enum Type {
+    TYPE_INT32 = 1,
+    TYPE_INT64 = 2,
+    TYPE_UINT32 = 3,
+    TYPE_UINT64 = 4,
+    TYPE_DOUBLE = 5,
+    TYPE_FLOAT = 6,
+    TYPE_BOOL = 7,
+    TYPE_ENUM = 8,
+    TYPE_STRING = 9,
+    TYPE_BYTES = 10,
+    TYPE_NULL = 11,  // explicit NULL type
+  };
+
+  // Constructors and Destructor
+  explicit DataPiece(const int32_t value)
+      : type_(TYPE_INT32), i32_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const int64_t value)
+      : type_(TYPE_INT64), i64_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const uint32_t value)
+      : type_(TYPE_UINT32), u32_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const uint64_t value)
+      : type_(TYPE_UINT64), u64_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const double value)
+      : type_(TYPE_DOUBLE),
+        double_(value),
+        use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const float value)
+      : type_(TYPE_FLOAT), float_(value), use_strict_base64_decoding_(false) {}
+  explicit DataPiece(const bool value)
+      : type_(TYPE_BOOL), bool_(value), use_strict_base64_decoding_(false) {}
+  DataPiece(StringPiece value, bool use_strict_base64_decoding)
+      : type_(TYPE_STRING),
+        str_(value),
+        use_strict_base64_decoding_(use_strict_base64_decoding) {}
+  // Constructor for bytes. The second parameter is not used.
+  DataPiece(StringPiece value, bool /*dummy*/, bool use_strict_base64_decoding)
+      : type_(TYPE_BYTES),
+        str_(value),
+        use_strict_base64_decoding_(use_strict_base64_decoding) {}
+
+  DataPiece(const DataPiece& r) : type_(r.type_) { InternalCopy(r); }
+
+  DataPiece& operator=(const DataPiece& x) {
+    InternalCopy(x);
+    return *this;
+  }
+
+  static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); }
+
+  virtual ~DataPiece() {
+  }
+
+  // Accessors
+  Type type() const { return type_; }
+
+  bool use_strict_base64_decoding() { return use_strict_base64_decoding_; }
+
+  StringPiece str() const {
+    GOOGLE_LOG_IF(DFATAL, type_ != TYPE_STRING) << "Not a string type.";
+    return str_;
+  }
+
+
+  // Parses, casts or converts the value stored in the DataPiece into an int32.
+  util::StatusOr<int32_t> ToInt32() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a uint32.
+  util::StatusOr<uint32_t> ToUint32() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into an int64.
+  util::StatusOr<int64_t> ToInt64() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a uint64.
+  util::StatusOr<uint64_t> ToUint64() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a double.
+  util::StatusOr<double> ToDouble() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a float.
+  util::StatusOr<float> ToFloat() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a bool.
+  util::StatusOr<bool> ToBool() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a string.
+  util::StatusOr<std::string> ToString() const;
+
+  // Tries to convert the value contained in this datapiece to string. If the
+  // conversion fails, it returns the default_string.
+  std::string ValueAsStringOrDefault(StringPiece default_string) const;
+
+  util::StatusOr<std::string> ToBytes() const;
+
+ private:
+  friend class ProtoWriter;
+
+  // Disallow implicit constructor.
+  DataPiece();
+
+  // Helper to create NULL or ENUM types.
+  DataPiece(Type type, int32_t val)
+      : type_(type), i32_(val), use_strict_base64_decoding_(false) {}
+
+  // Same as the ToEnum() method above but with additional flag to ignore
+  // unknown enum values.
+  util::StatusOr<int> ToEnum(const google::protobuf::Enum* enum_type,
+                             bool use_lower_camel_for_enums,
+                             bool case_insensitive_enum_parsing,
+                             bool ignore_unknown_enum_values,
+                             bool* is_unknown_enum_value) const;
+
+  // For numeric conversion between
+  //     int32, int64, uint32, uint64, double, float and bool
+  template <typename To>
+  util::StatusOr<To> GenericConvert() const;
+
+  // For conversion from string to
+  //     int32, int64, uint32, uint64, double, float and bool
+  template <typename To>
+  util::StatusOr<To> StringToNumber(bool (*func)(StringPiece, To*)) const;
+
+  // Decodes a base64 string. Returns true on success.
+  bool DecodeBase64(StringPiece src, std::string* dest) const;
+
+  // Helper function to initialize this DataPiece with 'other'.
+  void InternalCopy(const DataPiece& other);
+
+  // Data type for this piece of data.
+  Type type_;
+
+  // Stored piece of data.
+  union {
+    int32_t i32_;
+    int64_t i64_;
+    uint32_t u32_;
+    uint64_t u64_;
+    double double_;
+    float float_;
+    bool bool_;
+    StringPiece str_;
+  };
+
+  // Uses a stricter version of base64 decoding for byte fields.
+  bool use_strict_base64_decoding_;
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/default_value_objectwriter.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/default_value_objectwriter.h
new file mode 100644
index 0000000..1a151ab
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/default_value_objectwriter.h
@@ -0,0 +1,332 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <stack>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An ObjectWriter that renders non-repeated primitive fields of proto messages
+// with their default values. DefaultValueObjectWriter holds objects, lists and
+// fields it receives in a tree structure and writes them out to another
+// ObjectWriter when EndObject() is called on the root object. It also writes
+// out all non-repeated primitive fields that haven't been explicitly rendered
+// with their default values (0 for numbers, "" for strings, etc).
+class PROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
+ public:
+  // A Callback function to check whether a field needs to be scrubbed.
+  //
+  // Returns true if the field should not be present in the output. Returns
+  // false otherwise.
+  //
+  // The 'path' parameter is a vector of path to the field from root. For
+  // example: if a nested field "a.b.c" (b is the parent message field of c and
+  // a is the parent message field of b), then the vector should contain { "a",
+  // "b", "c" }.
+  //
+  // The Field* should point to the google::protobuf::Field of "c".
+  typedef std::function<bool(
+      const std::vector<std::string>& /*path of the field*/,
+      const google::protobuf::Field* /*field*/)>
+      FieldScrubCallBack;
+
+  DefaultValueObjectWriter(TypeResolver* type_resolver,
+                           const google::protobuf::Type& type,
+                           ObjectWriter* ow);
+
+  ~DefaultValueObjectWriter() override;
+
+  // ObjectWriter methods.
+  DefaultValueObjectWriter* StartObject(StringPiece name) override;
+
+  DefaultValueObjectWriter* EndObject() override;
+
+  DefaultValueObjectWriter* StartList(StringPiece name) override;
+
+  DefaultValueObjectWriter* EndList() override;
+
+  DefaultValueObjectWriter* RenderBool(StringPiece name,
+                                       bool value) override;
+
+  DefaultValueObjectWriter* RenderInt32(StringPiece name,
+                                        int32_t value) override;
+
+  DefaultValueObjectWriter* RenderUint32(StringPiece name,
+                                         uint32_t value) override;
+
+  DefaultValueObjectWriter* RenderInt64(StringPiece name,
+                                        int64_t value) override;
+
+  DefaultValueObjectWriter* RenderUint64(StringPiece name,
+                                         uint64_t value) override;
+
+  DefaultValueObjectWriter* RenderDouble(StringPiece name,
+                                         double value) override;
+
+  DefaultValueObjectWriter* RenderFloat(StringPiece name,
+                                        float value) override;
+
+  DefaultValueObjectWriter* RenderString(StringPiece name,
+                                         StringPiece value) override;
+  DefaultValueObjectWriter* RenderBytes(StringPiece name,
+                                        StringPiece value) override;
+
+  DefaultValueObjectWriter* RenderNull(StringPiece name) override;
+
+  // Register the callback for scrubbing of fields.
+  void RegisterFieldScrubCallBack(FieldScrubCallBack field_scrub_callback);
+
+  // If set to true, empty lists are suppressed from output when default values
+  // are written.
+  void set_suppress_empty_list(bool value) { suppress_empty_list_ = value; }
+
+  // If set to true, original proto field names are used
+  void set_preserve_proto_field_names(bool value) {
+    preserve_proto_field_names_ = value;
+  }
+
+  // If set to true, enums are rendered as ints from output when default values
+  // are written.
+  void set_print_enums_as_ints(bool value) { use_ints_for_enums_ = value; }
+
+ protected:
+  enum NodeKind {
+    PRIMITIVE = 0,
+    OBJECT = 1,
+    LIST = 2,
+    MAP = 3,
+  };
+
+  // "Node" represents a node in the tree that holds the input of
+  // DefaultValueObjectWriter.
+  class PROTOBUF_EXPORT Node {
+   public:
+    Node(const std::string& name, const google::protobuf::Type* type,
+         NodeKind kind, const DataPiece& data, bool is_placeholder,
+         const std::vector<std::string>& path, bool suppress_empty_list,
+         bool preserve_proto_field_names, bool use_ints_for_enums,
+         FieldScrubCallBack field_scrub_callback);
+    virtual ~Node() {
+      for (size_t i = 0; i < children_.size(); ++i) {
+        delete children_[i];
+      }
+    }
+
+    // Adds a child to this node. Takes ownership of this child.
+    void AddChild(Node* child) { children_.push_back(child); }
+
+    // Finds the child given its name.
+    Node* FindChild(StringPiece name);
+
+    // Populates children of this Node based on its type. If there are already
+    // children created, they will be merged to the result. Caller should pass
+    // in TypeInfo for looking up types of the children.
+    virtual void PopulateChildren(const TypeInfo* typeinfo);
+
+    // If this node is a leaf (has data), writes the current node to the
+    // ObjectWriter; if not, then recursively writes the children to the
+    // ObjectWriter.
+    virtual void WriteTo(ObjectWriter* ow);
+
+    // Accessors
+    const std::string& name() const { return name_; }
+
+    const std::vector<std::string>& path() const { return path_; }
+
+    const google::protobuf::Type* type() const { return type_; }
+
+    void set_type(const google::protobuf::Type* type) { type_ = type; }
+
+    NodeKind kind() const { return kind_; }
+
+    int number_of_children() const { return children_.size(); }
+
+    void set_data(const DataPiece& data) { data_ = data; }
+
+    bool is_any() const { return is_any_; }
+
+    void set_is_any(bool is_any) { is_any_ = is_any; }
+
+    void set_is_placeholder(bool is_placeholder) {
+      is_placeholder_ = is_placeholder;
+    }
+
+   protected:
+    // Returns the Value Type of a map given the Type of the map entry and a
+    // TypeInfo instance.
+    const google::protobuf::Type* GetMapValueType(
+        const google::protobuf::Type& found_type, const TypeInfo* typeinfo);
+
+    // Calls WriteTo() on every child in children_.
+    void WriteChildren(ObjectWriter* ow);
+
+    // The name of this node.
+    std::string name_;
+    // google::protobuf::Type of this node. Owned by TypeInfo.
+    const google::protobuf::Type* type_;
+    // The kind of this node.
+    NodeKind kind_;
+    // Whether this is a node for "Any".
+    bool is_any_;
+    // The data of this node when it is a leaf node.
+    DataPiece data_;
+    // Children of this node.
+    std::vector<Node*> children_;
+    // Whether this node is a placeholder for an object or list automatically
+    // generated when creating the parent node. Should be set to false after
+    // the parent node's StartObject()/StartList() method is called with this
+    // node's name.
+    bool is_placeholder_;
+
+    // Path of the field of this node
+    std::vector<std::string> path_;
+
+    // Whether to suppress empty list output.
+    bool suppress_empty_list_;
+
+    // Whether to preserve original proto field names
+    bool preserve_proto_field_names_;
+
+    // Whether to always print enums as ints
+    bool use_ints_for_enums_;
+
+    // Function for determining whether a field needs to be scrubbed or not.
+    FieldScrubCallBack field_scrub_callback_;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
+  };
+
+  // Creates a new Node and returns it. Caller owns memory of returned object.
+  virtual Node* CreateNewNode(const std::string& name,
+                              const google::protobuf::Type* type, NodeKind kind,
+                              const DataPiece& data, bool is_placeholder,
+                              const std::vector<std::string>& path,
+                              bool suppress_empty_list,
+                              bool preserve_proto_field_names,
+                              bool use_ints_for_enums,
+                              FieldScrubCallBack field_scrub_callback);
+
+  // Creates a DataPiece containing the default value of the type of the field.
+  static DataPiece CreateDefaultDataPieceForField(
+      const google::protobuf::Field& field, const TypeInfo* typeinfo) {
+    return CreateDefaultDataPieceForField(field, typeinfo, false);
+  }
+
+  // Same as the above but with a flag to use ints instead of enum names.
+  static DataPiece CreateDefaultDataPieceForField(
+      const google::protobuf::Field& field, const TypeInfo* typeinfo,
+      bool use_ints_for_enums);
+
+ protected:
+  // Returns a pointer to current Node in tree.
+  Node* current() { return current_; }
+
+ private:
+  // Populates children of "node" if it is an "any" Node and its real type has
+  // been given.
+  void MaybePopulateChildrenOfAny(Node* node);
+
+  // Writes the root_ node to ow_ and resets the root_ and current_ pointer to
+  // nullptr.
+  void WriteRoot();
+
+  // Adds or replaces the data_ of a primitive child node.
+  void RenderDataPiece(StringPiece name, const DataPiece& data);
+
+  // Returns the default enum value as a DataPiece, or the first enum value if
+  // there is no default. For proto3, where we cannot specify an explicit
+  // default, a zero value will always be returned.
+  static DataPiece FindEnumDefault(const google::protobuf::Field& field,
+                                   const TypeInfo* typeinfo,
+                                   bool use_ints_for_enums);
+
+  // Type information for all the types used in the descriptor. Used to find
+  // google::protobuf::Type of nested messages/enums.
+  const TypeInfo* typeinfo_;
+  // Whether the TypeInfo object is owned by this class.
+  bool own_typeinfo_;
+  // google::protobuf::Type of the root message type.
+  const google::protobuf::Type& type_;
+  // Holds copies of strings passed to RenderString.
+  std::vector<std::unique_ptr<std::string>> string_values_;
+
+  // The current Node. Owned by its parents.
+  Node* current_;
+  // The root Node.
+  std::unique_ptr<Node> root_;
+  // The stack to hold the path of Nodes from current_ to root_;
+  std::stack<Node*> stack_;
+
+  // Whether to suppress output of empty lists.
+  bool suppress_empty_list_;
+
+  // Whether to preserve original proto field names
+  bool preserve_proto_field_names_;
+
+  // Whether to always print enums as ints
+  bool use_ints_for_enums_;
+
+  // Function for determining whether a field needs to be scrubbed or not.
+  FieldScrubCallBack field_scrub_callback_;
+
+  ObjectWriter* ow_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultValueObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/error_listener.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/error_listener.h
new file mode 100644
index 0000000..8c9c501
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/error_listener.h
@@ -0,0 +1,109 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// Interface for error listener.
+class PROTOBUF_EXPORT ErrorListener {
+ public:
+  virtual ~ErrorListener() {}
+
+  // Reports an invalid name at the given location.
+  virtual void InvalidName(const LocationTrackerInterface& loc,
+                           StringPiece invalid_name,
+                           StringPiece message) = 0;
+
+  // Reports an invalid value for a field.
+  virtual void InvalidValue(const LocationTrackerInterface& loc,
+                            StringPiece type_name,
+                            StringPiece value) = 0;
+
+  // Reports a missing required field.
+  virtual void MissingField(const LocationTrackerInterface& loc,
+                            StringPiece missing_name) = 0;
+
+ protected:
+  ErrorListener() {}
+
+ private:
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorListener);
+};
+
+// An error listener that ignores all errors.
+class PROTOBUF_EXPORT NoopErrorListener : public ErrorListener {
+ public:
+  NoopErrorListener() {}
+  ~NoopErrorListener() override {}
+
+  void InvalidName(const LocationTrackerInterface& /*loc*/,
+                   StringPiece /* invalid_name */,
+                   StringPiece /* message */) override {}
+
+  void InvalidValue(const LocationTrackerInterface& /*loc*/,
+                    StringPiece /* type_name */,
+                    StringPiece /* value */) override {}
+
+  void MissingField(const LocationTrackerInterface& /* loc */,
+                    StringPiece /* missing_name */) override {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener);
+};
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/field_mask_utility.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/field_mask_utility.h
new file mode 100644
index 0000000..1882333
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/field_mask_utility.h
@@ -0,0 +1,74 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// FieldMask related utility methods.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+typedef std::function<std::string(StringPiece)> ConverterCallback;
+typedef std::function<util::Status(StringPiece)> PathSinkCallback;
+
+// Applies a 'converter' to each segment of a FieldMask path and returns the
+// result. Quoted strings in the 'path' are copied to the output as-is without
+// converting their content. Escaping is supported within quoted strings.
+// For example, "ab\"_c" will be returned as "ab\"_c" without any changes.
+std::string ConvertFieldMaskPath(const StringPiece path,
+                                 ConverterCallback converter);
+
+// Decodes a compact list of FieldMasks. For example, "a.b,a.c.d,a.c.e" will be
+// decoded into a list of field paths - "a.b", "a.c.d", "a.c.e". And the results
+// will be sent to 'path_sink', i.e. 'path_sink' will be called once per
+// resulting path.
+// Note that we also support Apiary style FieldMask form. The above example in
+// the Apiary style will look like "a.b,a.c(d,e)".
+util::Status DecodeCompactFieldMaskPaths(StringPiece paths,
+                                         PathSinkCallback path_sink);
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_escaping.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_escaping.h
new file mode 100644
index 0000000..7d54f22
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_escaping.h
@@ -0,0 +1,98 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class JsonEscaping {
+ public:
+  // The minimum value of a unicode high-surrogate code unit in the utf-16
+  // encoding. A high-surrogate is also known as a leading-surrogate.
+  // See http://www.unicode.org/glossary/#high_surrogate_code_unit
+  static constexpr uint16_t kMinHighSurrogate = 0xd800;
+
+  // The maximum value of a unicide high-surrogate code unit in the utf-16
+  // encoding. A high-surrogate is also known as a leading-surrogate.
+  // See http://www.unicode.org/glossary/#high_surrogate_code_unit
+  static constexpr uint16_t kMaxHighSurrogate = 0xdbff;
+
+  // The minimum value of a unicode low-surrogate code unit in the utf-16
+  // encoding. A low-surrogate is also known as a trailing-surrogate.
+  // See http://www.unicode.org/glossary/#low_surrogate_code_unit
+  static constexpr uint16_t kMinLowSurrogate = 0xdc00;
+
+  // The maximum value of a unicode low-surrogate code unit in the utf-16
+  // encoding. A low-surrogate is also known as a trailing surrogate.
+  // See http://www.unicode.org/glossary/#low_surrogate_code_unit
+  static constexpr uint16_t kMaxLowSurrogate = 0xdfff;
+
+  // The minimum value of a unicode supplementary code point.
+  // See http://www.unicode.org/glossary/#supplementary_code_point
+  static constexpr uint32_t kMinSupplementaryCodePoint = 0x010000;
+
+  // The minimum value of a unicode code point.
+  // See http://www.unicode.org/glossary/#code_point
+  static constexpr uint32_t kMinCodePoint = 0x000000;
+
+  // The maximum value of a unicode code point.
+  // See http://www.unicode.org/glossary/#code_point
+  static constexpr uint32_t kMaxCodePoint = 0x10ffff;
+
+  JsonEscaping() {}
+  virtual ~JsonEscaping() {}
+
+  // Escape the given ByteSource to the given ByteSink.
+  static void Escape(strings::ByteSource* input, strings::ByteSink* output);
+
+  // Escape the given ByteSource to the given ByteSink.
+  // This is optimized for the case where the string is all printable 7-bit
+  // ASCII and does not contain a few other characters (such as quotes).
+  static void Escape(StringPiece input, strings::ByteSink* output);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JsonEscaping);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_objectwriter.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_objectwriter.h
new file mode 100644
index 0000000..92348da
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_objectwriter.h
@@ -0,0 +1,278 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+// An ObjectWriter implementation that outputs JSON. This ObjectWriter
+// supports writing a compact form or a pretty printed form.
+//
+// Sample usage:
+//   string output;
+//   StringOutputStream* str_stream = new StringOutputStream(&output);
+//   CodedOutputStream* out_stream = new CodedOutputStream(str_stream);
+//   JsonObjectWriter* ow = new JsonObjectWriter("  ", out_stream);
+//   ow->StartObject("")
+//       ->RenderString("name", "value")
+//       ->RenderString("emptystring", string())
+//       ->StartObject("nested")
+//         ->RenderInt64("light", 299792458);
+//         ->RenderDouble("pi", 3.141592653589793);
+//       ->EndObject()
+//       ->StartList("empty")
+//       ->EndList()
+//     ->EndObject();
+//
+// And then the output string would become:
+// {
+//   "name": "value",
+//   "emptystring": "",
+//   "nested": {
+//     "light": "299792458",
+//     "pi": 3.141592653589793
+//   },
+//   "empty": []
+// }
+//
+// JsonObjectWriter does not validate if calls actually result in valid JSON.
+// For example, passing an empty name when one would be required won't result
+// in an error, just an invalid output.
+//
+// Note that all int64 and uint64 are rendered as strings instead of numbers.
+// This is because JavaScript parses numbers as 64-bit float thus int64 and
+// uint64 would lose precision if rendered as numbers.
+//
+// JsonObjectWriter is thread-unsafe.
+class PROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter {
+ public:
+  JsonObjectWriter(StringPiece indent_string, io::CodedOutputStream* out)
+      : element_(new Element(/*parent=*/nullptr, /*is_json_object=*/false)),
+        stream_(out),
+        sink_(out),
+        indent_string_(indent_string),
+        indent_char_('\0'),
+        indent_count_(0),
+        use_websafe_base64_for_bytes_(false) {
+    // See if we have a trivial sequence of indent characters.
+    if (!indent_string.empty()) {
+      indent_char_ = indent_string[0];
+      indent_count_ = indent_string.length();
+      for (size_t i = 1; i < indent_string.length(); i++) {
+        if (indent_char_ != indent_string_[i]) {
+          indent_char_ = '\0';
+          indent_count_ = 0;
+          break;
+        }
+      }
+    }
+  }
+  ~JsonObjectWriter() override;
+
+  // ObjectWriter methods.
+  JsonObjectWriter* StartObject(StringPiece name) override;
+  JsonObjectWriter* EndObject() override;
+  JsonObjectWriter* StartList(StringPiece name) override;
+  JsonObjectWriter* EndList() override;
+  JsonObjectWriter* RenderBool(StringPiece name, bool value) override;
+  JsonObjectWriter* RenderInt32(StringPiece name, int32_t value) override;
+  JsonObjectWriter* RenderUint32(StringPiece name,
+                                 uint32_t value) override;
+  JsonObjectWriter* RenderInt64(StringPiece name, int64_t value) override;
+  JsonObjectWriter* RenderUint64(StringPiece name,
+                                 uint64_t value) override;
+  JsonObjectWriter* RenderDouble(StringPiece name, double value) override;
+  JsonObjectWriter* RenderFloat(StringPiece name, float value) override;
+  JsonObjectWriter* RenderString(StringPiece name,
+                                 StringPiece value) override;
+  JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value) override;
+  JsonObjectWriter* RenderNull(StringPiece name) override;
+  virtual JsonObjectWriter* RenderNullAsEmpty(StringPiece name);
+
+  void set_use_websafe_base64_for_bytes(bool value) {
+    use_websafe_base64_for_bytes_ = value;
+  }
+
+ protected:
+  class PROTOBUF_EXPORT Element : public BaseElement {
+   public:
+    Element(Element* parent, bool is_json_object)
+        : BaseElement(parent),
+          is_first_(true),
+          is_json_object_(is_json_object) {}
+
+    // Called before each field of the Element is to be processed.
+    // Returns true if this is the first call (processing the first field).
+    bool is_first() {
+      if (is_first_) {
+        is_first_ = false;
+        return true;
+      }
+      return false;
+    }
+
+    // Whether we are currently rendering inside a JSON object (i.e., between
+    // StartObject() and EndObject()).
+    bool is_json_object() const { return is_json_object_; }
+
+   private:
+    bool is_first_;
+    bool is_json_object_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element);
+  };
+
+  Element* element() override { return element_.get(); }
+
+ private:
+  class PROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink {
+   public:
+    explicit ByteSinkWrapper(io::CodedOutputStream* stream) : stream_(stream) {}
+    ~ByteSinkWrapper() override {}
+
+    // ByteSink methods.
+    void Append(const char* bytes, size_t n) override {
+      stream_->WriteRaw(bytes, n);
+    }
+
+   private:
+    io::CodedOutputStream* stream_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSinkWrapper);
+  };
+
+  // Renders a simple value as a string. By default all non-string Render
+  // methods convert their argument to a string and call this method. This
+  // method can then be used to render the simple value without escaping it.
+  JsonObjectWriter* RenderSimple(StringPiece name,
+                                 StringPiece value) {
+    WritePrefix(name);
+    WriteRawString(value);
+    return this;
+  }
+
+  // Pushes a new JSON array element to the stack.
+  void PushArray() {
+    element_.reset(new Element(element_.release(), /*is_json_object=*/false));
+  }
+
+  // Pushes a new JSON object element to the stack.
+  void PushObject() {
+    element_.reset(new Element(element_.release(), /*is_json_object=*/true));
+  }
+
+  // Pops an element off of the stack and deletes the popped element.
+  void Pop() {
+    bool needs_newline = !element_->is_first();
+    element_.reset(element_->pop<Element>());
+    if (needs_newline) NewLine();
+  }
+
+  // If pretty printing is enabled, this will write a newline to the output,
+  // followed by optional indentation. Otherwise this method is a noop.
+  void NewLine() {
+    if (!indent_string_.empty()) {
+      size_t len = sizeof('\n') + (indent_string_.size() * element()->level());
+
+      // Take the slow-path if we don't have sufficient characters remaining in
+      // our buffer or we have a non-trivial indent string which would prevent
+      // us from using memset.
+      uint8_t* out = nullptr;
+      if (indent_count_ > 0) {
+        out = stream_->GetDirectBufferForNBytesAndAdvance(len);
+      }
+
+      if (out != nullptr) {
+        out[0] = '\n';
+        memset(&out[1], indent_char_, len - 1);
+      } else {
+        // Slow path, no contiguous output buffer available.
+        WriteChar('\n');
+        for (int i = 0; i < element()->level(); i++) {
+          stream_->WriteRaw(indent_string_.c_str(), indent_string_.length());
+        }
+      }
+    }
+  }
+
+  // Writes a prefix. This will write out any pretty printing and
+  // commas that are required, followed by the name and a ':' if
+  // the name is not null.
+  void WritePrefix(StringPiece name);
+
+  // Writes an individual character to the output.
+  void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); }
+
+  // Writes a string to the output.
+  void WriteRawString(StringPiece s) {
+    stream_->WriteRaw(s.data(), s.length());
+  }
+
+  std::unique_ptr<Element> element_;
+  io::CodedOutputStream* stream_;
+  ByteSinkWrapper sink_;
+  const std::string indent_string_;
+
+  // For the common case of indent being a single character repeated.
+  char indent_char_;
+  int indent_count_;
+
+  // Whether to use regular or websafe base64 encoding for byte fields. Defaults
+  // to regular base64 encoding.
+  bool use_websafe_base64_for_bytes_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_stream_parser.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_stream_parser.h
new file mode 100644
index 0000000..09f17ad
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/json_stream_parser.h
@@ -0,0 +1,350 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
+
+#include <cstdint>
+#include <stack>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+class ObjectWriter;
+
+// A JSON parser that can parse a stream of JSON chunks rather than needing the
+// entire JSON string up front. It is a modified version of the parser in
+// //net/proto/json/json-parser.h that has been changed in the following ways:
+// - Changed from recursion to an explicit stack to allow resumption
+// - Added support for int64 and uint64 numbers
+// - Removed support for octal and decimal escapes
+// - Removed support for numeric keys
+// - Removed support for functions (javascript)
+// - Removed some lax-comma support (but kept trailing comma support)
+// - Writes directly to an ObjectWriter rather than using subclassing
+//
+// Here is an example usage:
+// JsonStreamParser parser(ow_.get());
+// util::Status result = parser.Parse(chunk1);
+// result.Update(parser.Parse(chunk2));
+// result.Update(parser.FinishParse());
+// GOOGLE_DCHECK(result.ok()) << "Failed to parse JSON";
+//
+// This parser is thread-compatible as long as only one thread is calling a
+// Parse() method at a time.
+class PROTOBUF_EXPORT JsonStreamParser {
+ public:
+  // Creates a JsonStreamParser that will write to the given ObjectWriter.
+  explicit JsonStreamParser(ObjectWriter* ow);
+  virtual ~JsonStreamParser();
+
+  // Parses a UTF-8 encoded JSON string from a StringPiece. If the returned
+  // status is non-ok, the status might contain a payload ParseErrorType with
+  // type_url kParseErrorTypeUrl and a payload containing string snippet of the
+  // error with type_url kParseErrorSnippetUrl.
+  util::Status Parse(StringPiece json);
+
+
+  // Finish parsing the JSON string. If the returned status is non-ok, the
+  // status might contain a payload ParseErrorType with type_url
+  // kParseErrorTypeUrl and a payload containing string snippet of the error
+  // with type_url kParseErrorSnippetUrl.
+  util::Status FinishParse();
+
+
+  // Sets the max recursion depth of JSON message to be deserialized. JSON
+  // messages over this depth will fail to be deserialized.
+  // Default value is 100.
+  void set_max_recursion_depth(int max_depth) {
+    max_recursion_depth_ = max_depth;
+  }
+
+  // Denotes the cause of error.
+  enum ParseErrorType {
+    UNKNOWN_PARSE_ERROR,
+    OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES,
+    EXPECTED_COLON,
+    EXPECTED_COMMA_OR_BRACKET,
+    EXPECTED_VALUE,
+    EXPECTED_COMMA_OR_BRACES,
+    EXPECTED_OBJECT_KEY_OR_BRACES,
+    EXPECTED_VALUE_OR_BRACKET,
+    INVALID_KEY_OR_VARIABLE_NAME,
+    NON_UTF_8,
+    PARSING_TERMINATED_BEFORE_END_OF_INPUT,
+    UNEXPECTED_TOKEN,
+    EXPECTED_CLOSING_QUOTE,
+    ILLEGAL_HEX_STRING,
+    INVALID_ESCAPE_SEQUENCE,
+    MISSING_LOW_SURROGATE,
+    INVALID_LOW_SURROGATE,
+    INVALID_UNICODE,
+    UNABLE_TO_PARSE_NUMBER,
+    NUMBER_EXCEEDS_RANGE_DOUBLE
+  };
+
+ private:
+  friend class JsonStreamParserTest;
+  // Return the current recursion depth.
+  int recursion_depth() { return recursion_depth_; }
+
+  enum TokenType {
+    BEGIN_STRING,     // " or '
+    BEGIN_NUMBER,     // - or digit
+    BEGIN_TRUE,       // true
+    BEGIN_FALSE,      // false
+    BEGIN_NULL,       // null
+    BEGIN_OBJECT,     // {
+    END_OBJECT,       // }
+    BEGIN_ARRAY,      // [
+    END_ARRAY,        // ]
+    ENTRY_SEPARATOR,  // :
+    VALUE_SEPARATOR,  // ,
+    BEGIN_KEY,        // letter, _, $ or digit.  Must begin with non-digit
+    UNKNOWN           // Unknown token or we ran out of the stream.
+  };
+
+  enum ParseType {
+    VALUE,        // Expects a {, [, true, false, null, string or number
+    OBJ_MID,      // Expects a ',' or }
+    ENTRY,        // Expects a key or }
+    ENTRY_MID,    // Expects a :
+    ARRAY_VALUE,  // Expects a value or ]
+    ARRAY_MID     // Expects a ',' or ]
+  };
+
+  // Holds the result of parsing a number
+  struct NumberResult {
+    enum Type { DOUBLE, INT, UINT };
+    Type type;
+    union {
+      double double_val;
+      int64_t int_val;
+      uint64_t uint_val;
+    };
+  };
+
+  // Parses a single chunk of JSON, returning an error if the JSON was invalid.
+  util::Status ParseChunk(StringPiece chunk);
+
+  // Runs the parser based on stack_ and p_, until the stack is empty or p_ runs
+  // out of data. If we unexpectedly run out of p_ we push the latest back onto
+  // the stack and return.
+  util::Status RunParser();
+
+  // Parses a value from p_ and writes it to ow_.
+  // A value may be an object, array, true, false, null, string or number.
+  util::Status ParseValue(TokenType type);
+
+  // Parses a string and writes it out to the ow_.
+  util::Status ParseString();
+
+  // Parses a string, storing the result in parsed_.
+  util::Status ParseStringHelper();
+
+  // This function parses unicode escape sequences in strings. It returns an
+  // error when there's a parsing error, either the size is not the expected
+  // size or a character is not a hex digit.  When it returns str will contain
+  // what has been successfully parsed so far.
+  util::Status ParseUnicodeEscape();
+
+  // Expects p_ to point to a JSON number, writes the number to the writer using
+  // the appropriate Render method based on the type of number.
+  util::Status ParseNumber();
+
+  // Parse a number into a NumberResult, reporting an error if no number could
+  // be parsed. This method will try to parse into a uint64, int64, or double
+  // based on whether the number was positive or negative or had a decimal
+  // component.
+  util::Status ParseNumberHelper(NumberResult* result);
+
+  // Parse a number as double into a NumberResult.
+  util::Status ParseDoubleHelper(const std::string& number,
+                                 NumberResult* result);
+
+  // Handles a { during parsing of a value.
+  util::Status HandleBeginObject();
+
+  // Parses from the ENTRY state.
+  util::Status ParseEntry(TokenType type);
+
+  // Parses from the ENTRY_MID state.
+  util::Status ParseEntryMid(TokenType type);
+
+  // Parses from the OBJ_MID state.
+  util::Status ParseObjectMid(TokenType type);
+
+  // Handles a [ during parsing of a value.
+  util::Status HandleBeginArray();
+
+  // Parses from the ARRAY_VALUE state.
+  util::Status ParseArrayValue(TokenType type);
+
+  // Parses from the ARRAY_MID state.
+  util::Status ParseArrayMid(TokenType type);
+
+  // Expects p_ to point to an unquoted literal
+  util::Status ParseTrue();
+  util::Status ParseFalse();
+  util::Status ParseNull();
+  util::Status ParseEmptyNull();
+
+  // Whether an empty-null is allowed in the current state.
+  bool IsEmptyNullAllowed(TokenType type);
+
+  // Whether the whole input is all whitespaces.
+  bool IsInputAllWhiteSpaces(TokenType type);
+
+  // Report a failure as a util::Status.
+  util::Status ReportFailure(StringPiece message,
+                             ParseErrorType parse_code);
+
+  // Report a failure due to an UNKNOWN token type. We check if we hit the
+  // end of the stream and if we're finishing or not to detect what type of
+  // status to return in this case.
+  util::Status ReportUnknown(StringPiece message,
+                             ParseErrorType parse_code);
+
+  // Helper function to check recursion depth and increment it. It will return
+  // OkStatus() if the current depth is allowed. Otherwise an error is returned.
+  // key is used for error reporting.
+  util::Status IncrementRecursionDepth(StringPiece key) const;
+
+  // Advance p_ past all whitespace or until the end of the string.
+  void SkipWhitespace();
+
+  // Advance p_ one UTF-8 character
+  void Advance();
+
+  // Expects p_ to point to the beginning of a key.
+  util::Status ParseKey();
+
+  // Return the type of the next token at p_.
+  TokenType GetNextTokenType();
+
+  // The object writer to write parse events to.
+  ObjectWriter* ow_;
+
+  // The stack of parsing we still need to do. When the stack runs empty we will
+  // have parsed a single value from the root (e.g. an object or list).
+  std::stack<ParseType> stack_;
+
+  // Contains any leftover text from a previous chunk that we weren't able to
+  // fully parse, for example the start of a key or number.
+  std::string leftover_;
+
+  // The current chunk of JSON being parsed. Primarily used for providing
+  // context during error reporting.
+  StringPiece json_;
+
+  // A pointer within the current JSON being parsed, used to track location.
+  StringPiece p_;
+
+  // Stores the last key read, as we separate parsing of keys and values.
+  StringPiece key_;
+
+  // Storage for key_ if we need to keep ownership, for example between chunks
+  // or if the key was unescaped from a JSON string.
+  std::string key_storage_;
+
+  // True during the FinishParse() call, so we know that any errors are fatal.
+  // For example an unterminated string will normally result in cancelling and
+  // trying during the next chunk, but during FinishParse() it is an error.
+  bool finishing_;
+
+  // Whether non whitespace tokens have been seen during parsing.
+  // It is used to handle the case of a pure whitespace stream input.
+  bool seen_non_whitespace_;
+
+  // The JsonStreamParser requires a root element by default and it will raise
+  // error if the root element is missing. If `allow_no_root_element_` is true,
+  // the JsonStreamParser can also handle this case.
+  bool allow_no_root_element_;
+
+  // String we parsed during a call to ParseStringHelper().
+  StringPiece parsed_;
+
+  // Storage for the string we parsed. This may be empty if the string was able
+  // to be parsed directly from the input.
+  std::string parsed_storage_;
+
+  // The character that opened the string, either ' or ".
+  // A value of 0 indicates that string parsing is not in process.
+  char string_open_;
+
+  // Storage for the chunk that are being parsed in ParseChunk().
+  std::string chunk_storage_;
+
+  // Whether to allow non UTF-8 encoded input and replace invalid code points.
+  bool coerce_to_utf8_;
+
+  // Replacement character for invalid UTF-8 code points.
+  std::string utf8_replacement_character_;
+
+  // Whether allows empty string represented null array value or object entry
+  // value.
+  bool allow_empty_null_;
+
+  // Whether unquoted object keys can contain embedded non-alphanumeric
+  // characters when this is unambiguous for parsing.
+  bool allow_permissive_key_naming_;
+
+  // Whether allows out-of-range floating point numbers or reject them.
+  bool loose_float_number_conversion_;
+
+  // Tracks current recursion depth.
+  mutable int recursion_depth_;
+
+  // Maximum allowed recursion depth.
+  int max_recursion_depth_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonStreamParser);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/location_tracker.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/location_tracker.h
new file mode 100644
index 0000000..68fefcc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/location_tracker.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// LocationTrackerInterface is an interface for classes that track
+// the location information for the purpose of error reporting.
+class PROTOBUF_EXPORT LocationTrackerInterface {
+ public:
+  virtual ~LocationTrackerInterface() {}
+
+  // Returns the object location as human readable string.
+  virtual std::string ToString() const = 0;
+
+ protected:
+  LocationTrackerInterface() {}
+
+ private:
+  // Please do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LocationTrackerInterface);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_location_tracker.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_location_tracker.h
new file mode 100644
index 0000000..47821e6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_location_tracker.h
@@ -0,0 +1,64 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An empty concrete implementation of LocationTrackerInterface.
+class ObjectLocationTracker : public LocationTrackerInterface {
+ public:
+  // Creates an empty location tracker.
+  ObjectLocationTracker() {}
+
+  ~ObjectLocationTracker() override {}
+
+  // Returns empty because nothing is tracked.
+  std::string ToString() const override { return ""; }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectLocationTracker);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_source.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_source.h
new file mode 100644
index 0000000..fc7672e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_source.h
@@ -0,0 +1,85 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectWriter;
+
+// An ObjectSource is anything that can write to an ObjectWriter.
+// Implementation of this interface typically provide constructors or
+// factory methods to create an instance based on some source data, for
+// example, a character stream, or protobuf.
+//
+// Derived classes could be thread-unsafe.
+class PROTOBUF_EXPORT ObjectSource {
+ public:
+  virtual ~ObjectSource() {}
+
+  // Writes to the ObjectWriter
+  virtual util::Status WriteTo(ObjectWriter* ow) const {
+    return NamedWriteTo("", ow);
+  }
+
+  // Writes to the ObjectWriter with a custom name for the message.
+  // This is useful when you chain ObjectSource together by embedding one
+  // within another.
+  virtual util::Status NamedWriteTo(StringPiece name,
+                                    ObjectWriter* ow) const = 0;
+
+ protected:
+  ObjectSource() {}
+
+ private:
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectSource);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_writer.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_writer.h
new file mode 100644
index 0000000..bc4095b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/object_writer.h
@@ -0,0 +1,151 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+class DataPiece;
+
+// An ObjectWriter is an interface for writing a stream of events
+// representing objects and collections. Implementation of this
+// interface can be used to write an object stream to an in-memory
+// structure, protobufs, JSON, XML, or any other output format
+// desired. The ObjectSource interface is typically used as the
+// source of an object stream.
+//
+// See JsonObjectWriter for a sample implementation of ObjectWriter
+// and its use.
+//
+// Derived classes could be thread-unsafe.
+//
+// TODO(xinb): seems like a prime candidate to apply the RAII paradigm
+// and get rid the need to call EndXXX().
+class PROTOBUF_EXPORT ObjectWriter {
+ public:
+  virtual ~ObjectWriter() {}
+
+  // Starts an object. If the name is empty, the object will not be named.
+  virtual ObjectWriter* StartObject(StringPiece name) = 0;
+
+  // Ends an object.
+  virtual ObjectWriter* EndObject() = 0;
+
+  // Starts a list. If the name is empty, the list will not be named.
+  virtual ObjectWriter* StartList(StringPiece name) = 0;
+
+  // Ends a list.
+  virtual ObjectWriter* EndList() = 0;
+
+  // Renders a boolean value.
+  virtual ObjectWriter* RenderBool(StringPiece name, bool value) = 0;
+
+  // Renders an 32-bit integer value.
+  virtual ObjectWriter* RenderInt32(StringPiece name, int32_t value) = 0;
+
+  // Renders an 32-bit unsigned integer value.
+  virtual ObjectWriter* RenderUint32(StringPiece name,
+                                     uint32_t value) = 0;
+
+  // Renders a 64-bit integer value.
+  virtual ObjectWriter* RenderInt64(StringPiece name, int64_t value) = 0;
+
+  // Renders an 64-bit unsigned integer value.
+  virtual ObjectWriter* RenderUint64(StringPiece name,
+                                     uint64_t value) = 0;
+
+
+  // Renders a double value.
+  virtual ObjectWriter* RenderDouble(StringPiece name, double value) = 0;
+  // Renders a float value.
+  virtual ObjectWriter* RenderFloat(StringPiece name, float value) = 0;
+
+  // Renders a StringPiece value. This is for rendering strings.
+  virtual ObjectWriter* RenderString(StringPiece name,
+                                     StringPiece value) = 0;
+
+  // Renders a bytes value.
+  virtual ObjectWriter* RenderBytes(StringPiece name, StringPiece value) = 0;
+
+  // Renders a Null value.
+  virtual ObjectWriter* RenderNull(StringPiece name) = 0;
+
+
+  // Renders a DataPiece object to a ObjectWriter.
+  static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
+                                ObjectWriter* ow);
+
+
+  // Indicates whether this ObjectWriter has completed writing the root message,
+  // usually this means writing of one complete object. Subclasses must override
+  // this behavior appropriately.
+  virtual bool done() { return false; }
+
+  void set_use_strict_base64_decoding(bool value) {
+    use_strict_base64_decoding_ = value;
+  }
+
+  bool use_strict_base64_decoding() const {
+    return use_strict_base64_decoding_;
+  }
+
+ protected:
+  ObjectWriter() : use_strict_base64_decoding_(true) {}
+
+ private:
+  // If set to true, we use the stricter version of base64 decoding for byte
+  // fields by making sure decoded version encodes back to the original string.
+  bool use_strict_base64_decoding_;
+
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/proto_writer.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/proto_writer.h
new file mode 100644
index 0000000..a7cf6ac
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/proto_writer.h
@@ -0,0 +1,389 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
+
+#include <cstdint>
+#include <deque>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+class ObjectLocationTracker;
+
+// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class does not support special types like Struct or Map. However, since
+// this class supports raw protobuf, it can be used to provide support for
+// special types by inheriting from it or by wrapping it.
+//
+// It also supports streaming.
+class PROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
+ public:
+// Constructor. Does not take ownership of any parameter passed in.
+  ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type,
+              strings::ByteSink* output, ErrorListener* listener);
+  ~ProtoWriter() override;
+
+  // ObjectWriter methods.
+  ProtoWriter* StartObject(StringPiece name) override;
+  ProtoWriter* EndObject() override;
+  ProtoWriter* StartList(StringPiece name) override;
+  ProtoWriter* EndList() override;
+  ProtoWriter* RenderBool(StringPiece name, bool value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderInt32(StringPiece name, int32_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderUint32(StringPiece name, uint32_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderInt64(StringPiece name, int64_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderUint64(StringPiece name, uint64_t value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderDouble(StringPiece name, double value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderFloat(StringPiece name, float value) override {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  ProtoWriter* RenderString(StringPiece name,
+                            StringPiece value) override {
+    return RenderDataPiece(name,
+                           DataPiece(value, use_strict_base64_decoding()));
+  }
+
+  ProtoWriter* RenderBytes(StringPiece name, StringPiece value) override {
+    return RenderDataPiece(
+        name, DataPiece(value, false, use_strict_base64_decoding()));
+  }
+
+  ProtoWriter* RenderNull(StringPiece name) override {
+    return RenderDataPiece(name, DataPiece::NullData());
+  }
+
+
+  // Renders a DataPiece 'value' into a field whose wire type is determined
+  // from the given field 'name'.
+  virtual ProtoWriter* RenderDataPiece(StringPiece name,
+                                       const DataPiece& data);
+
+
+  // Returns the location tracker to use for tracking locations for errors.
+  const LocationTrackerInterface& location() {
+    return element_ != nullptr ? *element_ : *tracker_;
+  }
+
+  // When true, we finished writing to output a complete message.
+  bool done() override { return done_; }
+
+  // Returns the proto stream object.
+  io::CodedOutputStream* stream() { return stream_.get(); }
+
+  // Getters and mutators of invalid_depth_.
+  void IncrementInvalidDepth() { ++invalid_depth_; }
+  void DecrementInvalidDepth() { --invalid_depth_; }
+  int invalid_depth() { return invalid_depth_; }
+
+  ErrorListener* listener() { return listener_; }
+
+  const TypeInfo* typeinfo() { return typeinfo_; }
+
+  void set_ignore_unknown_fields(bool ignore_unknown_fields) {
+    ignore_unknown_fields_ = ignore_unknown_fields;
+  }
+
+  bool ignore_unknown_fields() { return ignore_unknown_fields_; }
+
+  void set_ignore_unknown_enum_values(bool ignore_unknown_enum_values) {
+    ignore_unknown_enum_values_ = ignore_unknown_enum_values;
+  }
+
+  void set_use_lower_camel_for_enums(bool use_lower_camel_for_enums) {
+    use_lower_camel_for_enums_ = use_lower_camel_for_enums;
+  }
+
+  void set_case_insensitive_enum_parsing(bool case_insensitive_enum_parsing) {
+    case_insensitive_enum_parsing_ = case_insensitive_enum_parsing;
+  }
+
+  void set_use_json_name_in_missing_fields(
+      bool use_json_name_in_missing_fields) {
+    use_json_name_in_missing_fields_ = use_json_name_in_missing_fields;
+  }
+
+ protected:
+  class PROTOBUF_EXPORT ProtoElement : public BaseElement,
+                                       public LocationTrackerInterface {
+   public:
+    // Constructor for the root element. No parent nor field.
+    ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+                 ProtoWriter* enclosing);
+
+    // Constructor for a field of an element.
+    ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
+                 const google::protobuf::Type& type, bool is_list);
+
+    ~ProtoElement() override {}
+
+    // Called just before the destructor for clean up:
+    //   - reports any missing required fields
+    //   - computes the space needed by the size field, and augment the
+    //     length of all parent messages by this additional space.
+    //   - releases and returns the parent pointer.
+    ProtoElement* pop();
+
+    // Accessors
+    // parent_field() may be nullptr if we are at root.
+    const google::protobuf::Field* parent_field() const {
+      return parent_field_;
+    }
+    const google::protobuf::Type& type() const { return type_; }
+
+    // Registers field for accounting required fields.
+    void RegisterField(const google::protobuf::Field* field);
+
+    // To report location on error messages.
+    std::string ToString() const override;
+
+    ProtoElement* parent() const override {
+      return static_cast<ProtoElement*>(BaseElement::parent());
+    }
+
+    // Returns true if the index is already taken by a preceding oneof input.
+    bool IsOneofIndexTaken(int32_t index);
+
+    // Marks the oneof 'index' as taken. Future inputs to this oneof will
+    // generate an error.
+    void TakeOneofIndex(int32_t index);
+
+    bool proto3() { return proto3_; }
+
+   private:
+    // Used for access to variables of the enclosing instance of
+    // ProtoWriter.
+    ProtoWriter* ow_;
+
+    // Describes the element as a field in the parent message.
+    // parent_field_ is nullptr if and only if this element is the root element.
+    const google::protobuf::Field* parent_field_;
+
+    // TypeInfo to lookup types.
+    const TypeInfo* typeinfo_;
+
+    // Whether the type_ is proto3 or not.
+    bool proto3_;
+
+    // Additional variables if this element is a message:
+    // (Root element is always a message).
+    // type_             : the type of this element.
+    // required_fields_  : set of required fields.
+    // size_index_       : index into ProtoWriter::size_insert_
+    //                     for later insertion of serialized message length.
+    const google::protobuf::Type& type_;
+    std::unordered_set<const google::protobuf::Field*> required_fields_;
+    const int size_index_;
+
+    // Tracks position in repeated fields, needed for LocationTrackerInterface.
+    int array_index_;
+
+    // Set of oneof indices already seen for the type_. Used to validate
+    // incoming messages so no more than one oneof is set.
+    std::vector<bool> oneof_indices_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
+  };
+
+  // Container for inserting 'size' information at the 'pos' position.
+  struct SizeInfo {
+    const int pos;
+    int size;
+  };
+
+  ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+              strings::ByteSink* output, ErrorListener* listener);
+
+  ProtoElement* element() override { return element_.get(); }
+
+  // Helper methods for calling ErrorListener. See error_listener.h.
+  void InvalidName(StringPiece unknown_name, StringPiece message);
+  void InvalidValue(StringPiece type_name, StringPiece value);
+  void MissingField(StringPiece missing_name);
+
+  // Common code for BeginObject() and BeginList() that does invalid_depth_
+  // bookkeeping associated with name lookup.
+  const google::protobuf::Field* BeginNamed(StringPiece name,
+                                            bool is_list);
+
+  // Lookup the field in the current element. Looks in the base descriptor
+  // and in any extension. This will report an error if the field cannot be
+  // found when ignore_unknown_names_ is false or if multiple matching
+  // extensions are found.
+  const google::protobuf::Field* Lookup(StringPiece name);
+
+  // Lookup the field type in the type descriptor. Returns nullptr if the type
+  // is not known.
+  const google::protobuf::Type* LookupType(
+      const google::protobuf::Field* field);
+
+  // Write serialized output to the final output ByteSink, inserting all
+  // the size information for nested messages that are missing from the
+  // intermediate Cord buffer.
+  void WriteRootMessage();
+
+  // Helper method to write proto tags based on the given field.
+  void WriteTag(const google::protobuf::Field& field);
+
+
+  // Returns true if the field for type_ can be set as a oneof. If field is not
+  // a oneof type, this function does nothing and returns true.
+  // If another field for this oneof is already set, this function returns
+  // false. It also calls the appropriate error callback.
+  // unnormalized_name is used for error string.
+  bool ValidOneof(const google::protobuf::Field& field,
+                  StringPiece unnormalized_name);
+
+  // Returns true if the field is repeated.
+  bool IsRepeated(const google::protobuf::Field& field);
+
+  // Starts an object given the field and the enclosing type.
+  ProtoWriter* StartObjectField(const google::protobuf::Field& field,
+                                const google::protobuf::Type& type);
+
+  // Starts a list given the field and the enclosing type.
+  ProtoWriter* StartListField(const google::protobuf::Field& field,
+                              const google::protobuf::Type& type);
+
+  // Renders a primitive field given the field and the enclosing type.
+  ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field,
+                                    const google::protobuf::Type& type,
+                                    const DataPiece& data);
+
+ private:
+  // Writes an ENUM field, including tag, to the stream.
+  static util::Status WriteEnum(int field_number, const DataPiece& data,
+                                const google::protobuf::Enum* enum_type,
+                                io::CodedOutputStream* stream,
+                                bool use_lower_camel_for_enums,
+                                bool case_insensitive_enum_parsing,
+                                bool ignore_unknown_values);
+
+  // Variables for describing the structure of the input tree:
+  // master_type_: descriptor for the whole protobuf message.
+  // typeinfo_ : the TypeInfo object to lookup types.
+  const google::protobuf::Type& master_type_;
+  const TypeInfo* typeinfo_;
+  // Whether we own the typeinfo_ object.
+  bool own_typeinfo_;
+
+  // Indicates whether we finished writing root message completely.
+  bool done_;
+
+  // If true, don't report unknown field names to the listener.
+  bool ignore_unknown_fields_;
+
+  // If true, don't report unknown enum values to the listener.
+  bool ignore_unknown_enum_values_;
+
+  // If true, check if enum name in camel case or without underscore matches the
+  // field name.
+  bool use_lower_camel_for_enums_;
+
+  // If true, check if enum name in UPPER_CASE matches the field name.
+  bool case_insensitive_enum_parsing_;
+
+  // If true, use the json name in missing fields errors.
+  bool use_json_name_in_missing_fields_;
+
+  // Variable for internal state processing:
+  // element_    : the current element.
+  // size_insert_: sizes of nested messages.
+  //               pos  - position to insert the size field.
+  //               size - size value to be inserted.
+  std::unique_ptr<ProtoElement> element_;
+  std::deque<SizeInfo> size_insert_;
+
+  // Variables for output generation:
+  // output_  : pointer to an external ByteSink for final user-visible output.
+  // buffer_  : buffer holding partial message before being ready for output_.
+  // adapter_ : internal adapter between CodedOutputStream and buffer_.
+  // stream_  : wrapper for writing tags and other encodings in wire format.
+  strings::ByteSink* output_;
+  std::string buffer_;
+  io::StringOutputStream adapter_;
+  std::unique_ptr<io::CodedOutputStream> stream_;
+
+  // Variables for error tracking and reporting:
+  // listener_     : a place to report any errors found.
+  // invalid_depth_: number of enclosing invalid nested messages.
+  // tracker_      : the root location tracker interface.
+  ErrorListener* listener_;
+  int invalid_depth_;
+  std::unique_ptr<LocationTrackerInterface> tracker_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/protostream_objectsource.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/protostream_objectsource.h
new file mode 100644
index 0000000..8ed2ca9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/protostream_objectsource.h
@@ -0,0 +1,329 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
+
+#include <cstdint>
+#include <functional>
+#include <string>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/status.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/object_source.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/stubs/status.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class TypeInfo;
+
+// An ObjectSource that can parse a stream of bytes as a protocol buffer.
+// Its WriteTo() method can be given an ObjectWriter.
+// This implementation uses a google.protobuf.Type for tag and name lookup.
+// The field names are converted into lower camel-case when writing to the
+// ObjectWriter.
+//
+// Sample usage: (suppose input is: string proto)
+//   ArrayInputStream arr_stream(proto.data(), proto.size());
+//   CodedInputStream in_stream(&arr_stream);
+//   ProtoStreamObjectSource os(&in_stream, /*ServiceTypeInfo*/ typeinfo,
+//                              <your message google::protobuf::Type>);
+//
+//   Status status = os.WriteTo(<some ObjectWriter>);
+class PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
+ public:
+
+  struct RenderOptions {
+    RenderOptions() = default;
+    RenderOptions(const RenderOptions&) = default;
+
+    // Sets whether or not to use lowerCamelCase casing for enum values. If set
+    // to false, enum values are output without any case conversions.
+    //
+    // For example, if we have an enum:
+    // enum Type {
+    //   ACTION_AND_ADVENTURE = 1;
+    // }
+    // Type type = 20;
+    //
+    // And this option is set to true. Then the rendered "type" field will have
+    // the string "actionAndAdventure".
+    // {
+    //   ...
+    //   "type": "actionAndAdventure",
+    //   ...
+    // }
+    //
+    // If set to false, the rendered "type" field will have the string
+    // "ACTION_AND_ADVENTURE".
+    // {
+    //   ...
+    //   "type": "ACTION_AND_ADVENTURE",
+    //   ...
+    // }
+    bool use_lower_camel_for_enums = false;
+
+    // Sets whether to always output enums as ints, by default this is off, and
+    // enums are rendered as strings.
+    bool use_ints_for_enums = false;
+
+    // Whether to preserve proto field names
+    bool preserve_proto_field_names = false;
+
+  };
+
+  ProtoStreamObjectSource(io::CodedInputStream* stream,
+                          TypeResolver* type_resolver,
+                          const google::protobuf::Type& type)
+      : ProtoStreamObjectSource(stream, type_resolver, type, RenderOptions()) {}
+  ProtoStreamObjectSource(io::CodedInputStream* stream,
+                          TypeResolver* type_resolver,
+                          const google::protobuf::Type& type,
+                          const RenderOptions& render_options);
+
+  ~ProtoStreamObjectSource() override;
+
+  util::Status NamedWriteTo(StringPiece name,
+                            ObjectWriter* ow) const override;
+
+  // Sets the max recursion depth of proto message to be deserialized. Proto
+  // messages over this depth will fail to be deserialized.
+  // Default value is 64.
+  void set_max_recursion_depth(int max_depth) {
+    max_recursion_depth_ = max_depth;
+  }
+
+ protected:
+  // Writes a proto2 Message to the ObjectWriter. When the given end_tag is
+  // found this method will complete, allowing it to be used for parsing both
+  // nested messages (end with 0) and nested groups (end with group end tag).
+  // The include_start_and_end parameter allows this method to be called when
+  // already inside of an object, and skip calling StartObject and EndObject.
+  virtual util::Status WriteMessage(const google::protobuf::Type& type,
+                                    StringPiece name,
+                                    const uint32_t end_tag,
+                                    bool include_start_and_end,
+                                    ObjectWriter* ow) const;
+
+  // Renders a repeating field (packed or unpacked).  Returns the next tag after
+  // reading all sequential repeating elements. The caller should use this tag
+  // before reading more tags from the stream.
+  virtual util::StatusOr<uint32_t> RenderList(
+      const google::protobuf::Field* field, StringPiece name,
+      uint32_t list_tag, ObjectWriter* ow) const;
+
+  // Looks up a field and verify its consistency with wire type in tag.
+  const google::protobuf::Field* FindAndVerifyField(
+      const google::protobuf::Type& type, uint32_t tag) const;
+
+  // Renders a field value to the ObjectWriter.
+  virtual util::Status RenderField(const google::protobuf::Field* field,
+                                   StringPiece field_name,
+                                   ObjectWriter* ow) const;
+
+  // Reads field value according to Field spec in 'field' and returns the read
+  // value as string. This only works for primitive datatypes (no message
+  // types).
+  const std::string ReadFieldValueAsString(
+      const google::protobuf::Field& field) const;
+
+
+  // Returns the input stream.
+  io::CodedInputStream* stream() const { return stream_; }
+
+ private:
+  ProtoStreamObjectSource(io::CodedInputStream* stream,
+                          const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type,
+                          const RenderOptions& render_options);
+  // Function that renders a well known type with a modified behavior.
+  typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*,
+                                       const google::protobuf::Type&,
+                                       StringPiece, ObjectWriter*);
+
+  // TODO(skarvaje): Mark these methods as non-const as they modify internal
+  // state (stream_).
+  //
+  // Renders a NWP map.
+  // Returns the next tag after reading all map entries. The caller should use
+  // this tag before reading more tags from the stream.
+  util::StatusOr<uint32_t> RenderMap(const google::protobuf::Field* field,
+                                     StringPiece name, uint32_t list_tag,
+                                     ObjectWriter* ow) const;
+
+  // Renders a packed repeating field. A packed field is stored as:
+  // {tag length item1 item2 item3} instead of the less efficient
+  // {tag item1 tag item2 tag item3}.
+  util::Status RenderPacked(const google::protobuf::Field* field,
+                            ObjectWriter* ow) const;
+
+  // Renders a google.protobuf.Timestamp value to ObjectWriter
+  static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
+                                      const google::protobuf::Type& type,
+                                      StringPiece name, ObjectWriter* ow);
+
+  // Renders a google.protobuf.Duration value to ObjectWriter
+  static util::Status RenderDuration(const ProtoStreamObjectSource* os,
+                                     const google::protobuf::Type& type,
+                                     StringPiece name, ObjectWriter* ow);
+
+  // Following RenderTYPE functions render well known types in
+  // google/protobuf/wrappers.proto corresponding to TYPE.
+  static util::Status RenderDouble(const ProtoStreamObjectSource* os,
+                                   const google::protobuf::Type& type,
+                                   StringPiece name, ObjectWriter* ow);
+  static util::Status RenderFloat(const ProtoStreamObjectSource* os,
+                                  const google::protobuf::Type& type,
+                                  StringPiece name, ObjectWriter* ow);
+  static util::Status RenderInt64(const ProtoStreamObjectSource* os,
+                                  const google::protobuf::Type& type,
+                                  StringPiece name, ObjectWriter* ow);
+  static util::Status RenderUInt64(const ProtoStreamObjectSource* os,
+                                   const google::protobuf::Type& type,
+                                   StringPiece name, ObjectWriter* ow);
+  static util::Status RenderInt32(const ProtoStreamObjectSource* os,
+                                  const google::protobuf::Type& type,
+                                  StringPiece name, ObjectWriter* ow);
+  static util::Status RenderUInt32(const ProtoStreamObjectSource* os,
+                                   const google::protobuf::Type& type,
+                                   StringPiece name, ObjectWriter* ow);
+  static util::Status RenderBool(const ProtoStreamObjectSource* os,
+                                 const google::protobuf::Type& type,
+                                 StringPiece name, ObjectWriter* ow);
+  static util::Status RenderString(const ProtoStreamObjectSource* os,
+                                   const google::protobuf::Type& type,
+                                   StringPiece name, ObjectWriter* ow);
+  static util::Status RenderBytes(const ProtoStreamObjectSource* os,
+                                  const google::protobuf::Type& type,
+                                  StringPiece name, ObjectWriter* ow);
+
+  // Renders a google.protobuf.Struct to ObjectWriter.
+  static util::Status RenderStruct(const ProtoStreamObjectSource* os,
+                                   const google::protobuf::Type& type,
+                                   StringPiece name, ObjectWriter* ow);
+
+  // Helper to render google.protobuf.Struct's Value fields to ObjectWriter.
+  static util::Status RenderStructValue(const ProtoStreamObjectSource* os,
+                                        const google::protobuf::Type& type,
+                                        StringPiece name,
+                                        ObjectWriter* ow);
+
+  // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
+  static util::Status RenderStructListValue(const ProtoStreamObjectSource* os,
+                                            const google::protobuf::Type& type,
+                                            StringPiece name,
+                                            ObjectWriter* ow);
+
+  // Render the "Any" type.
+  static util::Status RenderAny(const ProtoStreamObjectSource* os,
+                                const google::protobuf::Type& type,
+                                StringPiece name, ObjectWriter* ow);
+
+  // Render the "FieldMask" type.
+  static util::Status RenderFieldMask(const ProtoStreamObjectSource* os,
+                                      const google::protobuf::Type& type,
+                                      StringPiece name, ObjectWriter* ow);
+
+  static std::unordered_map<std::string, TypeRenderer>* renderers_;
+  static void InitRendererMap();
+  static void DeleteRendererMap();
+  static TypeRenderer* FindTypeRenderer(const std::string& type_url);
+
+  // Same as above but renders all non-message field types. Callers don't call
+  // this function directly. They just use RenderField.
+  util::Status RenderNonMessageField(const google::protobuf::Field* field,
+                                     StringPiece field_name,
+                                     ObjectWriter* ow) const;
+
+
+  // Utility function to detect proto maps. The 'field' MUST be repeated.
+  bool IsMap(const google::protobuf::Field& field) const;
+
+  // Utility to read int64 and int32 values from a message type in stream_.
+  // Used for reading google.protobuf.Timestamp and Duration messages.
+  std::pair<int64_t, int32_t> ReadSecondsAndNanos(
+      const google::protobuf::Type& type) const;
+
+  // Helper function to check recursion depth and increment it. It will return
+  // OkStatus() if the current depth is allowed. Otherwise an error is returned.
+  // type_name and field_name are used for error reporting.
+  util::Status IncrementRecursionDepth(StringPiece type_name,
+                                       StringPiece field_name) const;
+
+  // Input stream to read from. Ownership rests with the caller.
+  mutable io::CodedInputStream* stream_;
+
+  // Type information for all the types used in the descriptor. Used to find
+  // google::protobuf::Type of nested messages/enums.
+  const TypeInfo* typeinfo_;
+
+  // Whether this class owns the typeinfo_ object. If true the typeinfo_ object
+  // should be deleted in the destructor.
+  bool own_typeinfo_;
+
+  // google::protobuf::Type of the message source.
+  const google::protobuf::Type& type_;
+
+
+  const RenderOptions render_options_;
+
+  // Tracks current recursion depth.
+  mutable int recursion_depth_;
+
+  // Maximum allowed recursion depth.
+  int max_recursion_depth_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/protostream_objectwriter.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/protostream_objectwriter.h
new file mode 100644
index 0000000..ce2517f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/protostream_objectwriter.h
@@ -0,0 +1,453 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
+
+#include <deque>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/proto_writer.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/hash.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectLocationTracker;
+
+// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class supports all special types like Struct and Map. It uses
+// the ProtoWriter class to write raw proto bytes.
+//
+// It also supports streaming.
+class PROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
+ public:
+  // Options that control ProtoStreamObjectWriter class's behavior.
+  struct Options {
+    // Treats numeric inputs in google.protobuf.Struct as strings. Normally,
+    // numeric values are returned in double field "number_value" of
+    // google.protobuf.Struct. However, this can cause precision loss for
+    // int64/uint64/double inputs. This option is provided for cases that want
+    // to preserve number precision.
+    //
+    // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double
+    // as well.
+    bool struct_integers_as_strings;
+
+    // Not treat unknown fields as an error. If there is an unknown fields,
+    // just ignore it and continue to process the rest. Note that this doesn't
+    // apply to unknown enum values.
+    bool ignore_unknown_fields;
+
+    // Ignore unknown enum values.
+    bool ignore_unknown_enum_values;
+
+    // If true, check if enum name in camel case or without underscore matches
+    // the field name.
+    bool use_lower_camel_for_enums;
+
+    // If true, check if enum name in UPPER_CASE matches the field name.
+    bool case_insensitive_enum_parsing;
+
+    // If true, skips rendering the map entry if map value is null unless the
+    // value type is google.protobuf.NullType.
+    bool ignore_null_value_map_entry;
+
+    // If true, accepts repeated key/value pair for a map proto field.
+    bool use_legacy_json_map_format;
+
+    // If true, disable implicitly creating message list.
+    bool disable_implicit_message_list;
+
+    // If true, suppress the error of implicitly creating message list when it
+    // is disabled.
+    bool suppress_implicit_message_list_error;
+
+    // If true, disable implicitly creating scalar list.
+    bool disable_implicit_scalar_list;
+
+    // If true, suppress the error of implicitly creating scalar list when it
+    // is disabled.
+    bool suppress_implicit_scalar_list_error;
+
+    // If true, suppress the error of rendering scalar field if the source is an
+    // object.
+    bool suppress_object_to_scalar_error;
+
+    // If true, use the json name in missing fields errors.
+    bool use_json_name_in_missing_fields;
+
+    Options()
+        : struct_integers_as_strings(false),
+          ignore_unknown_fields(false),
+          ignore_unknown_enum_values(false),
+          use_lower_camel_for_enums(false),
+          case_insensitive_enum_parsing(false),
+          ignore_null_value_map_entry(false),
+          use_legacy_json_map_format(false),
+          disable_implicit_message_list(false),
+          suppress_implicit_message_list_error(false),
+          disable_implicit_scalar_list(false),
+          suppress_implicit_scalar_list_error(false),
+          suppress_object_to_scalar_error(false),
+          use_json_name_in_missing_fields(false) {}
+
+    // Default instance of Options with all options set to defaults.
+    static const Options& Defaults() {
+      static Options defaults;
+      return defaults;
+    }
+  };
+
+  // Constructor. Does not take ownership of any parameter passed in.
+  ProtoStreamObjectWriter(TypeResolver* type_resolver,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener,
+                          const ProtoStreamObjectWriter::Options& options =
+                              ProtoStreamObjectWriter::Options::Defaults());
+  ~ProtoStreamObjectWriter() override;
+
+  // ObjectWriter methods.
+  ProtoStreamObjectWriter* StartObject(StringPiece name) override;
+  ProtoStreamObjectWriter* EndObject() override;
+  ProtoStreamObjectWriter* StartList(StringPiece name) override;
+  ProtoStreamObjectWriter* EndList() override;
+
+  // Renders a DataPiece 'value' into a field whose wire type is determined
+  // from the given field 'name'.
+  ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
+                                           const DataPiece& data) override;
+
+ protected:
+  // Function that renders a well known type with modified behavior.
+  typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
+                                       const DataPiece&);
+
+  // Handles writing Anys out using nested object writers and the like.
+  class PROTOBUF_EXPORT AnyWriter {
+   public:
+    explicit AnyWriter(ProtoStreamObjectWriter* parent);
+    ~AnyWriter();
+
+    // Passes a StartObject call through to the Any writer.
+    void StartObject(StringPiece name);
+
+    // Passes an EndObject call through to the Any. Returns true if the any
+    // handled the EndObject call, false if the Any is now all done and is no
+    // longer needed.
+    bool EndObject();
+
+    // Passes a StartList call through to the Any writer.
+    void StartList(StringPiece name);
+
+    // Passes an EndList call through to the Any writer.
+    void EndList();
+
+    // Renders a data piece on the any.
+    void RenderDataPiece(StringPiece name, const DataPiece& value);
+
+   private:
+    // Before the "@type" field is encountered, we store all incoming data
+    // into this Event struct and replay them after we get the "@type" field.
+    class PROTOBUF_EXPORT Event {
+     public:
+      enum Type {
+        START_OBJECT = 0,
+        END_OBJECT = 1,
+        START_LIST = 2,
+        END_LIST = 3,
+        RENDER_DATA_PIECE = 4,
+      };
+
+      // Constructor for END_OBJECT and END_LIST events.
+      explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {}
+
+      // Constructor for START_OBJECT and START_LIST events.
+      explicit Event(Type type, StringPiece name)
+          : type_(type), name_(name), value_(DataPiece::NullData()) {}
+
+      // Constructor for RENDER_DATA_PIECE events.
+      explicit Event(StringPiece name, const DataPiece& value)
+          : type_(RENDER_DATA_PIECE), name_(name), value_(value) {
+        DeepCopy();
+      }
+
+      Event(const Event& other)
+          : type_(other.type_), name_(other.name_), value_(other.value_) {
+        DeepCopy();
+      }
+
+      Event& operator=(const Event& other) {
+        type_ = other.type_;
+        name_ = other.name_;
+        value_ = other.value_;
+        DeepCopy();
+        return *this;
+      }
+
+      void Replay(AnyWriter* writer) const;
+
+     private:
+      void DeepCopy();
+
+      Type type_;
+      std::string name_;
+      DataPiece value_;
+      std::string value_storage_;
+    };
+
+    // Handles starting up the any once we have a type.
+    void StartAny(const DataPiece& value);
+
+    // Writes the Any out to the parent writer in its serialized form.
+    void WriteAny();
+
+    // The parent of this writer, needed for various bits such as type info and
+    // the listeners.
+    ProtoStreamObjectWriter* parent_;
+
+    // The nested object writer, used to write events.
+    std::unique_ptr<ProtoStreamObjectWriter> ow_;
+
+    // The type_url_ that this Any represents.
+    std::string type_url_;
+
+    // Whether this any is invalid. This allows us to only report an invalid
+    // Any message a single time rather than every time we get a nested field.
+    bool invalid_;
+
+    // The output data and wrapping ByteSink.
+    std::string data_;
+    strings::StringByteSink output_;
+
+    // The depth within the Any, so we can track when we're done.
+    int depth_;
+
+    // True if the type is a well-known type. Well-known types in Any
+    // has a special formatting:
+    // {
+    //   "@type": "type.googleapis.com/google.protobuf.XXX",
+    //   "value": <JSON representation of the type>,
+    // }
+    bool is_well_known_type_;
+    TypeRenderer* well_known_type_render_;
+
+    // Store data before the "@type" field.
+    std::vector<Event> uninterpreted_events_;
+  };
+
+  // Represents an item in a stack of items used to keep state between
+  // ObjectWrier events.
+  class PROTOBUF_EXPORT Item : public BaseElement {
+   public:
+    // Indicates the type of item.
+    enum ItemType {
+      MESSAGE,  // Simple message
+      MAP,      // Proto3 map type
+      ANY,      // Proto3 Any type
+    };
+
+    // Constructor for the root item.
+    Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
+         bool is_placeholder, bool is_list);
+
+    // Constructor for a field of a message.
+    Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
+
+    ~Item() override {}
+
+    // These functions return true if the element type is corresponding to the
+    // type in function name.
+    bool IsMap() { return item_type_ == MAP; }
+    bool IsAny() { return item_type_ == ANY; }
+
+    AnyWriter* any() const { return any_.get(); }
+
+    Item* parent() const override {
+      return static_cast<Item*>(BaseElement::parent());
+    }
+
+    // Inserts map key into hash set if and only if the key did NOT already
+    // exist in hash set.
+    // The hash set (map_keys_) is ONLY used to keep track of map keys.
+    // Return true if insert successfully; returns false if the map key was
+    // already present.
+    bool InsertMapKeyIfNotPresent(StringPiece map_key);
+
+    bool is_placeholder() const { return is_placeholder_; }
+    bool is_list() const { return is_list_; }
+
+   private:
+    // Used for access to variables of the enclosing instance of
+    // ProtoStreamObjectWriter.
+    ProtoStreamObjectWriter* ow_;
+
+    // A writer for Any objects, handles all Any-related nonsense.
+    std::unique_ptr<AnyWriter> any_;
+
+    // The type of this element, see enum for permissible types.
+    ItemType item_type_;
+
+    // Set of map keys already seen for the type_. Used to validate incoming
+    // messages so no map key appears more than once.
+    std::unique_ptr<std::unordered_set<std::string> > map_keys_;
+
+    // Conveys whether this Item is a placeholder or not. Placeholder items are
+    // pushed to stack to account for special types.
+    bool is_placeholder_;
+
+    // Conveys whether this Item is a list or not. This is used to send
+    // StartList or EndList calls to underlying ObjectWriter.
+    bool is_list_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
+  };
+
+  ProtoStreamObjectWriter(const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener);
+
+  ProtoStreamObjectWriter(const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener,
+                          const ProtoStreamObjectWriter::Options& options);
+
+  // Returns true if the field is a map.
+  inline bool IsMap(const google::protobuf::Field& field);
+
+  // Returns true if the field is an any.
+  inline bool IsAny(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.Struct.
+  inline bool IsStruct(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.Value.
+  inline bool IsStructValue(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.ListValue.
+  inline bool IsStructListValue(const google::protobuf::Field& field);
+
+  // Renders google.protobuf.Value in struct.proto. It picks the right oneof
+  // type based on value's type.
+  static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
+                                        const DataPiece& data);
+
+  // Renders google.protobuf.Timestamp value.
+  static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
+                                      const DataPiece& data);
+
+  // Renders google.protobuf.FieldMask value.
+  static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
+                                      const DataPiece& data);
+
+  // Renders google.protobuf.Duration value.
+  static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
+                                     const DataPiece& data);
+
+  // Renders wrapper message types for primitive types in
+  // google/protobuf/wrappers.proto.
+  static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
+                                        const DataPiece& data);
+
+  static void InitRendererMap();
+  static void DeleteRendererMap();
+  static TypeRenderer* FindTypeRenderer(const std::string& type_url);
+
+  // Returns true if the map key for type_ is not duplicated key.
+  // If map key is duplicated key, this function returns false.
+  // Note that caller should make sure that the current proto element (current_)
+  // is of element type MAP or STRUCT_MAP.
+  // It also calls the appropriate error callback and unnormalzied_name is used
+  // for error string.
+  bool ValidMapKey(StringPiece unnormalized_name);
+
+  // Pushes an item on to the stack. Also calls either StartObject or StartList
+  // on the underlying ObjectWriter depending on whether is_list is false or
+  // not.
+  // is_placeholder conveys whether the item is a placeholder item or not.
+  // Placeholder items are pushed when adding auxiliary types' StartObject or
+  // StartList calls.
+  void Push(StringPiece name, Item::ItemType item_type,
+            bool is_placeholder, bool is_list);
+
+
+  // Pops items from the stack. All placeholder items are popped until a
+  // non-placeholder item is found.
+  void Pop();
+
+  // Pops one element from the stack. Calls EndObject() or EndList() on the
+  // underlying ObjectWriter depending on the value of is_list_.
+  void PopOneElement();
+
+ private:
+  // Helper functions to create the map and find functions responsible for
+  // rendering well known types, keyed by type URL.
+  static std::unordered_map<std::string, TypeRenderer>* renderers_;
+
+  // Variables for describing the structure of the input tree:
+  // master_type_: descriptor for the whole protobuf message.
+  const google::protobuf::Type& master_type_;
+
+  // The current element, variable for internal state processing.
+  std::unique_ptr<Item> current_;
+
+  // Reference to the options that control this class's behavior.
+  const ProtoStreamObjectWriter::Options options_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/structured_objectwriter.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/structured_objectwriter.h
new file mode 100644
index 0000000..f6f7c89
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/structured_objectwriter.h
@@ -0,0 +1,121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
+
+#include <memory>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/object_writer.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An StructuredObjectWriter is an ObjectWriter for writing
+// tree-structured data in a stream of events representing objects
+// and collections. Implementation of this interface can be used to
+// write an object stream to an in-memory structure, protobufs,
+// JSON, XML, or any other output format desired. The ObjectSource
+// interface is typically used as the source of an object stream.
+//
+// See JsonObjectWriter for a sample implementation of
+// StructuredObjectWriter and its use.
+//
+// Derived classes could be thread-unsafe.
+class PROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter {
+ public:
+  ~StructuredObjectWriter() override {}
+
+ protected:
+  // A base element class for subclasses to extend, makes tracking state easier.
+  //
+  // StructuredObjectWriter behaves as a visitor. BaseElement represents a node
+  // in the input tree. Implementation of StructuredObjectWriter should also
+  // extend BaseElement to keep track of the location in the input tree.
+  class PROTOBUF_EXPORT BaseElement {
+   public:
+    // Takes ownership of the parent Element.
+    explicit BaseElement(BaseElement* parent)
+        : parent_(parent),
+          level_(parent == nullptr ? 0 : parent->level() + 1) {}
+    virtual ~BaseElement() {}
+
+    // Releases ownership of the parent and returns a pointer to it.
+    template <typename ElementType>
+    ElementType* pop() {
+      return down_cast<ElementType*>(parent_.release());
+    }
+
+    // Returns true if this element is the root.
+    bool is_root() const { return parent_ == nullptr; }
+
+    // Returns the number of hops from this element to the root element.
+    int level() const { return level_; }
+
+   protected:
+    // Returns pointer to parent element without releasing ownership.
+    virtual BaseElement* parent() const { return parent_.get(); }
+
+   private:
+    // Pointer to the parent Element.
+    std::unique_ptr<BaseElement> parent_;
+
+    // Number of hops to the root Element.
+    // The root Element has nullptr parent_ and a level_ of 0.
+    const int level_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(BaseElement);
+  };
+
+  StructuredObjectWriter() {}
+
+  // Returns the current element. Used for indentation and name overrides.
+  virtual BaseElement* element() = 0;
+
+ private:
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StructuredObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/type_info.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/type_info.h
new file mode 100644
index 0000000..257df5b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/type_info.h
@@ -0,0 +1,97 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+// Internal helper class for type resolving. Note that this class is not
+// thread-safe and should only be accessed in one thread.
+class PROTOBUF_EXPORT TypeInfo {
+ public:
+  TypeInfo() {}
+  virtual ~TypeInfo() {}
+
+  // Resolves a type url into a Type. If the type url is invalid, returns
+  // INVALID_ARGUMENT error status. If the type url is valid but the
+  // corresponding type cannot be found, returns a NOT_FOUND error status.
+  //
+  // This TypeInfo class retains the ownership of the returned pointer.
+  virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
+      StringPiece type_url) const = 0;
+
+  // Resolves a type url into a Type. Like ResolveTypeUrl() but returns
+  // NULL if the type url is invalid or the type cannot be found.
+  //
+  // This TypeInfo class retains the ownership of the returned pointer.
+  virtual const google::protobuf::Type* GetTypeByTypeUrl(
+      StringPiece type_url) const = 0;
+
+  // Resolves a type url for an enum. Returns NULL if the type url is
+  // invalid or the type cannot be found.
+  //
+  // This TypeInfo class retains the ownership of the returned pointer.
+  virtual const google::protobuf::Enum* GetEnumByTypeUrl(
+      StringPiece type_url) const = 0;
+
+  // Looks up a field in the specified type given a CamelCase name.
+  virtual const google::protobuf::Field* FindField(
+      const google::protobuf::Type* type,
+      StringPiece camel_case_name) const = 0;
+
+  // Creates a TypeInfo object that looks up type information from a
+  // TypeResolver. Caller takes ownership of the returned pointer.
+  static TypeInfo* NewTypeInfo(TypeResolver* type_resolver);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeInfo);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/utility.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/utility.h
new file mode 100644
index 0000000..79d6779
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/internal/utility.h
@@ -0,0 +1,204 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// Size of "type.googleapis.com"
+static const int64_t kTypeUrlSize = 19;
+
+// Finds the tech option identified by option_name. Parses the boolean value and
+// returns it.
+// When the option with the given name is not found, default_value is returned.
+PROTOBUF_EXPORT bool GetBoolOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, bool default_value);
+
+// Returns int64 option value. If the option isn't found, returns the
+// default_value.
+PROTOBUF_EXPORT int64_t GetInt64OptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, int64_t default_value);
+
+// Returns double option value. If the option isn't found, returns the
+// default_value.
+PROTOBUF_EXPORT double GetDoubleOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, double default_value);
+
+// Returns string option value. If the option isn't found, returns the
+// default_value.
+PROTOBUF_EXPORT std::string GetStringOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, StringPiece default_value);
+
+// Returns a boolean value contained in Any type.
+// TODO(skarvaje): Make these utilities dealing with Any types more generic,
+// add more error checking and move to a more public/shareable location so
+// others can use.
+PROTOBUF_EXPORT bool GetBoolFromAny(const google::protobuf::Any& any);
+
+// Returns int64 value contained in Any type.
+PROTOBUF_EXPORT int64_t GetInt64FromAny(const google::protobuf::Any& any);
+
+// Returns double value contained in Any type.
+PROTOBUF_EXPORT double GetDoubleFromAny(const google::protobuf::Any& any);
+
+// Returns string value contained in Any type.
+PROTOBUF_EXPORT std::string GetStringFromAny(const google::protobuf::Any& any);
+
+// Returns the type string without the url prefix. e.g.: If the passed type is
+// 'type.googleapis.com/tech.type.Bool', the returned value is 'tech.type.Bool'.
+PROTOBUF_EXPORT const StringPiece GetTypeWithoutUrl(
+    StringPiece type_url);
+
+// Returns the simple_type with the base type url (kTypeServiceBaseUrl)
+// prefixed.
+//
+// E.g:
+// GetFullTypeWithUrl("google.protobuf.Timestamp") returns the string
+// "type.googleapis.com/google.protobuf.Timestamp".
+PROTOBUF_EXPORT const std::string GetFullTypeWithUrl(
+    StringPiece simple_type);
+
+// Finds and returns option identified by name and option_name within the
+// provided map. Returns nullptr if none found.
+const google::protobuf::Option* FindOptionOrNull(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name);
+
+// Finds and returns the field identified by field_name in the passed tech Type
+// object. Returns nullptr if none found.
+const google::protobuf::Field* FindFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece field_name);
+
+// Similar to FindFieldInTypeOrNull, but this looks up fields with given
+// json_name.
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name);
+
+// Similar to FindFieldInTypeOrNull, but this looks up fields by number.
+const google::protobuf::Field* FindFieldInTypeByNumberOrNull(
+    const google::protobuf::Type* type, int32_t number);
+
+// Finds and returns the EnumValue identified by enum_name in the passed tech
+// Enum object. Returns nullptr if none found.
+const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name);
+
+// Finds and returns the EnumValue identified by value in the passed tech
+// Enum object. Returns nullptr if none found.
+const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
+    const google::protobuf::Enum* enum_type, int32_t value);
+
+// Finds and returns the EnumValue identified by enum_name without underscore in
+// the passed tech Enum object. Returns nullptr if none found.
+// For Ex. if enum_name is ACTIONANDADVENTURE it can get accepted if
+// EnumValue's name is action_and_adventure or ACTION_AND_ADVENTURE.
+const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name);
+
+// Converts input to camel-case and returns it.
+PROTOBUF_EXPORT std::string ToCamelCase(const StringPiece input);
+
+// Converts enum name string to camel-case and returns it.
+std::string EnumValueNameToLowerCamelCase(const StringPiece input);
+
+// Converts input to snake_case and returns it.
+PROTOBUF_EXPORT std::string ToSnakeCase(StringPiece input);
+
+// Returns true if type_name represents a well-known type.
+PROTOBUF_EXPORT bool IsWellKnownType(const std::string& type_name);
+
+// Returns true if 'bool_string' represents a valid boolean value. Only "true",
+// "false", "0" and "1" are allowed.
+PROTOBUF_EXPORT bool IsValidBoolString(StringPiece bool_string);
+
+// Returns true if "field" is a protobuf map field based on its type.
+PROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field,
+                           const google::protobuf::Type& type);
+
+// Returns true if the given type has special MessageSet wire format.
+bool IsMessageSetWireFormat(const google::protobuf::Type& type);
+
+// Infinity/NaN-aware conversion to string.
+PROTOBUF_EXPORT std::string DoubleAsString(double value);
+PROTOBUF_EXPORT std::string FloatAsString(float value);
+
+// Convert from int32, int64, uint32, uint64, double or float to string.
+template <typename T>
+std::string ValueAsString(T value) {
+  return StrCat(value);
+}
+
+template <>
+inline std::string ValueAsString(float value) {
+  return FloatAsString(value);
+}
+
+template <>
+inline std::string ValueAsString(double value) {
+  return DoubleAsString(value);
+}
+
+// Converts a string to float. Unlike safe_strtof, conversion will fail if the
+// value fits into double but not float (e.g., DBL_MAX).
+PROTOBUF_EXPORT bool SafeStrToFloat(StringPiece str, float* value);
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/json_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/json_util.h
new file mode 100644
index 0000000..0f1c4d8b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/json_util.h
@@ -0,0 +1,204 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions to convert between protobuf binary format and proto3 JSON
+// format.
+#ifndef GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
+
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/util/type_resolver.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+}  // namespace io
+namespace util {
+
+struct JsonParseOptions {
+  // Whether to ignore unknown JSON fields during parsing
+  bool ignore_unknown_fields;
+
+  // If true, when a lowercase enum value fails to parse, try convert it to
+  // UPPER_CASE and see if it matches a valid enum.
+  // WARNING: This option exists only to preserve legacy behavior. Avoid using
+  // this option. If your enum needs to support different casing, consider using
+  // allow_alias instead.
+  bool case_insensitive_enum_parsing;
+
+  JsonParseOptions()
+      : ignore_unknown_fields(false), case_insensitive_enum_parsing(false) {}
+};
+
+struct JsonPrintOptions {
+  // Whether to add spaces, line breaks and indentation to make the JSON output
+  // easy to read.
+  bool add_whitespace;
+  // Whether to always print primitive fields. By default proto3 primitive
+  // fields with default values will be omitted in JSON output. For example, an
+  // int32 field set to 0 will be omitted. Set this flag to true will override
+  // the default behavior and print primitive fields regardless of their values.
+  bool always_print_primitive_fields;
+  // Whether to always print enums as ints. By default they are rendered as
+  // strings.
+  bool always_print_enums_as_ints;
+  // Whether to preserve proto field names
+  bool preserve_proto_field_names;
+
+  JsonPrintOptions()
+      : add_whitespace(false),
+        always_print_primitive_fields(false),
+        always_print_enums_as_ints(false),
+        preserve_proto_field_names(false) {}
+};
+
+// DEPRECATED. Use JsonPrintOptions instead.
+typedef JsonPrintOptions JsonOptions;
+
+// Converts from protobuf message to JSON and appends it to |output|. This is a
+// simple wrapper of BinaryToJsonString(). It will use the DescriptorPool of the
+// passed-in message to resolve Any types.
+PROTOBUF_EXPORT util::Status MessageToJsonString(const Message& message,
+                                                 std::string* output,
+                                                 const JsonOptions& options);
+
+inline util::Status MessageToJsonString(const Message& message,
+                                        std::string* output) {
+  return MessageToJsonString(message, output, JsonOptions());
+}
+
+// Converts from JSON to protobuf message. This is a simple wrapper of
+// JsonStringToBinary(). It will use the DescriptorPool of the passed-in
+// message to resolve Any types.
+PROTOBUF_EXPORT util::Status JsonStringToMessage(
+    StringPiece input, Message* message, const JsonParseOptions& options);
+
+inline util::Status JsonStringToMessage(StringPiece input,
+                                        Message* message) {
+  return JsonStringToMessage(input, message, JsonParseOptions());
+}
+
+// Converts protobuf binary data to JSON.
+// The conversion will fail if:
+//   1. TypeResolver fails to resolve a type.
+//   2. input is not valid protobuf wire format, or conflicts with the type
+//      information returned by TypeResolver.
+// Note that unknown fields will be discarded silently.
+PROTOBUF_EXPORT util::Status BinaryToJsonStream(
+    TypeResolver* resolver, const std::string& type_url,
+    io::ZeroCopyInputStream* binary_input,
+    io::ZeroCopyOutputStream* json_output, const JsonPrintOptions& options);
+
+inline util::Status BinaryToJsonStream(TypeResolver* resolver,
+                                       const std::string& type_url,
+                                       io::ZeroCopyInputStream* binary_input,
+                                       io::ZeroCopyOutputStream* json_output) {
+  return BinaryToJsonStream(resolver, type_url, binary_input, json_output,
+                            JsonPrintOptions());
+}
+
+PROTOBUF_EXPORT util::Status BinaryToJsonString(
+    TypeResolver* resolver, const std::string& type_url,
+    const std::string& binary_input, std::string* json_output,
+    const JsonPrintOptions& options);
+
+inline util::Status BinaryToJsonString(TypeResolver* resolver,
+                                       const std::string& type_url,
+                                       const std::string& binary_input,
+                                       std::string* json_output) {
+  return BinaryToJsonString(resolver, type_url, binary_input, json_output,
+                            JsonPrintOptions());
+}
+
+// Converts JSON data to protobuf binary format.
+// The conversion will fail if:
+//   1. TypeResolver fails to resolve a type.
+//   2. input is not valid JSON format, or conflicts with the type
+//      information returned by TypeResolver.
+PROTOBUF_EXPORT util::Status JsonToBinaryStream(
+    TypeResolver* resolver, const std::string& type_url,
+    io::ZeroCopyInputStream* json_input,
+    io::ZeroCopyOutputStream* binary_output, const JsonParseOptions& options);
+
+inline util::Status JsonToBinaryStream(
+    TypeResolver* resolver, const std::string& type_url,
+    io::ZeroCopyInputStream* json_input,
+    io::ZeroCopyOutputStream* binary_output) {
+  return JsonToBinaryStream(resolver, type_url, json_input, binary_output,
+                            JsonParseOptions());
+}
+
+PROTOBUF_EXPORT util::Status JsonToBinaryString(
+    TypeResolver* resolver, const std::string& type_url,
+    StringPiece json_input, std::string* binary_output,
+    const JsonParseOptions& options);
+
+inline util::Status JsonToBinaryString(TypeResolver* resolver,
+                                       const std::string& type_url,
+                                       StringPiece json_input,
+                                       std::string* binary_output) {
+  return JsonToBinaryString(resolver, type_url, json_input, binary_output,
+                            JsonParseOptions());
+}
+
+namespace internal {
+// Internal helper class. Put in the header so we can write unit-tests for it.
+class PROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
+ public:
+  explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
+      : stream_(stream), buffer_(nullptr), buffer_size_(0) {}
+  ~ZeroCopyStreamByteSink() override;
+
+  void Append(const char* bytes, size_t len) override;
+
+ private:
+  io::ZeroCopyOutputStream* stream_;
+  void* buffer_;
+  int buffer_size_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyStreamByteSink);
+};
+}  // namespace internal
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/message_differencer.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/message_differencer.h
new file mode 100644
index 0000000..f63cd54
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/message_differencer.h
@@ -0,0 +1,980 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file defines static methods and classes for comparing Protocol
+// Messages.
+//
+// Aug. 2008: Added Unknown Fields Comparison for messages.
+// Aug. 2009: Added different options to compare repeated fields.
+// Apr. 2010: Moved field comparison to FieldComparator
+// Sep. 2020: Added option to output map keys in path
+
+#ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+#define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/descriptor.h>  // FieldDescriptor
+#include <google/protobuf/message.h>     // Message
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/util/field_comparator.h>
+
+// Always include as last one, otherwise it can break compilation
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class DynamicMessageFactory;
+class FieldDescriptor;
+
+namespace io {
+class ZeroCopyOutputStream;
+class Printer;
+}  // namespace io
+
+namespace util {
+
+class DefaultFieldComparator;
+class FieldContext;  // declared below MessageDifferencer
+
+// Defines a collection of field descriptors.
+// In case of internal google codebase we are using absl::FixedArray instead
+// of vector. It significantly speeds up proto comparison (by ~30%) by
+// reducing the number of malloc/free operations
+typedef std::vector<const FieldDescriptor*> FieldDescriptorArray;
+
+// A basic differencer that can be used to determine
+// the differences between two specified Protocol Messages. If any differences
+// are found, the Compare method will return false, and any differencer reporter
+// specified via ReportDifferencesTo will have its reporting methods called (see
+// below for implementation of the report). Based off of the original
+// ProtocolDifferencer implementation in //net/proto/protocol-differencer.h
+// (Thanks Todd!).
+//
+// MessageDifferencer REQUIRES that compared messages be the same type, defined
+// as messages that share the same descriptor.  If not, the behavior of this
+// class is undefined.
+//
+// People disagree on what MessageDifferencer should do when asked to compare
+// messages with different descriptors.  Some people think it should always
+// return false.  Others expect it to try to look for similar fields and
+// compare them anyway -- especially if the descriptors happen to be identical.
+// If we chose either of these behaviors, some set of people would find it
+// surprising, and could end up writing code expecting the other behavior
+// without realizing their error.  Therefore, we forbid that usage.
+//
+// This class is implemented based on the proto2 reflection. The performance
+// should be good enough for normal usages. However, for places where the
+// performance is extremely sensitive, there are several alternatives:
+// - Comparing serialized string
+// Downside: false negatives (there are messages that are the same but their
+// serialized strings are different).
+// - Equals code generator by compiler plugin (net/proto2/contrib/equals_plugin)
+// Downside: more generated code; maintenance overhead for the additional rule
+// (must be in sync with the original proto_library).
+//
+// Note on handling of google.protobuf.Any: MessageDifferencer automatically
+// unpacks Any::value into a Message and compares its individual fields.
+// Messages encoded in a repeated Any cannot be compared using TreatAsMap.
+//
+// Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to
+// guard it with a lock to use the same MessageDifferencer instance from
+// multiple threads. Note that it's fine to call static comparison methods
+// (like MessageDifferencer::Equals) concurrently, but it's not recommended for
+// performance critical code as it leads to extra allocations.
+class PROTOBUF_EXPORT MessageDifferencer {
+ public:
+  // Determines whether the supplied messages are equal. Equality is defined as
+  // all fields within the two messages being set to the same value. Primitive
+  // fields and strings are compared by value while embedded messages/groups
+  // are compared as if via a recursive call. Use Compare() with IgnoreField()
+  // if some fields should be ignored in the comparison. Use Compare() with
+  // TreatAsSet() if there are repeated fields where ordering does not matter.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool Equals(const Message& message1, const Message& message2);
+
+  // Determines whether the supplied messages are equivalent. Equivalency is
+  // defined as all fields within the two messages having the same value. This
+  // differs from the Equals method above in that fields with default values
+  // are considered set to said value automatically. For details on how default
+  // values are defined for each field type, see:
+  // https://developers.google.com/protocol-buffers/docs/proto?csw=1#optional.
+  // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare()
+  // if some fields should be ignored in the comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool Equivalent(const Message& message1, const Message& message2);
+
+  // Determines whether the supplied messages are approximately equal.
+  // Approximate equality is defined as all fields within the two messages
+  // being approximately equal.  Primitive (non-float) fields and strings are
+  // compared by value, floats are compared using MathUtil::AlmostEquals() and
+  // embedded messages/groups are compared as if via a recursive call. Use
+  // IgnoreField() and Compare() if some fields should be ignored in the
+  // comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool ApproximatelyEquals(const Message& message1,
+                                  const Message& message2);
+
+  // Determines whether the supplied messages are approximately equivalent.
+  // Approximate equivalency is defined as all fields within the two messages
+  // being approximately equivalent. As in
+  // MessageDifferencer::ApproximatelyEquals, primitive (non-float) fields and
+  // strings are compared by value, floats are compared using
+  // MathUtil::AlmostEquals() and embedded messages/groups are compared as if
+  // via a recursive call. However, fields with default values are considered
+  // set to said value, as per MessageDiffencer::Equivalent. Use IgnoreField()
+  // and Compare() if some fields should be ignored in the comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool ApproximatelyEquivalent(const Message& message1,
+                                      const Message& message2);
+
+  // Identifies an individual field in a message instance.  Used for field_path,
+  // below.
+  struct SpecificField {
+    // For known fields, "field" is filled in and "unknown_field_number" is -1.
+    // For unknown fields, "field" is NULL, "unknown_field_number" is the field
+    // number, and "unknown_field_type" is its type.
+    const FieldDescriptor* field = nullptr;
+    int unknown_field_number = -1;
+    UnknownField::Type unknown_field_type = UnknownField::Type::TYPE_VARINT;
+
+    // If this a repeated field, "index" is the index within it.  For unknown
+    // fields, this is the index of the field among all unknown fields of the
+    // same field number and type.
+    int index = -1;
+
+    // If "field" is a repeated field which is being treated as a map or
+    // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates
+    // the index the position to which the element has moved.  If the element
+    // has not moved, "new_index" will have the same value as "index".
+    int new_index = -1;
+
+    // If "field" is a map field, point to the map entry.
+    const Message* map_entry1 = nullptr;
+    const Message* map_entry2 = nullptr;
+
+    // For unknown fields, these are the pointers to the UnknownFieldSet
+    // containing the unknown fields. In certain cases (e.g. proto1's
+    // MessageSet, or nested groups of unknown fields), these may differ from
+    // the messages' internal UnknownFieldSets.
+    const UnknownFieldSet* unknown_field_set1 = nullptr;
+    const UnknownFieldSet* unknown_field_set2 = nullptr;
+
+    // For unknown fields, these are the index of the field within the
+    // UnknownFieldSets. One or the other will be -1 when
+    // reporting an addition or deletion.
+    int unknown_field_index1 = -1;
+    int unknown_field_index2 = -1;
+  };
+
+  // Abstract base class from which all MessageDifferencer
+  // reporters derive. The five Report* methods below will be called when
+  // a field has been added, deleted, modified, moved, or matched. The third
+  // argument is a vector of FieldDescriptor pointers which describes the chain
+  // of fields that was taken to find the current field. For example, for a
+  // field found in an embedded message, the vector will contain two
+  // FieldDescriptors. The first will be the field of the embedded message
+  // itself and the second will be the actual field in the embedded message
+  // that was added/deleted/modified.
+  // Fields will be reported in PostTraversalOrder.
+  // For example, given following proto, if both baz and mooo are changed.
+  // foo {
+  //   bar {
+  //     baz: 1
+  //     mooo: 2
+  //   }
+  // }
+  // ReportModified will be invoked with following order:
+  // 1. foo.bar.baz or foo.bar.mooo
+  // 2. foo.bar.mooo or foo.bar.baz
+  // 2. foo.bar
+  // 3. foo
+  class PROTOBUF_EXPORT Reporter {
+   public:
+    Reporter();
+    virtual ~Reporter();
+
+    // Reports that a field has been added into Message2.
+    virtual void ReportAdded(const Message& message1, const Message& message2,
+                             const std::vector<SpecificField>& field_path) = 0;
+
+    // Reports that a field has been deleted from Message1.
+    virtual void ReportDeleted(
+        const Message& message1, const Message& message2,
+        const std::vector<SpecificField>& field_path) = 0;
+
+    // Reports that the value of a field has been modified.
+    virtual void ReportModified(
+        const Message& message1, const Message& message2,
+        const std::vector<SpecificField>& field_path) = 0;
+
+    // Reports that a repeated field has been moved to another location.  This
+    // only applies when using TreatAsSet or TreatAsMap()  -- see below. Also
+    // note that for any given field, ReportModified and ReportMoved are
+    // mutually exclusive. If a field has been both moved and modified, then
+    // only ReportModified will be called.
+    virtual void ReportMoved(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const std::vector<SpecificField>& /* field_path */) {}
+
+    // Reports that two fields match. Useful for doing side-by-side diffs.
+    // This function is mutually exclusive with ReportModified and ReportMoved.
+    // Note that you must call set_report_matches(true) before calling Compare
+    // to make use of this function.
+    virtual void ReportMatched(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const std::vector<SpecificField>& /* field_path */) {}
+
+    // Reports that two fields would have been compared, but the
+    // comparison has been skipped because the field was marked as
+    // 'ignored' using IgnoreField().  This function is mutually
+    // exclusive with all the other Report() functions.
+    //
+    // The contract of ReportIgnored is slightly different than the
+    // other Report() functions, in that |field_path.back().index| is
+    // always equal to -1, even if the last field is repeated. This is
+    // because while the other Report() functions indicate where in a
+    // repeated field the action (Addition, Deletion, etc...)
+    // happened, when a repeated field is 'ignored', the differencer
+    // simply calls ReportIgnored on the repeated field as a whole and
+    // moves on without looking at its individual elements.
+    //
+    // Furthermore, ReportIgnored() does not indicate whether the
+    // fields were in fact equal or not, as Compare() does not inspect
+    // these fields at all. It is up to the Reporter to decide whether
+    // the fields are equal or not (perhaps with a second call to
+    // Compare()), if it cares.
+    virtual void ReportIgnored(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const std::vector<SpecificField>& /* field_path */) {}
+
+    // Report that an unknown field is ignored. (see comment above).
+    // Note this is a different function since the last SpecificField in field
+    // path has a null field.  This could break existing Reporter.
+    virtual void ReportUnknownFieldIgnored(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const std::vector<SpecificField>& /* field_path */) {}
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter);
+  };
+
+  // MapKeyComparator is used to determine if two elements have the same key
+  // when comparing elements of a repeated field as a map.
+  class PROTOBUF_EXPORT MapKeyComparator {
+   public:
+    MapKeyComparator();
+    virtual ~MapKeyComparator();
+
+    virtual bool IsMatch(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const std::vector<SpecificField>& /* parent_fields */) const {
+      GOOGLE_CHECK(false) << "IsMatch() is not implemented.";
+      return false;
+    }
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapKeyComparator);
+  };
+
+  // Abstract base class from which all IgnoreCriteria derive.
+  // By adding IgnoreCriteria more complex ignore logic can be implemented.
+  // IgnoreCriteria are registered with AddIgnoreCriteria. For each compared
+  // field IsIgnored is called on each added IgnoreCriteria until one returns
+  // true or all return false.
+  // IsIgnored is called for fields where at least one side has a value.
+  class PROTOBUF_EXPORT IgnoreCriteria {
+   public:
+    IgnoreCriteria();
+    virtual ~IgnoreCriteria();
+
+    // Returns true if the field should be ignored.
+    virtual bool IsIgnored(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const FieldDescriptor* /* field */,
+        const std::vector<SpecificField>& /* parent_fields */) = 0;
+
+    // Returns true if the unknown field should be ignored.
+    // Note: This will be called for unknown fields as well in which case
+    //       field.field will be null.
+    virtual bool IsUnknownFieldIgnored(
+        const Message& /* message1 */, const Message& /* message2 */,
+        const SpecificField& /* field */,
+        const std::vector<SpecificField>& /* parent_fields */) {
+      return false;
+    }
+  };
+
+  // To add a Reporter, construct default here, then use ReportDifferencesTo or
+  // ReportDifferencesToString.
+  explicit MessageDifferencer();
+
+  ~MessageDifferencer();
+
+  enum MessageFieldComparison {
+    EQUAL,       // Fields must be present in both messages
+                 // for the messages to be considered the same.
+    EQUIVALENT,  // Fields with default values are considered set
+                 // for comparison purposes even if not explicitly
+                 // set in the messages themselves.  Unknown fields
+                 // are ignored.
+  };
+
+  enum Scope {
+    FULL,    // All fields of both messages are considered in the comparison.
+    PARTIAL  // Only fields present in the first message are considered; fields
+             // set only in the second message will be skipped during
+             // comparison.
+  };
+
+  // DEPRECATED. Use FieldComparator::FloatComparison instead.
+  enum FloatComparison {
+    EXACT,       // Floats and doubles are compared exactly.
+    APPROXIMATE  // Floats and doubles are compared using the
+                 // MathUtil::AlmostEquals method.
+  };
+
+  enum RepeatedFieldComparison {
+    AS_LIST,  // Repeated fields are compared in order.  Differing values at
+              // the same index are reported using ReportModified().  If the
+              // repeated fields have different numbers of elements, the
+              // unpaired elements are reported using ReportAdded() or
+              // ReportDeleted().
+    AS_SET,   // Treat all the repeated fields as sets.
+              // See TreatAsSet(), as below.
+    AS_SMART_LIST,  // Similar to AS_SET, but preserve the order and find the
+                    // longest matching sequence from the first matching
+                    // element. To use an optimal solution, call
+                    // SetMatchIndicesForSmartListCallback() to pass it in.
+    AS_SMART_SET,   // Similar to AS_SET, but match elements with fewest diffs.
+  };
+
+  // The elements of the given repeated field will be treated as a set for
+  // diffing purposes, so different orderings of the same elements will be
+  // considered equal.  Elements which are present on both sides of the
+  // comparison but which have changed position will be reported with
+  // ReportMoved().  Elements which only exist on one side or the other are
+  // reported with ReportAdded() and ReportDeleted() regardless of their
+  // positions.  ReportModified() is never used for this repeated field.  If
+  // the only differences between the compared messages is that some fields
+  // have been moved, then the comparison returns true.
+  //
+  // Note that despite the name of this method, this is really
+  // comparison as multisets: if one side of the comparison has a duplicate
+  // in the repeated field but the other side doesn't, this will count as
+  // a mismatch.
+  //
+  // If the scope of comparison is set to PARTIAL, then in addition to what's
+  // above, extra values added to repeated fields of the second message will
+  // not cause the comparison to fail.
+  //
+  // Note that set comparison is currently O(k * n^2) (where n is the total
+  // number of elements, and k is the average size of each element). In theory
+  // it could be made O(n * k) with a more complex hashing implementation. Feel
+  // free to contribute one if the current implementation is too slow for you.
+  // If partial matching is also enabled, the time complexity will be O(k * n^2
+  // + n^3) in which n^3 is the time complexity of the maximum matching
+  // algorithm.
+  //
+  // REQUIRES: field->is_repeated() and field not registered with TreatAsMap*
+  void TreatAsSet(const FieldDescriptor* field);
+  void TreatAsSmartSet(const FieldDescriptor* field);
+
+  // The elements of the given repeated field will be treated as a list for
+  // diffing purposes, so different orderings of the same elements will NOT be
+  // considered equal.
+  //
+  // REQUIRES: field->is_repeated() and field not registered with TreatAsMap*
+  void TreatAsList(const FieldDescriptor* field);
+  // Note that the complexity is similar to treating as SET.
+  void TreatAsSmartList(const FieldDescriptor* field);
+
+  // The elements of the given repeated field will be treated as a map for
+  // diffing purposes, with |key| being the map key.  Thus, elements with the
+  // same key will be compared even if they do not appear at the same index.
+  // Differences are reported similarly to TreatAsSet(), except that
+  // ReportModified() is used to report elements with the same key but
+  // different values.  Note that if an element is both moved and modified,
+  // only ReportModified() will be called.  As with TreatAsSet, if the only
+  // differences between the compared messages is that some fields have been
+  // moved, then the comparison returns true. See TreatAsSet for notes on
+  // performance.
+  //
+  // REQUIRES:  field->is_repeated()
+  // REQUIRES:  field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+  // REQUIRES:  key->containing_type() == field->message_type()
+  void TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key);
+  // Same as TreatAsMap except that this method will use multiple fields as
+  // the key in comparison. All specified fields in 'key_fields' should be
+  // present in the compared elements. Two elements will be treated as having
+  // the same key iff they have the same value for every specified field. There
+  // are two steps in the comparison process. The first one is key matching.
+  // Every element from one message will be compared to every element from
+  // the other message. Only fields in 'key_fields' are compared in this step
+  // to decide if two elements have the same key. The second step is value
+  // comparison. Those pairs of elements with the same key (with equal value
+  // for every field in 'key_fields') will be compared in this step.
+  // Time complexity of the first step is O(s * m * n ^ 2) where s is the
+  // average size of the fields specified in 'key_fields', m is the number of
+  // fields in 'key_fields' and n is the number of elements. If partial
+  // matching is enabled, an extra O(n^3) will be incured by the maximum
+  // matching algorithm. The second step is O(k * n) where k is the average
+  // size of each element.
+  void TreatAsMapWithMultipleFieldsAsKey(
+      const FieldDescriptor* field,
+      const std::vector<const FieldDescriptor*>& key_fields);
+  // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field
+  // do not necessarily need to be a direct subfield. Each element in
+  // key_field_paths indicate a path from the message being compared, listing
+  // successive subfield to reach the key field.
+  //
+  // REQUIRES:
+  //   for key_field_path in key_field_paths:
+  //     key_field_path[0]->containing_type() == field->message_type()
+  //     for i in [0, key_field_path.size() - 1):
+  //       key_field_path[i+1]->containing_type() ==
+  //           key_field_path[i]->message_type()
+  //       key_field_path[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+  //       !key_field_path[i]->is_repeated()
+  void TreatAsMapWithMultipleFieldPathsAsKey(
+      const FieldDescriptor* field,
+      const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths);
+
+  // Uses a custom MapKeyComparator to determine if two elements have the same
+  // key when comparing a repeated field as a map.
+  // The caller is responsible to delete the key_comparator.
+  // This method varies from TreatAsMapWithMultipleFieldsAsKey only in the
+  // first key matching step. Rather than comparing some specified fields, it
+  // will invoke the IsMatch method of the given 'key_comparator' to decide if
+  // two elements have the same key.
+  void TreatAsMapUsingKeyComparator(const FieldDescriptor* field,
+                                    const MapKeyComparator* key_comparator);
+
+  // Initiates and returns a new instance of MultipleFieldsMapKeyComparator.
+  MapKeyComparator* CreateMultipleFieldsMapKeyComparator(
+      const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths);
+
+  // Add a custom ignore criteria that is evaluated in addition to the
+  // ignored fields added with IgnoreField.
+  // Takes ownership of ignore_criteria.
+  void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria);
+
+  // Indicates that any field with the given descriptor should be
+  // ignored for the purposes of comparing two messages. This applies
+  // to fields nested in the message structure as well as top level
+  // ones. When the MessageDifferencer encounters an ignored field,
+  // ReportIgnored is called on the reporter, if one is specified.
+  //
+  // The only place where the field's 'ignored' status is not applied is when
+  // it is being used as a key in a field passed to TreatAsMap or is one of
+  // the fields passed to TreatAsMapWithMultipleFieldsAsKey.
+  // In this case it is compared in key matching but after that it's ignored
+  // in value comparison.
+  void IgnoreField(const FieldDescriptor* field);
+
+  // Sets the field comparator used to determine differences between protocol
+  // buffer fields. By default it's set to a DefaultFieldComparator instance.
+  // MessageDifferencer doesn't take ownership over the passed object.
+  // Note that this method must be called before Compare for the comparator to
+  // be used.
+  void set_field_comparator(FieldComparator* comparator);
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+  void set_field_comparator(DefaultFieldComparator* comparator);
+#endif  // PROTOBUF_FUTURE_BREAKING_CHANGES
+
+  // DEPRECATED. Pass a DefaultFieldComparator instance instead.
+  // Sets the fraction and margin for the float comparison of a given field.
+  // Uses MathUtil::WithinFractionOrMargin to compare the values.
+  // NOTE: this method does nothing if differencer's field comparator has been
+  //       set to a custom object.
+  //
+  // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
+  //           field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
+  // REQUIRES: float_comparison_ == APPROXIMATE
+  void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
+                            double margin);
+
+  // Sets the type of comparison (as defined in the MessageFieldComparison
+  // enumeration above) that is used by this differencer when determining how
+  // to compare fields in messages.
+  void set_message_field_comparison(MessageFieldComparison comparison);
+
+  // Returns the current message field comparison used in this differencer.
+  MessageFieldComparison message_field_comparison() const;
+
+  // Tells the differencer whether or not to report matches. This method must
+  // be called before Compare. The default for a new differencer is false.
+  void set_report_matches(bool report_matches) {
+    report_matches_ = report_matches;
+  }
+
+  // Tells the differencer whether or not to report moves (in a set or map
+  // repeated field). This method must be called before Compare. The default for
+  // a new differencer is true.
+  void set_report_moves(bool report_moves) { report_moves_ = report_moves; }
+
+  // Tells the differencer whether or not to report ignored values. This method
+  // must be called before Compare. The default for a new differencer is true.
+  void set_report_ignores(bool report_ignores) {
+    report_ignores_ = report_ignores;
+  }
+
+  // Sets the scope of the comparison (as defined in the Scope enumeration
+  // above) that is used by this differencer when determining which fields to
+  // compare between the messages.
+  void set_scope(Scope scope);
+
+  // Returns the current scope used by this differencer.
+  Scope scope() const;
+
+  // DEPRECATED. Pass a DefaultFieldComparator instance instead.
+  // Sets the type of comparison (as defined in the FloatComparison enumeration
+  // above) that is used by this differencer when comparing float (and double)
+  // fields in messages.
+  // NOTE: this method does nothing if differencer's field comparator has been
+  //       set to a custom object.
+  void set_float_comparison(FloatComparison comparison);
+
+  // Sets the type of comparison for repeated field (as defined in the
+  // RepeatedFieldComparison enumeration above) that is used by this
+  // differencer when compare repeated fields in messages.
+  void set_repeated_field_comparison(RepeatedFieldComparison comparison);
+
+  // Returns the current repeated field comparison used by this differencer.
+  RepeatedFieldComparison repeated_field_comparison() const;
+
+  // Compares the two specified messages, returning true if they are the same,
+  // false otherwise. If this method returns false, any changes between the
+  // two messages will be reported if a Reporter was specified via
+  // ReportDifferencesTo (see also ReportDifferencesToString).
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  bool Compare(const Message& message1, const Message& message2);
+
+  // Same as above, except comparing only the list of fields specified by the
+  // two vectors of FieldDescriptors.
+  bool CompareWithFields(
+      const Message& message1, const Message& message2,
+      const std::vector<const FieldDescriptor*>& message1_fields,
+      const std::vector<const FieldDescriptor*>& message2_fields);
+
+  // Automatically creates a reporter that will output the differences
+  // found (if any) to the specified output string pointer. Note that this
+  // method must be called before Compare.
+  void ReportDifferencesToString(std::string* output);
+
+  // Tells the MessageDifferencer to report differences via the specified
+  // reporter. Note that this method must be called before Compare for
+  // the reporter to be used. It is the responsibility of the caller to delete
+  // this object.
+  // If the provided pointer equals NULL, the MessageDifferencer stops reporting
+  // differences to any previously set reporters or output strings.
+  void ReportDifferencesTo(Reporter* reporter);
+
+ private:
+  // Class for processing Any deserialization.  This logic is used by both the
+  // MessageDifferencer and StreamReporter classes.
+  class UnpackAnyField {
+   private:
+    std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_;
+
+   public:
+    UnpackAnyField() = default;
+    ~UnpackAnyField() = default;
+    // If "any" is of type google.protobuf.Any, extract its payload using
+    // DynamicMessageFactory and store in "data".
+    bool UnpackAny(const Message& any, std::unique_ptr<Message>* data);
+  };
+
+ public:
+  // An implementation of the MessageDifferencer Reporter that outputs
+  // any differences found in human-readable form to the supplied
+  // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter
+  // *must* be '$'.
+  //
+  // WARNING: this reporter does not necessarily flush its output until it is
+  // destroyed. As a result, it is not safe to assume the output is valid or
+  // complete until after you destroy the reporter. For example, if you use a
+  // StreamReporter to write to a StringOutputStream, the target string may
+  // contain uninitialized data until the reporter is destroyed.
+  class PROTOBUF_EXPORT StreamReporter : public Reporter {
+   public:
+    explicit StreamReporter(io::ZeroCopyOutputStream* output);
+    explicit StreamReporter(io::Printer* printer);  // delimiter '$'
+    ~StreamReporter() override;
+
+    // When set to true, the stream reporter will also output aggregates nodes
+    // (i.e. messages and groups) whose subfields have been modified. When
+    // false, will only report the individual subfields. Defaults to false.
+    void set_report_modified_aggregates(bool report) {
+      report_modified_aggregates_ = report;
+    }
+
+    // The following are implementations of the methods described above.
+
+    void ReportAdded(const Message& message1, const Message& message2,
+                     const std::vector<SpecificField>& field_path) override;
+
+    void ReportDeleted(const Message& message1, const Message& message2,
+                       const std::vector<SpecificField>& field_path) override;
+
+    void ReportModified(const Message& message1, const Message& message2,
+                        const std::vector<SpecificField>& field_path) override;
+
+    void ReportMoved(const Message& message1, const Message& message2,
+                     const std::vector<SpecificField>& field_path) override;
+
+    void ReportMatched(const Message& message1, const Message& message2,
+                       const std::vector<SpecificField>& field_path) override;
+
+    void ReportIgnored(const Message& message1, const Message& message2,
+                       const std::vector<SpecificField>& field_path) override;
+
+    void ReportUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const std::vector<SpecificField>& field_path) override;
+
+    // Messages that are being compared must be provided to StreamReporter prior
+    // to processing
+    void SetMessages(const Message& message1, const Message& message2);
+
+   protected:
+    // Prints the specified path of fields to the buffer.
+    virtual void PrintPath(const std::vector<SpecificField>& field_path,
+                           bool left_side);
+
+    // Prints the value of fields to the buffer.  left_side is true if the
+    // given message is from the left side of the comparison, false if it
+    // was the right.  This is relevant only to decide whether to follow
+    // unknown_field_index1 or unknown_field_index2 when an unknown field
+    // is encountered in field_path.
+    virtual void PrintValue(const Message& message,
+                            const std::vector<SpecificField>& field_path,
+                            bool left_side);
+
+    // Prints the specified path of unknown fields to the buffer.
+    virtual void PrintUnknownFieldValue(const UnknownField* unknown_field);
+
+    // Just print a string
+    void Print(const std::string& str);
+
+   private:
+    // helper function for PrintPath that contains logic for printing maps
+    void PrintMapKey(bool left_side, const SpecificField& specific_field);
+
+    io::Printer* printer_;
+    bool delete_printer_;
+    bool report_modified_aggregates_;
+    const Message* message1_;
+    const Message* message2_;
+    MessageDifferencer::UnpackAnyField unpack_any_field_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StreamReporter);
+  };
+
+ private:
+  friend class SimpleFieldComparator;
+
+  // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator.
+  // Implementation of this class needs to do field value comparison which
+  // relies on some private methods of MessageDifferencer. That's why this
+  // class is declared as a nested class of MessageDifferencer.
+  class MultipleFieldsMapKeyComparator;
+
+  // A MapKeyComparator for use with map_entries.
+  class PROTOBUF_EXPORT MapEntryKeyComparator : public MapKeyComparator {
+   public:
+    explicit MapEntryKeyComparator(MessageDifferencer* message_differencer);
+    bool IsMatch(
+        const Message& message1, const Message& message2,
+        const std::vector<SpecificField>& parent_fields) const override;
+
+   private:
+    MessageDifferencer* message_differencer_;
+  };
+
+  // Returns true if field1's number() is less than field2's.
+  static bool FieldBefore(const FieldDescriptor* field1,
+                          const FieldDescriptor* field2);
+
+  // Retrieve all the set fields, including extensions.
+  FieldDescriptorArray RetrieveFields(const Message& message,
+                                      bool base_message);
+
+  // Combine the two lists of fields into the combined_fields output vector.
+  // All fields present in both lists will always be included in the combined
+  // list.  Fields only present in one of the lists will only appear in the
+  // combined list if the corresponding fields_scope option is set to FULL.
+  FieldDescriptorArray CombineFields(const FieldDescriptorArray& fields1,
+                                     Scope fields1_scope,
+                                     const FieldDescriptorArray& fields2,
+                                     Scope fields2_scope);
+
+  // Internal version of the Compare method which performs the actual
+  // comparison. The parent_fields vector is a vector containing field
+  // descriptors of all fields accessed to get to this comparison operation
+  // (i.e. if the current message is an embedded message, the parent_fields
+  // vector will contain the field that has this embedded message).
+  bool Compare(const Message& message1, const Message& message2,
+               std::vector<SpecificField>* parent_fields);
+
+  // Compares all the unknown fields in two messages.
+  bool CompareUnknownFields(const Message& message1, const Message& message2,
+                            const UnknownFieldSet&, const UnknownFieldSet&,
+                            std::vector<SpecificField>* parent_fields);
+
+  // Compares the specified messages for the requested field lists. The field
+  // lists are modified depending on comparison settings, and then passed to
+  // CompareWithFieldsInternal.
+  bool CompareRequestedFieldsUsingSettings(
+      const Message& message1, const Message& message2,
+      const FieldDescriptorArray& message1_fields,
+      const FieldDescriptorArray& message2_fields,
+      std::vector<SpecificField>* parent_fields);
+
+  // Compares the specified messages with the specified field lists.
+  bool CompareWithFieldsInternal(const Message& message1,
+                                 const Message& message2,
+                                 const FieldDescriptorArray& message1_fields,
+                                 const FieldDescriptorArray& message2_fields,
+                                 std::vector<SpecificField>* parent_fields);
+
+  // Compares the repeated fields, and report the error.
+  bool CompareRepeatedField(const Message& message1, const Message& message2,
+                            const FieldDescriptor* field,
+                            std::vector<SpecificField>* parent_fields);
+
+  // Compares map fields, and report the error.
+  bool CompareMapField(const Message& message1, const Message& message2,
+                       const FieldDescriptor* field,
+                       std::vector<SpecificField>* parent_fields);
+
+  // Helper for CompareRepeatedField and CompareMapField: compares and reports
+  // differences element-wise. This is the implementation for non-map fields,
+  // and can also compare map fields by using the underlying representation.
+  bool CompareRepeatedRep(const Message& message1, const Message& message2,
+                          const FieldDescriptor* field,
+                          std::vector<SpecificField>* parent_fields);
+
+  // Helper for CompareMapField: compare the map fields using map reflection
+  // instead of sync to repeated.
+  bool CompareMapFieldByMapReflection(const Message& message1,
+                                      const Message& message2,
+                                      const FieldDescriptor* field,
+                                      std::vector<SpecificField>* parent_fields,
+                                      DefaultFieldComparator* comparator);
+
+  // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields.
+  bool CompareFieldValue(const Message& message1, const Message& message2,
+                         const FieldDescriptor* field, int index1, int index2);
+
+  // Compares the specified field on the two messages, returning
+  // true if they are the same, false otherwise. For repeated fields,
+  // this method only compares the value in the specified index. This method
+  // uses Compare functions to recurse into submessages.
+  // The parent_fields vector is used in calls to a Reporter instance calls.
+  // It can be NULL, in which case the MessageDifferencer will create new
+  // list of parent messages if it needs to recursively compare the given field.
+  // To avoid confusing users you should not set it to NULL unless you modified
+  // Reporter to handle the change of parent_fields correctly.
+  bool CompareFieldValueUsingParentFields(
+      const Message& message1, const Message& message2,
+      const FieldDescriptor* field, int index1, int index2,
+      std::vector<SpecificField>* parent_fields);
+
+  // Compares the specified field on the two messages, returning comparison
+  // result, as returned by appropriate FieldComparator.
+  FieldComparator::ComparisonResult GetFieldComparisonResult(
+      const Message& message1, const Message& message2,
+      const FieldDescriptor* field, int index1, int index2,
+      const FieldContext* field_context);
+
+  // Check if the two elements in the repeated field are match to each other.
+  // if the key_comprator is NULL, this function returns true when the two
+  // elements are equal.
+  bool IsMatch(const FieldDescriptor* repeated_field,
+               const MapKeyComparator* key_comparator, const Message* message1,
+               const Message* message2,
+               const std::vector<SpecificField>& parent_fields,
+               Reporter* reporter, int index1, int index2);
+
+  // Returns true when this repeated field has been configured to be treated
+  // as a Set / SmartSet / SmartList.
+  bool IsTreatedAsSet(const FieldDescriptor* field);
+  bool IsTreatedAsSmartSet(const FieldDescriptor* field);
+
+  bool IsTreatedAsSmartList(const FieldDescriptor* field);
+  // When treating as SMART_LIST, it uses MatchIndicesPostProcessorForSmartList
+  // by default to find the longest matching sequence from the first matching
+  // element. The callback takes two vectors showing the matching indices from
+  // the other vector, where -1 means an unmatch.
+  void SetMatchIndicesForSmartListCallback(
+      std::function<void(std::vector<int>*, std::vector<int>*)> callback);
+
+  // Returns true when this repeated field is to be compared as a subset, ie.
+  // has been configured to be treated as a set or map and scope is set to
+  // PARTIAL.
+  bool IsTreatedAsSubset(const FieldDescriptor* field);
+
+  // Returns true if this field is to be ignored when this
+  // MessageDifferencer compares messages.
+  bool IsIgnored(const Message& message1, const Message& message2,
+                 const FieldDescriptor* field,
+                 const std::vector<SpecificField>& parent_fields);
+
+  // Returns true if this unknown field is to be ignored when this
+  // MessageDifferencer compares messages.
+  bool IsUnknownFieldIgnored(const Message& message1, const Message& message2,
+                             const SpecificField& field,
+                             const std::vector<SpecificField>& parent_fields);
+
+  // Returns MapKeyComparator* when this field has been configured to be treated
+  // as a map or its is_map() return true.  If not, returns NULL.
+  const MapKeyComparator* GetMapKeyComparator(
+      const FieldDescriptor* field) const;
+
+  // Attempts to match indices of a repeated field, so that the contained values
+  // match. Clears output vectors and sets their values to indices of paired
+  // messages, ie. if message1[0] matches message2[1], then match_list1[0] == 1
+  // and match_list2[1] == 0. The unmatched indices are indicated by -1.
+  // Assumes the repeated field is not treated as a simple list.
+  // This method returns false if the match failed. However, it doesn't mean
+  // that the comparison succeeds when this method returns true (you need to
+  // double-check in this case).
+  bool MatchRepeatedFieldIndices(
+      const Message& message1, const Message& message2,
+      const FieldDescriptor* repeated_field,
+      const MapKeyComparator* key_comparator,
+      const std::vector<SpecificField>& parent_fields,
+      std::vector<int>* match_list1, std::vector<int>* match_list2);
+
+  // Checks if index is equal to new_index in all the specific fields.
+  static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields);
+
+  // CHECKs that the given repeated field can be compared according to
+  // new_comparison.
+  void CheckRepeatedFieldComparisons(
+      const FieldDescriptor* field,
+      const RepeatedFieldComparison& new_comparison);
+
+  // Defines a map between field descriptors and their MapKeyComparators.
+  // Used for repeated fields when they are configured as TreatAsMap.
+  typedef std::map<const FieldDescriptor*, const MapKeyComparator*>
+      FieldKeyComparatorMap;
+
+  // Defines a set to store field descriptors.  Used for repeated fields when
+  // they are configured as TreatAsSet.
+  typedef std::set<const FieldDescriptor*> FieldSet;
+  typedef std::map<const FieldDescriptor*, RepeatedFieldComparison> FieldMap;
+
+  Reporter* reporter_;
+  DefaultFieldComparator default_field_comparator_;
+  MessageFieldComparison message_field_comparison_;
+  Scope scope_;
+  RepeatedFieldComparison repeated_field_comparison_;
+
+  FieldMap repeated_field_comparisons_;
+  // Keeps track of MapKeyComparators that are created within
+  // MessageDifferencer. These MapKeyComparators should be deleted
+  // before MessageDifferencer is destroyed.
+  // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't
+  // store the supplied FieldDescriptors directly. Instead, a new
+  // MapKeyComparator is created for comparison purpose.
+  std::vector<MapKeyComparator*> owned_key_comparators_;
+  FieldKeyComparatorMap map_field_key_comparator_;
+  MapEntryKeyComparator map_entry_key_comparator_;
+  std::vector<IgnoreCriteria*> ignore_criteria_;
+  // Reused multiple times in RetrieveFields to avoid extra allocations
+  std::vector<const FieldDescriptor*> tmp_message_fields_;
+
+  FieldSet ignored_fields_;
+
+  union {
+    DefaultFieldComparator* default_impl;
+    FieldComparator* base;
+  } field_comparator_ = {&default_field_comparator_};
+  enum { kFCDefault, kFCBase } field_comparator_kind_ = kFCDefault;
+
+  bool report_matches_;
+  bool report_moves_;
+  bool report_ignores_;
+
+  std::string* output_string_;
+
+  // Callback to post-process the matched indices to support SMART_LIST.
+  std::function<void(std::vector<int>*, std::vector<int>*)>
+      match_indices_for_smart_list_callback_;
+
+  MessageDifferencer::UnpackAnyField unpack_any_field_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer);
+};
+
+// This class provides extra information to the FieldComparator::Compare
+// function.
+class PROTOBUF_EXPORT FieldContext {
+ public:
+  explicit FieldContext(
+      std::vector<MessageDifferencer::SpecificField>* parent_fields)
+      : parent_fields_(parent_fields) {}
+
+  std::vector<MessageDifferencer::SpecificField>* parent_fields() const {
+    return parent_fields_;
+  }
+
+ private:
+  std::vector<MessageDifferencer::SpecificField>* parent_fields_;
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/time_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/time_util.h
new file mode 100644
index 0000000..709527e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/time_util.h
@@ -0,0 +1,314 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines utilities for the Timestamp and Duration well known types.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
+
+#include <cstdint>
+#include <ctime>
+#include <ostream>
+#include <string>
+#ifdef _MSC_VER
+#ifdef _XBOX_ONE
+struct timeval {
+  int64_t tv_sec;  /* seconds */
+  int64_t tv_usec; /* and microseconds */
+};
+#else
+#include <winsock2.h>
+#endif  // _XBOX_ONE
+#else
+#include <sys/time.h>
+#endif
+
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Utility functions for Timestamp and Duration.
+class PROTOBUF_EXPORT TimeUtil {
+  typedef google::protobuf::Timestamp Timestamp;
+  typedef google::protobuf::Duration Duration;
+
+ public:
+  // The min/max Timestamp/Duration values we support.
+  //
+  // For "0001-01-01T00:00:00Z".
+  static const int64_t kTimestampMinSeconds = -62135596800LL;
+  // For "9999-12-31T23:59:59.999999999Z".
+  static const int64_t kTimestampMaxSeconds = 253402300799LL;
+  static const int64_t kDurationMinSeconds = -315576000000LL;
+  static const int64_t kDurationMaxSeconds = 315576000000LL;
+
+  // Converts Timestamp to/from RFC 3339 date string format.
+  // Generated output will always be Z-normalized and uses 3, 6 or 9
+  // fractional digits as required to represent the exact time. When
+  // parsing, any fractional digits (or none) and any offset are
+  // accepted as long as they fit into nano-seconds precision.
+  // Note that Timestamp can only represent time from
+  // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. Converting
+  // a Timestamp outside of this range is undefined behavior.
+  // See https://www.ietf.org/rfc/rfc3339.txt
+  //
+  // Example of generated format:
+  //   "1972-01-01T10:00:20.021Z"
+  //
+  // Example of accepted format:
+  //   "1972-01-01T10:00:20.021-05:00"
+  static std::string ToString(const Timestamp& timestamp);
+  static bool FromString(const std::string& value, Timestamp* timestamp);
+
+  // Converts Duration to/from string format. The string format will contains
+  // 3, 6, or 9 fractional digits depending on the precision required to
+  // represent the exact Duration value. For example:
+  //   "1s", "1.010s", "1.000000100s", "-3.100s"
+  // The range that can be represented by Duration is from -315,576,000,000
+  // to +315,576,000,000 inclusive (in seconds).
+  static std::string ToString(const Duration& duration);
+  static bool FromString(const std::string& value, Duration* timestamp);
+
+#ifdef GetCurrentTime
+#undef GetCurrentTime  // Visual Studio has macro GetCurrentTime
+#endif
+  // Gets the current UTC time.
+  static Timestamp GetCurrentTime();
+  // Returns the Time representing "1970-01-01 00:00:00".
+  static Timestamp GetEpoch();
+
+  // Converts between Duration and integer types. The behavior is undefined if
+  // the input value is not in the valid range of Duration.
+  static Duration NanosecondsToDuration(int64_t nanos);
+  static Duration MicrosecondsToDuration(int64_t micros);
+  static Duration MillisecondsToDuration(int64_t millis);
+  static Duration SecondsToDuration(int64_t seconds);
+  static Duration MinutesToDuration(int64_t minutes);
+  static Duration HoursToDuration(int64_t hours);
+  // Result will be truncated towards zero. For example, "-1.5s" will be
+  // truncated to "-1s", and "1.5s" to "1s" when converting to seconds.
+  // It's undefined behavior if the input duration is not valid or the result
+  // exceeds the range of int64. A duration is not valid if it's not in the
+  // valid range of Duration, or have an invalid nanos value (i.e., larger
+  // than 999999999, less than -999999999, or have a different sign from the
+  // seconds part).
+  static int64_t DurationToNanoseconds(const Duration& duration);
+  static int64_t DurationToMicroseconds(const Duration& duration);
+  static int64_t DurationToMilliseconds(const Duration& duration);
+  static int64_t DurationToSeconds(const Duration& duration);
+  static int64_t DurationToMinutes(const Duration& duration);
+  static int64_t DurationToHours(const Duration& duration);
+  // Creates Timestamp from integer types. The integer value indicates the
+  // time elapsed from Epoch time. The behavior is undefined if the input
+  // value is not in the valid range of Timestamp.
+  static Timestamp NanosecondsToTimestamp(int64_t nanos);
+  static Timestamp MicrosecondsToTimestamp(int64_t micros);
+  static Timestamp MillisecondsToTimestamp(int64_t millis);
+  static Timestamp SecondsToTimestamp(int64_t seconds);
+  // Result will be truncated down to the nearest integer value. For example,
+  // with "1969-12-31T23:59:59.9Z", TimestampToMilliseconds() returns -100
+  // and TimestampToSeconds() returns -1. It's undefined behavior if the input
+  // Timestamp is not valid (i.e., its seconds part or nanos part does not fall
+  // in the valid range) or the return value doesn't fit into int64.
+  static int64_t TimestampToNanoseconds(const Timestamp& timestamp);
+  static int64_t TimestampToMicroseconds(const Timestamp& timestamp);
+  static int64_t TimestampToMilliseconds(const Timestamp& timestamp);
+  static int64_t TimestampToSeconds(const Timestamp& timestamp);
+
+  // Conversion to/from other time/date types. Note that these types may
+  // have a different precision and time range from Timestamp/Duration.
+  // When converting to a lower precision type, the value will be truncated
+  // to the nearest value that can be represented. If the value is
+  // out of the range of the result type, the return value is undefined.
+  //
+  // Conversion to/from time_t
+  static Timestamp TimeTToTimestamp(time_t value);
+  static time_t TimestampToTimeT(const Timestamp& value);
+
+  // Conversion to/from timeval
+  static Timestamp TimevalToTimestamp(const timeval& value);
+  static timeval TimestampToTimeval(const Timestamp& value);
+  static Duration TimevalToDuration(const timeval& value);
+  static timeval DurationToTimeval(const Duration& value);
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+// Overloaded operators for Duration.
+//
+// Assignment operators.
+PROTOBUF_EXPORT Duration& operator+=(Duration& d1,
+                                     const Duration& d2);  // NOLINT
+PROTOBUF_EXPORT Duration& operator-=(Duration& d1,
+                                     const Duration& d2);     // NOLINT
+PROTOBUF_EXPORT Duration& operator*=(Duration& d, int64_t r);  // NOLINT
+PROTOBUF_EXPORT Duration& operator*=(Duration& d, double r);  // NOLINT
+PROTOBUF_EXPORT Duration& operator/=(Duration& d, int64_t r);  // NOLINT
+PROTOBUF_EXPORT Duration& operator/=(Duration& d, double r);  // NOLINT
+// Overload for other integer types.
+template <typename T>
+Duration& operator*=(Duration& d, T r) {  // NOLINT
+  int64_t x = r;
+  return d *= x;
+}
+template <typename T>
+Duration& operator/=(Duration& d, T r) {  // NOLINT
+  int64_t x = r;
+  return d /= x;
+}
+PROTOBUF_EXPORT Duration& operator%=(Duration& d1,
+                                     const Duration& d2);  // NOLINT
+// Relational operators.
+inline bool operator<(const Duration& d1, const Duration& d2) {
+  if (d1.seconds() == d2.seconds()) {
+    return d1.nanos() < d2.nanos();
+  }
+  return d1.seconds() < d2.seconds();
+}
+inline bool operator>(const Duration& d1, const Duration& d2) {
+  return d2 < d1;
+}
+inline bool operator>=(const Duration& d1, const Duration& d2) {
+  return !(d1 < d2);
+}
+inline bool operator<=(const Duration& d1, const Duration& d2) {
+  return !(d2 < d1);
+}
+inline bool operator==(const Duration& d1, const Duration& d2) {
+  return d1.seconds() == d2.seconds() && d1.nanos() == d2.nanos();
+}
+inline bool operator!=(const Duration& d1, const Duration& d2) {
+  return !(d1 == d2);
+}
+// Additive operators
+inline Duration operator-(const Duration& d) {
+  Duration result;
+  result.set_seconds(-d.seconds());
+  result.set_nanos(-d.nanos());
+  return result;
+}
+inline Duration operator+(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result += d2;
+}
+inline Duration operator-(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result -= d2;
+}
+// Multiplicative operators
+template <typename T>
+inline Duration operator*(Duration d, T r) {
+  return d *= r;
+}
+template <typename T>
+inline Duration operator*(T r, Duration d) {
+  return d *= r;
+}
+template <typename T>
+inline Duration operator/(Duration d, T r) {
+  return d /= r;
+}
+PROTOBUF_EXPORT int64_t operator/(const Duration& d1, const Duration& d2);
+
+inline Duration operator%(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result %= d2;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const Duration& d) {
+  out << ::PROTOBUF_NAMESPACE_ID::util::TimeUtil::ToString(d);
+  return out;
+}
+
+// Overloaded operators for Timestamp
+//
+// Assignment operators.
+PROTOBUF_EXPORT Timestamp& operator+=(Timestamp& t,
+                                      const Duration& d);  // NOLINT
+PROTOBUF_EXPORT Timestamp& operator-=(Timestamp& t,
+                                      const Duration& d);  // NOLINT
+// Relational operators.
+inline bool operator<(const Timestamp& t1, const Timestamp& t2) {
+  if (t1.seconds() == t2.seconds()) {
+    return t1.nanos() < t2.nanos();
+  }
+  return t1.seconds() < t2.seconds();
+}
+inline bool operator>(const Timestamp& t1, const Timestamp& t2) {
+  return t2 < t1;
+}
+inline bool operator>=(const Timestamp& t1, const Timestamp& t2) {
+  return !(t1 < t2);
+}
+inline bool operator<=(const Timestamp& t1, const Timestamp& t2) {
+  return !(t2 < t1);
+}
+inline bool operator==(const Timestamp& t1, const Timestamp& t2) {
+  return t1.seconds() == t2.seconds() && t1.nanos() == t2.nanos();
+}
+inline bool operator!=(const Timestamp& t1, const Timestamp& t2) {
+  return !(t1 == t2);
+}
+// Additive operators.
+inline Timestamp operator+(const Timestamp& t, const Duration& d) {
+  Timestamp result = t;
+  return result += d;
+}
+inline Timestamp operator+(const Duration& d, const Timestamp& t) {
+  Timestamp result = t;
+  return result += d;
+}
+inline Timestamp operator-(const Timestamp& t, const Duration& d) {
+  Timestamp result = t;
+  return result -= d;
+}
+PROTOBUF_EXPORT Duration operator-(const Timestamp& t1, const Timestamp& t2);
+
+inline std::ostream& operator<<(std::ostream& out, const Timestamp& t) {
+  out << ::PROTOBUF_NAMESPACE_ID::util::TimeUtil::ToString(t);
+  return out;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/type_resolver.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/type_resolver.h
new file mode 100644
index 0000000..b2e7b43
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/type_resolver.h
@@ -0,0 +1,77 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines a TypeResolver for the Any message.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_H__
+#define GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/status.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class DescriptorPool;
+namespace util {
+
+// Abstract interface for a type resolver.
+//
+// Implementations of this interface must be thread-safe.
+class PROTOBUF_EXPORT TypeResolver {
+ public:
+  TypeResolver() {}
+  virtual ~TypeResolver() {}
+
+  // Resolves a type url for a message type.
+  virtual util::Status ResolveMessageType(
+      const std::string& type_url, google::protobuf::Type* message_type) = 0;
+
+  // Resolves a type url for an enum type.
+  virtual util::Status ResolveEnumType(const std::string& type_url,
+                                       google::protobuf::Enum* enum_type) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeResolver);
+};
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/type_resolver_util.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/type_resolver_util.h
new file mode 100644
index 0000000..7f6a4b9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/util/type_resolver_util.h
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Defines utilities for the TypeResolver.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+class DescriptorPool;
+namespace util {
+class TypeResolver;
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+// Creates a TypeResolver that serves type information in the given descriptor
+// pool. Caller takes ownership of the returned TypeResolver.
+PROTOBUF_EXPORT TypeResolver* NewTypeResolverForDescriptorPool(
+    const std::string& url_prefix, const DescriptorPool* pool);
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wire_format.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wire_format.h
new file mode 100644
index 0000000..1acbf9e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wire_format.h
@@ -0,0 +1,414 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//         atenasio@google.com (Chris Atenasio) (ZigZag transform)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+
+#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_H__
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_H__
+
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class MapKey;           // map_field.h
+class UnknownFieldSet;  // unknown_field_set.h
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This class is for internal use by the protocol buffer library and by
+// protocol-compiler-generated message classes.  It must not be called
+// directly by clients.
+//
+// This class contains code for implementing the binary protocol buffer
+// wire format via reflection.  The WireFormatLite class implements the
+// non-reflection based routines.
+//
+// This class is really a namespace that contains only static methods
+class PROTOBUF_EXPORT WireFormat {
+ public:
+  // Given a field return its WireType
+  static inline WireFormatLite::WireType WireTypeForField(
+      const FieldDescriptor* field);
+
+  // Given a FieldDescriptor::Type return its WireType
+  static inline WireFormatLite::WireType WireTypeForFieldType(
+      FieldDescriptor::Type type);
+
+  // Compute the byte size of a tag.  For groups, this includes both the start
+  // and end tags.
+  static inline size_t TagSize(int field_number, FieldDescriptor::Type type);
+
+  // These procedures can be used to implement the methods of Message which
+  // handle parsing and serialization of the protocol buffer wire format
+  // using only the Reflection interface.  When you ask the protocol
+  // compiler to optimize for code size rather than speed, it will implement
+  // those methods in terms of these procedures.  Of course, these are much
+  // slower than the specialized implementations which the protocol compiler
+  // generates when told to optimize for speed.
+
+  // Read a message in protocol buffer wire format.
+  //
+  // This procedure reads either to the end of the input stream or through
+  // a WIRETYPE_END_GROUP tag ending the message, whichever comes first.
+  // It returns false if the input is invalid.
+  //
+  // Required fields are NOT checked by this method.  You must call
+  // IsInitialized() on the resulting message yourself.
+  static bool ParseAndMergePartial(io::CodedInputStream* input,
+                                   Message* message);
+
+  // This is meant for internal protobuf use (WireFormat is an internal class).
+  // This is the reflective implementation of the _InternalParse functionality.
+  static const char* _InternalParse(Message* msg, const char* ptr,
+                                    internal::ParseContext* ctx);
+
+  // Serialize a message in protocol buffer wire format.
+  //
+  // Any embedded messages within the message must have their correct sizes
+  // cached.  However, the top-level message need not; its size is passed as
+  // a parameter to this procedure.
+  //
+  // These return false iff the underlying stream returns a write error.
+  static void SerializeWithCachedSizes(const Message& message, int size,
+                                       io::CodedOutputStream* output) {
+    int expected_endpoint = output->ByteCount() + size;
+    output->SetCur(
+        _InternalSerialize(message, output->Cur(), output->EpsCopy()));
+    GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint)
+        << ": Protocol message serialized to a size different from what was "
+           "originally expected.  Perhaps it was modified by another thread "
+           "during serialization?";
+  }
+  static uint8_t* _InternalSerialize(const Message& message, uint8_t* target,
+                                     io::EpsCopyOutputStream* stream);
+
+  // Implements Message::ByteSize() via reflection.  WARNING:  The result
+  // of this method is *not* cached anywhere.  However, all embedded messages
+  // will have their ByteSize() methods called, so their sizes will be cached.
+  // Therefore, calling this method is sufficient to allow you to call
+  // WireFormat::SerializeWithCachedSizes() on the same object.
+  static size_t ByteSize(const Message& message);
+
+  // -----------------------------------------------------------------
+  // Helpers for dealing with unknown fields
+
+  // Skips a field value of the given WireType.  The input should start
+  // positioned immediately after the tag.  If unknown_fields is non-nullptr,
+  // the contents of the field will be added to it.
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag,
+                        UnknownFieldSet* unknown_fields);
+
+  // Reads and ignores a message from the input.  If unknown_fields is
+  // non-nullptr, the contents will be added to it.
+  static bool SkipMessage(io::CodedInputStream* input,
+                          UnknownFieldSet* unknown_fields);
+
+  // Read a packed enum field. If the is_valid function is not nullptr, values
+  // for which is_valid(value) returns false are appended to
+  // unknown_fields_stream.
+  static bool ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+                                             uint32_t field_number,
+                                             bool (*is_valid)(int),
+                                             UnknownFieldSet* unknown_fields,
+                                             RepeatedField<int>* values);
+
+  // Write the contents of an UnknownFieldSet to the output.
+  static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
+                                     io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeUnknownFieldsToArray(
+        unknown_fields, output->Cur(), output->EpsCopy()));
+  }
+  // Same as above, except writing directly to the provided buffer.
+  // Requires that the buffer have sufficient capacity for
+  // ComputeUnknownFieldsSize(unknown_fields).
+  //
+  // Returns a pointer past the last written byte.
+  static uint8_t* SerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target) {
+    io::EpsCopyOutputStream stream(
+        target, static_cast<int>(ComputeUnknownFieldsSize(unknown_fields)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalSerializeUnknownFieldsToArray(unknown_fields, target,
+                                                 &stream);
+  }
+  static uint8_t* InternalSerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target,
+      io::EpsCopyOutputStream* stream);
+
+  // Same thing except for messages that have the message_set_wire_format
+  // option.
+  static void SerializeUnknownMessageSetItems(
+      const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeUnknownMessageSetItemsToArray(
+        unknown_fields, output->Cur(), output->EpsCopy()));
+  }
+  // Same as above, except writing directly to the provided buffer.
+  // Requires that the buffer have sufficient capacity for
+  // ComputeUnknownMessageSetItemsSize(unknown_fields).
+  //
+  // Returns a pointer past the last written byte.
+  static uint8_t* SerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target);
+  static uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8_t* target,
+      io::EpsCopyOutputStream* stream);
+
+  // Compute the size of the UnknownFieldSet on the wire.
+  static size_t ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields);
+
+  // Same thing except for messages that have the message_set_wire_format
+  // option.
+  static size_t ComputeUnknownMessageSetItemsSize(
+      const UnknownFieldSet& unknown_fields);
+
+  // Helper functions for encoding and decoding tags.  (Inlined below and in
+  // _inl.h)
+  //
+  // This is different from MakeTag(field->number(), field->type()) in the
+  // case of packed repeated fields.
+  static uint32_t MakeTag(const FieldDescriptor* field);
+
+  // Parse a single field.  The input should start out positioned immediately
+  // after the tag.
+  static bool ParseAndMergeField(
+      uint32_t tag,
+      const FieldDescriptor* field,  // May be nullptr for unknown
+      Message* message, io::CodedInputStream* input);
+
+  // Serialize a single field.
+  static void SerializeFieldWithCachedSizes(
+      const FieldDescriptor* field,  // Cannot be nullptr
+      const Message& message, io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeField(field, message, output->Cur(),
+                                          output->EpsCopy()));
+  }
+  static uint8_t* InternalSerializeField(
+      const FieldDescriptor* field,  // Cannot be nullptr
+      const Message& message, uint8_t* target, io::EpsCopyOutputStream* stream);
+
+  // Compute size of a single field.  If the field is a message type, this
+  // will call ByteSize() for the embedded message, insuring that it caches
+  // its size.
+  static size_t FieldByteSize(const FieldDescriptor* field,  // Can't be nullptr
+                              const Message& message);
+
+  // Parse/serialize a MessageSet::Item group.  Used with messages that use
+  // option message_set_wire_format = true.
+  static bool ParseAndMergeMessageSetItem(io::CodedInputStream* input,
+                                          Message* message);
+  static void SerializeMessageSetItemWithCachedSizes(
+      const FieldDescriptor* field, const Message& message,
+      io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeMessageSetItem(
+        field, message, output->Cur(), output->EpsCopy()));
+  }
+  static uint8_t* InternalSerializeMessageSetItem(
+      const FieldDescriptor* field, const Message& message, uint8_t* target,
+      io::EpsCopyOutputStream* stream);
+  static size_t MessageSetItemByteSize(const FieldDescriptor* field,
+                                       const Message& message);
+
+  // Computes the byte size of a field, excluding tags. For packed fields, it
+  // only includes the size of the raw data, and not the size of the total
+  // length, but for other length-delimited types, the size of the length is
+  // included.
+  static size_t FieldDataOnlyByteSize(
+      const FieldDescriptor* field,  // Cannot be nullptr
+      const Message& message);
+
+  enum Operation {
+    PARSE = 0,
+    SERIALIZE = 1,
+  };
+
+  // Verifies that a string field is valid UTF8, logging an error if not.
+  // This function will not be called by newly generated protobuf code
+  // but remains present to support existing code.
+  static void VerifyUTF8String(const char* data, int size, Operation op);
+  // The NamedField variant takes a field name in order to produce an
+  // informative error message if verification fails.
+  static void VerifyUTF8StringNamedField(const char* data, int size,
+                                         Operation op, const char* field_name);
+
+ private:
+  struct MessageSetParser;
+  // Skip a MessageSet field.
+  static bool SkipMessageSetField(io::CodedInputStream* input,
+                                  uint32_t field_number,
+                                  UnknownFieldSet* unknown_fields);
+
+  // Parse a MessageSet field.
+  static bool ParseAndMergeMessageSetField(uint32_t field_number,
+                                           const FieldDescriptor* field,
+                                           Message* message,
+                                           io::CodedInputStream* input);
+  // Parses the value from the wire that belongs to tag.
+  static const char* _InternalParseAndMergeField(Message* msg, const char* ptr,
+                                                 internal::ParseContext* ctx,
+                                                 uint64_t tag,
+                                                 const Reflection* reflection,
+                                                 const FieldDescriptor* field);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat);
+};
+
+// Subclass of FieldSkipper which saves skipped fields to an UnknownFieldSet.
+class PROTOBUF_EXPORT UnknownFieldSetFieldSkipper : public FieldSkipper {
+ public:
+  UnknownFieldSetFieldSkipper(UnknownFieldSet* unknown_fields)
+      : unknown_fields_(unknown_fields) {}
+  ~UnknownFieldSetFieldSkipper() override {}
+
+  // implements FieldSkipper -----------------------------------------
+  bool SkipField(io::CodedInputStream* input, uint32_t tag) override;
+  bool SkipMessage(io::CodedInputStream* input) override;
+  void SkipUnknownEnum(int field_number, int value) override;
+
+ protected:
+  UnknownFieldSet* unknown_fields_;
+};
+
+// inline methods ====================================================
+
+inline WireFormatLite::WireType WireFormat::WireTypeForField(
+    const FieldDescriptor* field) {
+  if (field->is_packed()) {
+    return WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+  } else {
+    return WireTypeForFieldType(field->type());
+  }
+}
+
+inline WireFormatLite::WireType WireFormat::WireTypeForFieldType(
+    FieldDescriptor::Type type) {
+  // Some compilers don't like enum -> enum casts, so we implicit_cast to
+  // int first.
+  return WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(implicit_cast<int>(type)));
+}
+
+inline uint32_t WireFormat::MakeTag(const FieldDescriptor* field) {
+  return WireFormatLite::MakeTag(field->number(), WireTypeForField(field));
+}
+
+inline size_t WireFormat::TagSize(int field_number,
+                                  FieldDescriptor::Type type) {
+  // Some compilers don't like enum -> enum casts, so we implicit_cast to
+  // int first.
+  return WireFormatLite::TagSize(
+      field_number,
+      static_cast<WireFormatLite::FieldType>(implicit_cast<int>(type)));
+}
+
+inline void WireFormat::VerifyUTF8String(const char* data, int size,
+                                         WireFormat::Operation op) {
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  WireFormatLite::VerifyUtf8String(
+      data, size, static_cast<WireFormatLite::Operation>(op), nullptr);
+#else
+  // Avoid the compiler warning about unused variables.
+  (void)data;
+  (void)size;
+  (void)op;
+#endif
+}
+
+inline void WireFormat::VerifyUTF8StringNamedField(const char* data, int size,
+                                                   WireFormat::Operation op,
+                                                   const char* field_name) {
+#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+  WireFormatLite::VerifyUtf8String(
+      data, size, static_cast<WireFormatLite::Operation>(op), field_name);
+#else
+  // Avoid the compiler warning about unused variables.
+  (void)data;
+  (void)size;
+  (void)op;
+  (void)field_name;
+#endif
+}
+
+
+inline uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  return WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+      unknown_fields, target, stream);
+}
+
+inline size_t ComputeUnknownMessageSetItemsSize(
+    const UnknownFieldSet& unknown_fields) {
+  return WireFormat::ComputeUnknownMessageSetItemsSize(unknown_fields);
+}
+
+// Compute the size of the UnknownFieldSet on the wire.
+PROTOBUF_EXPORT
+size_t ComputeUnknownFieldsSize(const InternalMetadata& metadata, size_t size,
+                                CachedSize* cached_size);
+
+size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
+                              const MapKey& value);
+
+uint8_t* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                        const MapKey& value, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream);
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_WIRE_FORMAT_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wire_format_lite.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wire_format_lite.h
new file mode 100644
index 0000000..80d3961
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wire_format_lite.h
@@ -0,0 +1,1908 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//         atenasio@google.com (Chris Atenasio) (ZigZag transform)
+//         wink@google.com (Wink Saville) (refactored from wire_format.h)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This header is logically internal, but is made public because it is used
+// from protocol-compiler-generated code, which may reside in other components.
+
+#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
+
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+
+// Do UTF-8 validation on string type in Debug build only
+#ifndef NDEBUG
+#define GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
+#endif
+
+// Avoid conflict with iOS where <ConditionalMacros.h> #defines TYPE_BOOL.
+//
+// If some one needs the macro TYPE_BOOL in a file that includes this header,
+// it's possible to bring it back using push/pop_macro as follows.
+//
+// #pragma push_macro("TYPE_BOOL")
+// #include this header and/or all headers that need the macro to be undefined.
+// #pragma pop_macro("TYPE_BOOL")
+#undef TYPE_BOOL
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This class is for internal use by the protocol buffer library and by
+// protocol-compiler-generated message classes.  It must not be called
+// directly by clients.
+//
+// This class contains helpers for implementing the binary protocol buffer
+// wire format without the need for reflection. Use WireFormat when using
+// reflection.
+//
+// This class is really a namespace that contains only static methods.
+class PROTOBUF_EXPORT WireFormatLite {
+ public:
+  // -----------------------------------------------------------------
+  // Helper constants and functions related to the format.  These are
+  // mostly meant for internal and generated code to use.
+
+  // The wire format is composed of a sequence of tag/value pairs, each
+  // of which contains the value of one field (or one element of a repeated
+  // field).  Each tag is encoded as a varint.  The lower bits of the tag
+  // identify its wire type, which specifies the format of the data to follow.
+  // The rest of the bits contain the field number.  Each type of field (as
+  // declared by FieldDescriptor::Type, in descriptor.h) maps to one of
+  // these wire types.  Immediately following each tag is the field's value,
+  // encoded in the format specified by the wire type.  Because the tag
+  // identifies the encoding of this data, it is possible to skip
+  // unrecognized fields for forwards compatibility.
+
+  enum WireType {
+    WIRETYPE_VARINT = 0,
+    WIRETYPE_FIXED64 = 1,
+    WIRETYPE_LENGTH_DELIMITED = 2,
+    WIRETYPE_START_GROUP = 3,
+    WIRETYPE_END_GROUP = 4,
+    WIRETYPE_FIXED32 = 5,
+  };
+
+  // Lite alternative to FieldDescriptor::Type.  Must be kept in sync.
+  enum FieldType {
+    TYPE_DOUBLE = 1,
+    TYPE_FLOAT = 2,
+    TYPE_INT64 = 3,
+    TYPE_UINT64 = 4,
+    TYPE_INT32 = 5,
+    TYPE_FIXED64 = 6,
+    TYPE_FIXED32 = 7,
+    TYPE_BOOL = 8,
+    TYPE_STRING = 9,
+    TYPE_GROUP = 10,
+    TYPE_MESSAGE = 11,
+    TYPE_BYTES = 12,
+    TYPE_UINT32 = 13,
+    TYPE_ENUM = 14,
+    TYPE_SFIXED32 = 15,
+    TYPE_SFIXED64 = 16,
+    TYPE_SINT32 = 17,
+    TYPE_SINT64 = 18,
+    MAX_FIELD_TYPE = 18,
+  };
+
+  // Lite alternative to FieldDescriptor::CppType.  Must be kept in sync.
+  enum CppType {
+    CPPTYPE_INT32 = 1,
+    CPPTYPE_INT64 = 2,
+    CPPTYPE_UINT32 = 3,
+    CPPTYPE_UINT64 = 4,
+    CPPTYPE_DOUBLE = 5,
+    CPPTYPE_FLOAT = 6,
+    CPPTYPE_BOOL = 7,
+    CPPTYPE_ENUM = 8,
+    CPPTYPE_STRING = 9,
+    CPPTYPE_MESSAGE = 10,
+    MAX_CPPTYPE = 10,
+  };
+
+  // Helper method to get the CppType for a particular Type.
+  static CppType FieldTypeToCppType(FieldType type);
+
+  // Given a FieldDescriptor::Type return its WireType
+  static inline WireFormatLite::WireType WireTypeForFieldType(
+      WireFormatLite::FieldType type) {
+    return kWireTypeForFieldType[type];
+  }
+
+  // Number of bits in a tag which identify the wire type.
+  static constexpr int kTagTypeBits = 3;
+  // Mask for those bits.
+  static constexpr uint32_t kTagTypeMask = (1 << kTagTypeBits) - 1;
+
+  // Helper functions for encoding and decoding tags.  (Inlined below and in
+  // _inl.h)
+  //
+  // This is different from MakeTag(field->number(), field->type()) in the
+  // case of packed repeated fields.
+  constexpr static uint32_t MakeTag(int field_number, WireType type);
+  static WireType GetTagWireType(uint32_t tag);
+  static int GetTagFieldNumber(uint32_t tag);
+
+  // Compute the byte size of a tag.  For groups, this includes both the start
+  // and end tags.
+  static inline size_t TagSize(int field_number,
+                               WireFormatLite::FieldType type);
+
+  // Skips a field value with the given tag.  The input should start
+  // positioned immediately after the tag.  Skipped values are simply
+  // discarded, not recorded anywhere.  See WireFormat::SkipField() for a
+  // version that records to an UnknownFieldSet.
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag);
+
+  // Skips a field value with the given tag.  The input should start
+  // positioned immediately after the tag. Skipped values are recorded to a
+  // CodedOutputStream.
+  static bool SkipField(io::CodedInputStream* input, uint32_t tag,
+                        io::CodedOutputStream* output);
+
+  // Reads and ignores a message from the input.  Skipped values are simply
+  // discarded, not recorded anywhere.  See WireFormat::SkipMessage() for a
+  // version that records to an UnknownFieldSet.
+  static bool SkipMessage(io::CodedInputStream* input);
+
+  // Reads and ignores a message from the input.  Skipped values are recorded
+  // to a CodedOutputStream.
+  static bool SkipMessage(io::CodedInputStream* input,
+                          io::CodedOutputStream* output);
+
+  // This macro does the same thing as WireFormatLite::MakeTag(), but the
+  // result is usable as a compile-time constant, which makes it usable
+  // as a switch case or a template input.  WireFormatLite::MakeTag() is more
+  // type-safe, though, so prefer it if possible.
+#define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \
+  static_cast<uint32_t>((static_cast<uint32_t>(FIELD_NUMBER) << 3) | (TYPE))
+
+  // These are the tags for the old MessageSet format, which was defined as:
+  //   message MessageSet {
+  //     repeated group Item = 1 {
+  //       required int32 type_id = 2;
+  //       required string message = 3;
+  //     }
+  //   }
+  static constexpr int kMessageSetItemNumber = 1;
+  static constexpr int kMessageSetTypeIdNumber = 2;
+  static constexpr int kMessageSetMessageNumber = 3;
+  static const int kMessageSetItemStartTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetItemNumber, WireFormatLite::WIRETYPE_START_GROUP);
+  static const int kMessageSetItemEndTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetItemNumber, WireFormatLite::WIRETYPE_END_GROUP);
+  static const int kMessageSetTypeIdTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetTypeIdNumber, WireFormatLite::WIRETYPE_VARINT);
+  static const int kMessageSetMessageTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kMessageSetMessageNumber, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+
+  // Byte size of all tags of a MessageSet::Item combined.
+  static const size_t kMessageSetItemTagsSize;
+
+  // Helper functions for converting between floats/doubles and IEEE-754
+  // uint32s/uint64s so that they can be written.  (Assumes your platform
+  // uses IEEE-754 floats.)
+  static uint32_t EncodeFloat(float value);
+  static float DecodeFloat(uint32_t value);
+  static uint64_t EncodeDouble(double value);
+  static double DecodeDouble(uint64_t value);
+
+  // Helper functions for mapping signed integers to unsigned integers in
+  // such a way that numbers with small magnitudes will encode to smaller
+  // varints.  If you simply static_cast a negative number to an unsigned
+  // number and varint-encode it, it will always take 10 bytes, defeating
+  // the purpose of varint.  So, for the "sint32" and "sint64" field types,
+  // we ZigZag-encode the values.
+  static uint32_t ZigZagEncode32(int32_t n);
+  static int32_t ZigZagDecode32(uint32_t n);
+  static uint64_t ZigZagEncode64(int64_t n);
+  static int64_t ZigZagDecode64(uint64_t n);
+
+  // =================================================================
+  // Methods for reading/writing individual field.
+
+  // Read fields, not including tags.  The assumption is that you already
+  // read the tag to determine what field to read.
+
+  // For primitive fields, we just use a templatized routine parameterized by
+  // the represented type and the FieldType. These are specialized with the
+  // appropriate definition for each declared type.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadPrimitive(io::CodedInputStream* input,
+                                                   CType* value);
+
+  // Reads repeated primitive values, with optimizations for repeats.
+  // tag_size and tag should both be compile-time constants provided by the
+  // protocol compiler.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadRepeatedPrimitive(
+      int tag_size, uint32_t tag, io::CodedInputStream* input,
+      RepeatedField<CType>* value);
+
+  // Identical to ReadRepeatedPrimitive, except will not inline the
+  // implementation.
+  template <typename CType, enum FieldType DeclaredType>
+  static bool ReadRepeatedPrimitiveNoInline(int tag_size, uint32_t tag,
+                                            io::CodedInputStream* input,
+                                            RepeatedField<CType>* value);
+
+  // Reads a primitive value directly from the provided buffer. It returns a
+  // pointer past the segment of data that was read.
+  //
+  // This is only implemented for the types with fixed wire size, e.g.
+  // float, double, and the (s)fixed* types.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static const uint8_t* ReadPrimitiveFromArray(
+      const uint8_t* buffer, CType* value);
+
+  // Reads a primitive packed field.
+  //
+  // This is only implemented for packable types.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadPackedPrimitive(
+      io::CodedInputStream* input, RepeatedField<CType>* value);
+
+  // Identical to ReadPackedPrimitive, except will not inline the
+  // implementation.
+  template <typename CType, enum FieldType DeclaredType>
+  static bool ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
+                                          RepeatedField<CType>* value);
+
+  // Read a packed enum field. If the is_valid function is not nullptr, values
+  // for which is_valid(value) returns false are silently dropped.
+  static bool ReadPackedEnumNoInline(io::CodedInputStream* input,
+                                     bool (*is_valid)(int),
+                                     RepeatedField<int>* values);
+
+  // Read a packed enum field. If the is_valid function is not nullptr, values
+  // for which is_valid(value) returns false are appended to
+  // unknown_fields_stream.
+  static bool ReadPackedEnumPreserveUnknowns(
+      io::CodedInputStream* input, int field_number, bool (*is_valid)(int),
+      io::CodedOutputStream* unknown_fields_stream, RepeatedField<int>* values);
+
+  // Read a string.  ReadString(..., std::string* value) requires an
+  // existing std::string.
+  static inline bool ReadString(io::CodedInputStream* input,
+                                std::string* value);
+  // ReadString(..., std::string** p) is internal-only, and should only be
+  // called from generated code. It starts by setting *p to "new std::string" if
+  // *p == &GetEmptyStringAlreadyInited().  It then invokes
+  // ReadString(io::CodedInputStream* input, *p).  This is useful for reducing
+  // code size.
+  static inline bool ReadString(io::CodedInputStream* input, std::string** p);
+  // Analogous to ReadString().
+  static bool ReadBytes(io::CodedInputStream* input, std::string* value);
+  static bool ReadBytes(io::CodedInputStream* input, std::string** p);
+
+  enum Operation {
+    PARSE = 0,
+    SERIALIZE = 1,
+  };
+
+  // Returns true if the data is valid UTF-8.
+  static bool VerifyUtf8String(const char* data, int size, Operation op,
+                               const char* field_name);
+
+  template <typename MessageType>
+  static inline bool ReadGroup(int field_number, io::CodedInputStream* input,
+                               MessageType* value);
+
+  template <typename MessageType>
+  static inline bool ReadMessage(io::CodedInputStream* input,
+                                 MessageType* value);
+
+  template <typename MessageType>
+  static inline bool ReadMessageNoVirtual(io::CodedInputStream* input,
+                                          MessageType* value) {
+    return ReadMessage(input, value);
+  }
+
+  // Write a tag.  The Write*() functions typically include the tag, so
+  // normally there's no need to call this unless using the Write*NoTag()
+  // variants.
+  PROTOBUF_NDEBUG_INLINE static void WriteTag(int field_number, WireType type,
+                                              io::CodedOutputStream* output);
+
+  // Write fields, without tags.
+  PROTOBUF_NDEBUG_INLINE static void WriteInt32NoTag(
+      int32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteInt64NoTag(
+      int64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteUInt32NoTag(
+      uint32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteUInt64NoTag(
+      uint64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSInt32NoTag(
+      int32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSInt64NoTag(
+      int64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteFixed32NoTag(
+      uint32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteFixed64NoTag(
+      uint64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSFixed32NoTag(
+      int32_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteSFixed64NoTag(
+      int64_t value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteFloatNoTag(
+      float value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteDoubleNoTag(
+      double value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteBoolNoTag(
+      bool value, io::CodedOutputStream* output);
+  PROTOBUF_NDEBUG_INLINE static void WriteEnumNoTag(
+      int value, io::CodedOutputStream* output);
+
+  // Write array of primitive fields, without tags
+  static void WriteFloatArray(const float* a, int n,
+                              io::CodedOutputStream* output);
+  static void WriteDoubleArray(const double* a, int n,
+                               io::CodedOutputStream* output);
+  static void WriteFixed32Array(const uint32_t* a, int n,
+                                io::CodedOutputStream* output);
+  static void WriteFixed64Array(const uint64_t* a, int n,
+                                io::CodedOutputStream* output);
+  static void WriteSFixed32Array(const int32_t* a, int n,
+                                 io::CodedOutputStream* output);
+  static void WriteSFixed64Array(const int64_t* a, int n,
+                                 io::CodedOutputStream* output);
+  static void WriteBoolArray(const bool* a, int n,
+                             io::CodedOutputStream* output);
+
+  // Write fields, including tags.
+  static void WriteInt32(int field_number, int32_t value,
+                         io::CodedOutputStream* output);
+  static void WriteInt64(int field_number, int64_t value,
+                         io::CodedOutputStream* output);
+  static void WriteUInt32(int field_number, uint32_t value,
+                          io::CodedOutputStream* output);
+  static void WriteUInt64(int field_number, uint64_t value,
+                          io::CodedOutputStream* output);
+  static void WriteSInt32(int field_number, int32_t value,
+                          io::CodedOutputStream* output);
+  static void WriteSInt64(int field_number, int64_t value,
+                          io::CodedOutputStream* output);
+  static void WriteFixed32(int field_number, uint32_t value,
+                           io::CodedOutputStream* output);
+  static void WriteFixed64(int field_number, uint64_t value,
+                           io::CodedOutputStream* output);
+  static void WriteSFixed32(int field_number, int32_t value,
+                            io::CodedOutputStream* output);
+  static void WriteSFixed64(int field_number, int64_t value,
+                            io::CodedOutputStream* output);
+  static void WriteFloat(int field_number, float value,
+                         io::CodedOutputStream* output);
+  static void WriteDouble(int field_number, double value,
+                          io::CodedOutputStream* output);
+  static void WriteBool(int field_number, bool value,
+                        io::CodedOutputStream* output);
+  static void WriteEnum(int field_number, int value,
+                        io::CodedOutputStream* output);
+
+  static void WriteString(int field_number, const std::string& value,
+                          io::CodedOutputStream* output);
+  static void WriteBytes(int field_number, const std::string& value,
+                         io::CodedOutputStream* output);
+  static void WriteStringMaybeAliased(int field_number,
+                                      const std::string& value,
+                                      io::CodedOutputStream* output);
+  static void WriteBytesMaybeAliased(int field_number, const std::string& value,
+                                     io::CodedOutputStream* output);
+
+  static void WriteGroup(int field_number, const MessageLite& value,
+                         io::CodedOutputStream* output);
+  static void WriteMessage(int field_number, const MessageLite& value,
+                           io::CodedOutputStream* output);
+  // Like above, but these will check if the output stream has enough
+  // space to write directly to a flat array.
+  static void WriteGroupMaybeToArray(int field_number, const MessageLite& value,
+                                     io::CodedOutputStream* output);
+  static void WriteMessageMaybeToArray(int field_number,
+                                       const MessageLite& value,
+                                       io::CodedOutputStream* output);
+
+  // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
+  // pointer must point at an instance of MessageType, *not* a subclass (or
+  // the subclass must not override SerializeWithCachedSizes()).
+  template <typename MessageType>
+  static inline void WriteGroupNoVirtual(int field_number,
+                                         const MessageType& value,
+                                         io::CodedOutputStream* output);
+  template <typename MessageType>
+  static inline void WriteMessageNoVirtual(int field_number,
+                                           const MessageType& value,
+                                           io::CodedOutputStream* output);
+
+  // Like above, but use only *ToArray methods of CodedOutputStream.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteTagToArray(int field_number,
+                                                         WireType type,
+                                                         uint8_t* target);
+
+  // Write fields, without tags.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32NoTagToArray(
+      uint32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64NoTagToArray(
+      uint64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32NoTagToArray(
+      uint32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64NoTagToArray(
+      uint64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32NoTagToArray(
+      int32_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64NoTagToArray(
+      int64_t value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatNoTagToArray(
+      float value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleNoTagToArray(
+      double value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolNoTagToArray(bool value,
+                                                               uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumNoTagToArray(int value,
+                                                               uint8_t* target);
+
+  // Write fields, without tags.  These require that value.size() > 0.
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WritePrimitiveNoTagToArray(
+      const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+      uint8_t* target);
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixedNoTagToArray(
+      const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+      uint8_t* target);
+
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32NoTagToArray(
+      const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64NoTagToArray(
+      const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32NoTagToArray(
+      const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64NoTagToArray(
+      const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32NoTagToArray(
+      const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64NoTagToArray(
+      const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatNoTagToArray(
+      const RepeatedField<float>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleNoTagToArray(
+      const RepeatedField<double>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolNoTagToArray(
+      const RepeatedField<bool>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumNoTagToArray(
+      const RepeatedField<int>& value, uint8_t* output);
+
+  // Write fields, including tags.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32ToArray(int field_number,
+                                                           int32_t value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64ToArray(int field_number,
+                                                           int64_t value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32ToArray(int field_number,
+                                                            uint32_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64ToArray(int field_number,
+                                                            uint64_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32ToArray(int field_number,
+                                                            int32_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64ToArray(int field_number,
+                                                            int64_t value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32ToArray(int field_number,
+                                                             uint32_t value,
+                                                             uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64ToArray(int field_number,
+                                                             uint64_t value,
+                                                             uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32ToArray(int field_number,
+                                                              int32_t value,
+                                                              uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64ToArray(int field_number,
+                                                              int64_t value,
+                                                              uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatToArray(int field_number,
+                                                           float value,
+                                                           uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleToArray(int field_number,
+                                                            double value,
+                                                            uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolToArray(int field_number,
+                                                          bool value,
+                                                          uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumToArray(int field_number,
+                                                          int value,
+                                                          uint8_t* target);
+
+  template <typename T>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WritePrimitiveToArray(
+      int field_number, const RepeatedField<T>& value,
+      uint8_t* (*Writer)(int, T, uint8_t*), uint8_t* target);
+
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteInt64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt32ToArray(
+      int field_number, const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteUInt64ToArray(
+      int field_number, const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSInt64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed32ToArray(
+      int field_number, const RepeatedField<uint32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFixed64ToArray(
+      int field_number, const RepeatedField<uint64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed32ToArray(
+      int field_number, const RepeatedField<int32_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteSFixed64ToArray(
+      int field_number, const RepeatedField<int64_t>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteFloatToArray(
+      int field_number, const RepeatedField<float>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteDoubleToArray(
+      int field_number, const RepeatedField<double>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBoolToArray(
+      int field_number, const RepeatedField<bool>& value, uint8_t* output);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteEnumToArray(
+      int field_number, const RepeatedField<int>& value, uint8_t* output);
+
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteStringToArray(
+      int field_number, const std::string& value, uint8_t* target);
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteBytesToArray(
+      int field_number, const std::string& value, uint8_t* target);
+
+  // Whether to serialize deterministically (e.g., map keys are
+  // sorted) is a property of a CodedOutputStream, and in the process
+  // of serialization, the "ToArray" variants may be invoked.  But they don't
+  // have a CodedOutputStream available, so they get an additional parameter
+  // telling them whether to serialize deterministically.
+  static uint8_t* InternalWriteGroup(int field_number, const MessageLite& value,
+                                     uint8_t* target,
+                                     io::EpsCopyOutputStream* stream);
+  static uint8_t* InternalWriteMessage(int field_number,
+                                       const MessageLite& value,
+                                       int cached_size, uint8_t* target,
+                                       io::EpsCopyOutputStream* stream);
+
+  // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
+  // pointer must point at an instance of MessageType, *not* a subclass (or
+  // the subclass must not override SerializeWithCachedSizes()).
+  template <typename MessageType>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteGroupNoVirtualToArray(
+      int field_number, const MessageType& value, uint8_t* target);
+  template <typename MessageType>
+  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteMessageNoVirtualToArray(
+      int field_number, const MessageType& value, uint8_t* target);
+
+  // For backward-compatibility, the last four methods also have versions
+  // that are non-deterministic always.
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteGroupToArray(
+      int field_number, const MessageLite& value, uint8_t* target) {
+    io::EpsCopyOutputStream stream(
+        target,
+        value.GetCachedSize() +
+            static_cast<int>(2 * io::CodedOutputStream::VarintSize32(
+                                     static_cast<uint32_t>(field_number) << 3)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalWriteGroup(field_number, value, target, &stream);
+  }
+  PROTOBUF_NDEBUG_INLINE static uint8_t* WriteMessageToArray(
+      int field_number, const MessageLite& value, uint8_t* target) {
+    int size = value.GetCachedSize();
+    io::EpsCopyOutputStream stream(
+        target,
+        size + static_cast<int>(io::CodedOutputStream::VarintSize32(
+                                    static_cast<uint32_t>(field_number) << 3) +
+                                io::CodedOutputStream::VarintSize32(size)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalWriteMessage(field_number, value, value.GetCachedSize(),
+                                target, &stream);
+  }
+
+  // Compute the byte size of a field.  The XxSize() functions do NOT include
+  // the tag, so you must also call TagSize().  (This is because, for repeated
+  // fields, you should only call TagSize() once and multiply it by the element
+  // count, but you may have to call XxSize() for each individual element.)
+  static inline size_t Int32Size(int32_t value);
+  static inline size_t Int64Size(int64_t value);
+  static inline size_t UInt32Size(uint32_t value);
+  static inline size_t UInt64Size(uint64_t value);
+  static inline size_t SInt32Size(int32_t value);
+  static inline size_t SInt64Size(int64_t value);
+  static inline size_t EnumSize(int value);
+  static inline size_t Int32SizePlusOne(int32_t value);
+  static inline size_t Int64SizePlusOne(int64_t value);
+  static inline size_t UInt32SizePlusOne(uint32_t value);
+  static inline size_t UInt64SizePlusOne(uint64_t value);
+  static inline size_t SInt32SizePlusOne(int32_t value);
+  static inline size_t SInt64SizePlusOne(int64_t value);
+  static inline size_t EnumSizePlusOne(int value);
+
+  static size_t Int32Size(const RepeatedField<int32_t>& value);
+  static size_t Int64Size(const RepeatedField<int64_t>& value);
+  static size_t UInt32Size(const RepeatedField<uint32_t>& value);
+  static size_t UInt64Size(const RepeatedField<uint64_t>& value);
+  static size_t SInt32Size(const RepeatedField<int32_t>& value);
+  static size_t SInt64Size(const RepeatedField<int64_t>& value);
+  static size_t EnumSize(const RepeatedField<int>& value);
+
+  // These types always have the same size.
+  static constexpr size_t kFixed32Size = 4;
+  static constexpr size_t kFixed64Size = 8;
+  static constexpr size_t kSFixed32Size = 4;
+  static constexpr size_t kSFixed64Size = 8;
+  static constexpr size_t kFloatSize = 4;
+  static constexpr size_t kDoubleSize = 8;
+  static constexpr size_t kBoolSize = 1;
+
+  static inline size_t StringSize(const std::string& value);
+  static inline size_t BytesSize(const std::string& value);
+
+  template <typename MessageType>
+  static inline size_t GroupSize(const MessageType& value);
+  template <typename MessageType>
+  static inline size_t MessageSize(const MessageType& value);
+
+  // Like above, but de-virtualize the call to ByteSize().  The
+  // pointer must point at an instance of MessageType, *not* a subclass (or
+  // the subclass must not override ByteSize()).
+  template <typename MessageType>
+  static inline size_t GroupSizeNoVirtual(const MessageType& value);
+  template <typename MessageType>
+  static inline size_t MessageSizeNoVirtual(const MessageType& value);
+
+  // Given the length of data, calculate the byte size of the data on the
+  // wire if we encode the data as a length delimited field.
+  static inline size_t LengthDelimitedSize(size_t length);
+
+ private:
+  // A helper method for the repeated primitive reader. This method has
+  // optimizations for primitive types that have fixed size on the wire, and
+  // can be read using potentially faster paths.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadRepeatedFixedSizePrimitive(
+      int tag_size, uint32_t tag, io::CodedInputStream* input,
+      RepeatedField<CType>* value);
+
+  // Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
+  template <typename CType, enum FieldType DeclaredType>
+  PROTOBUF_NDEBUG_INLINE static bool ReadPackedFixedSizePrimitive(
+      io::CodedInputStream* input, RepeatedField<CType>* value);
+
+  static const CppType kFieldTypeToCppTypeMap[];
+  static const WireFormatLite::WireType kWireTypeForFieldType[];
+  static void WriteSubMessageMaybeToArray(int size, const MessageLite& value,
+                                          io::CodedOutputStream* output);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormatLite);
+};
+
+// A class which deals with unknown values.  The default implementation just
+// discards them.  WireFormat defines a subclass which writes to an
+// UnknownFieldSet.  This class is used by ExtensionSet::ParseField(), since
+// ExtensionSet is part of the lite library but UnknownFieldSet is not.
+class PROTOBUF_EXPORT FieldSkipper {
+ public:
+  FieldSkipper() {}
+  virtual ~FieldSkipper() {}
+
+  // Skip a field whose tag has already been consumed.
+  virtual bool SkipField(io::CodedInputStream* input, uint32_t tag);
+
+  // Skip an entire message or group, up to an end-group tag (which is consumed)
+  // or end-of-stream.
+  virtual bool SkipMessage(io::CodedInputStream* input);
+
+  // Deal with an already-parsed unrecognized enum value.  The default
+  // implementation does nothing, but the UnknownFieldSet-based implementation
+  // saves it as an unknown varint.
+  virtual void SkipUnknownEnum(int field_number, int value);
+};
+
+// Subclass of FieldSkipper which saves skipped fields to a CodedOutputStream.
+
+class PROTOBUF_EXPORT CodedOutputStreamFieldSkipper : public FieldSkipper {
+ public:
+  explicit CodedOutputStreamFieldSkipper(io::CodedOutputStream* unknown_fields)
+      : unknown_fields_(unknown_fields) {}
+  ~CodedOutputStreamFieldSkipper() override {}
+
+  // implements FieldSkipper -----------------------------------------
+  bool SkipField(io::CodedInputStream* input, uint32_t tag) override;
+  bool SkipMessage(io::CodedInputStream* input) override;
+  void SkipUnknownEnum(int field_number, int value) override;
+
+ protected:
+  io::CodedOutputStream* unknown_fields_;
+};
+
+// inline methods ====================================================
+
+inline WireFormatLite::CppType WireFormatLite::FieldTypeToCppType(
+    FieldType type) {
+  return kFieldTypeToCppTypeMap[type];
+}
+
+constexpr inline uint32_t WireFormatLite::MakeTag(int field_number,
+                                                  WireType type) {
+  return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
+}
+
+inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32_t tag) {
+  return static_cast<WireType>(tag & kTagTypeMask);
+}
+
+inline int WireFormatLite::GetTagFieldNumber(uint32_t tag) {
+  return static_cast<int>(tag >> kTagTypeBits);
+}
+
+inline size_t WireFormatLite::TagSize(int field_number,
+                                      WireFormatLite::FieldType type) {
+  size_t result = io::CodedOutputStream::VarintSize32(
+      static_cast<uint32_t>(field_number << kTagTypeBits));
+  if (type == TYPE_GROUP) {
+    // Groups have both a start and an end tag.
+    return result * 2;
+  } else {
+    return result;
+  }
+}
+
+inline uint32_t WireFormatLite::EncodeFloat(float value) {
+  return bit_cast<uint32_t>(value);
+}
+
+inline float WireFormatLite::DecodeFloat(uint32_t value) {
+  return bit_cast<float>(value);
+}
+
+inline uint64_t WireFormatLite::EncodeDouble(double value) {
+  return bit_cast<uint64_t>(value);
+}
+
+inline double WireFormatLite::DecodeDouble(uint64_t value) {
+  return bit_cast<double>(value);
+}
+
+// ZigZag Transform:  Encodes signed integers so that they can be
+// effectively used with varint encoding.
+//
+// varint operates on unsigned integers, encoding smaller numbers into
+// fewer bytes.  If you try to use it on a signed integer, it will treat
+// this number as a very large unsigned integer, which means that even
+// small signed numbers like -1 will take the maximum number of bytes
+// (10) to encode.  ZigZagEncode() maps signed integers to unsigned
+// in such a way that those with a small absolute value will have smaller
+// encoded values, making them appropriate for encoding using varint.
+//
+//       int32_t ->     uint32_t
+// -------------------------
+//           0 ->          0
+//          -1 ->          1
+//           1 ->          2
+//          -2 ->          3
+//         ... ->        ...
+//  2147483647 -> 4294967294
+// -2147483648 -> 4294967295
+//
+//        >> encode >>
+//        << decode <<
+
+inline uint32_t WireFormatLite::ZigZagEncode32(int32_t n) {
+  // Note:  the right-shift must be arithmetic
+  // Note:  left shift must be unsigned because of overflow
+  return (static_cast<uint32_t>(n) << 1) ^ static_cast<uint32_t>(n >> 31);
+}
+
+inline int32_t WireFormatLite::ZigZagDecode32(uint32_t n) {
+  // Note:  Using unsigned types prevent undefined behavior
+  return static_cast<int32_t>((n >> 1) ^ (~(n & 1) + 1));
+}
+
+inline uint64_t WireFormatLite::ZigZagEncode64(int64_t n) {
+  // Note:  the right-shift must be arithmetic
+  // Note:  left shift must be unsigned because of overflow
+  return (static_cast<uint64_t>(n) << 1) ^ static_cast<uint64_t>(n >> 63);
+}
+
+inline int64_t WireFormatLite::ZigZagDecode64(uint64_t n) {
+  // Note:  Using unsigned types prevent undefined behavior
+  return static_cast<int64_t>((n >> 1) ^ (~(n & 1) + 1));
+}
+
+// String is for UTF-8 text only, but, even so, ReadString() can simply
+// call ReadBytes().
+
+inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
+                                       std::string* value) {
+  return ReadBytes(input, value);
+}
+
+inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
+                                       std::string** p) {
+  return ReadBytes(input, p);
+}
+
+inline uint8_t* InternalSerializeUnknownMessageSetItemsToArray(
+    const std::string& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  return stream->WriteRaw(unknown_fields.data(),
+                          static_cast<int>(unknown_fields.size()), target);
+}
+
+inline size_t ComputeUnknownMessageSetItemsSize(
+    const std::string& unknown_fields) {
+  return unknown_fields.size();
+}
+
+// Implementation details of ReadPrimitive.
+
+template <>
+inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_INT32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
+  if (!input->ReadVarint32(&temp)) return false;
+  *value = static_cast<int32_t>(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_INT64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
+  if (!input->ReadVarint64(&temp)) return false;
+  *value = static_cast<int64_t>(temp);
+  return true;
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint32_t, WireFormatLite::TYPE_UINT32>(
+    io::CodedInputStream* input, uint32_t* value) {
+  return input->ReadVarint32(value);
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint64_t, WireFormatLite::TYPE_UINT64>(
+    io::CodedInputStream* input, uint64_t* value) {
+  return input->ReadVarint64(value);
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SINT32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
+  if (!input->ReadVarint32(&temp)) return false;
+  *value = ZigZagDecode32(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_SINT64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
+  if (!input->ReadVarint64(&temp)) return false;
+  *value = ZigZagDecode64(temp);
+  return true;
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint32_t, WireFormatLite::TYPE_FIXED32>(
+    io::CodedInputStream* input, uint32_t* value) {
+  return input->ReadLittleEndian32(value);
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<uint64_t, WireFormatLite::TYPE_FIXED64>(
+    io::CodedInputStream* input, uint64_t* value) {
+  return input->ReadLittleEndian64(value);
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SFIXED32>(
+    io::CodedInputStream* input, int32_t* value) {
+  uint32_t temp;
+  if (!input->ReadLittleEndian32(&temp)) return false;
+  *value = static_cast<int32_t>(temp);
+  return true;
+}
+template <>
+inline bool
+WireFormatLite::ReadPrimitive<int64_t, WireFormatLite::TYPE_SFIXED64>(
+    io::CodedInputStream* input, int64_t* value) {
+  uint64_t temp;
+  if (!input->ReadLittleEndian64(&temp)) return false;
+  *value = static_cast<int64_t>(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<float, WireFormatLite::TYPE_FLOAT>(
+    io::CodedInputStream* input, float* value) {
+  uint32_t temp;
+  if (!input->ReadLittleEndian32(&temp)) return false;
+  *value = DecodeFloat(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<double, WireFormatLite::TYPE_DOUBLE>(
+    io::CodedInputStream* input, double* value) {
+  uint64_t temp;
+  if (!input->ReadLittleEndian64(&temp)) return false;
+  *value = DecodeDouble(temp);
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
+    io::CodedInputStream* input, bool* value) {
+  uint64_t temp;
+  if (!input->ReadVarint64(&temp)) return false;
+  *value = temp != 0;
+  return true;
+}
+template <>
+inline bool WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+    io::CodedInputStream* input, int* value) {
+  uint32_t temp;
+  if (!input->ReadVarint32(&temp)) return false;
+  *value = static_cast<int>(temp);
+  return true;
+}
+
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<uint32_t, WireFormatLite::TYPE_FIXED32>(
+    const uint8_t* buffer, uint32_t* value) {
+  return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value);
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<uint64_t, WireFormatLite::TYPE_FIXED64>(
+    const uint8_t* buffer, uint64_t* value) {
+  return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value);
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<int32_t, WireFormatLite::TYPE_SFIXED32>(
+    const uint8_t* buffer, int32_t* value) {
+  uint32_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
+  *value = static_cast<int32_t>(temp);
+  return buffer;
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<int64_t, WireFormatLite::TYPE_SFIXED64>(
+    const uint8_t* buffer, int64_t* value) {
+  uint64_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
+  *value = static_cast<int64_t>(temp);
+  return buffer;
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<float, WireFormatLite::TYPE_FLOAT>(
+    const uint8_t* buffer, float* value) {
+  uint32_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp);
+  *value = DecodeFloat(temp);
+  return buffer;
+}
+template <>
+inline const uint8_t*
+WireFormatLite::ReadPrimitiveFromArray<double, WireFormatLite::TYPE_DOUBLE>(
+    const uint8_t* buffer, double* value) {
+  uint64_t temp;
+  buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp);
+  *value = DecodeDouble(temp);
+  return buffer;
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadRepeatedPrimitive(
+    int,  // tag_size, unused.
+    uint32_t tag, io::CodedInputStream* input, RepeatedField<CType>* values) {
+  CType value;
+  if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+  values->Add(value);
+  int elements_already_reserved = values->Capacity() - values->size();
+  while (elements_already_reserved > 0 && input->ExpectTag(tag)) {
+    if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+    values->AddAlreadyReserved(value);
+    elements_already_reserved--;
+  }
+  return true;
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
+    int tag_size, uint32_t tag, io::CodedInputStream* input,
+    RepeatedField<CType>* values) {
+  GOOGLE_DCHECK_EQ(UInt32Size(tag), static_cast<size_t>(tag_size));
+  CType value;
+  if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+  values->Add(value);
+
+  // For fixed size values, repeated values can be read more quickly by
+  // reading directly from a raw array.
+  //
+  // We can get a tight loop by only reading as many elements as can be
+  // added to the RepeatedField without having to do any resizing. Additionally,
+  // we only try to read as many elements as are available from the current
+  // buffer space. Doing so avoids having to perform boundary checks when
+  // reading the value: the maximum number of elements that can be read is
+  // known outside of the loop.
+  const void* void_pointer;
+  int size;
+  input->GetDirectBufferPointerInline(&void_pointer, &size);
+  if (size > 0) {
+    const uint8_t* buffer = reinterpret_cast<const uint8_t*>(void_pointer);
+    // The number of bytes each type occupies on the wire.
+    const int per_value_size = tag_size + static_cast<int>(sizeof(value));
+
+    // parentheses around (std::min) prevents macro expansion of min(...)
+    int elements_available =
+        (std::min)(values->Capacity() - values->size(), size / per_value_size);
+    int num_read = 0;
+    while (num_read < elements_available &&
+           (buffer = io::CodedInputStream::ExpectTagFromArray(buffer, tag)) !=
+               nullptr) {
+      buffer = ReadPrimitiveFromArray<CType, DeclaredType>(buffer, &value);
+      values->AddAlreadyReserved(value);
+      ++num_read;
+    }
+    const int read_bytes = num_read * per_value_size;
+    if (read_bytes > 0) {
+      input->Skip(read_bytes);
+    }
+  }
+  return true;
+}
+
+// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
+// the optimized code path.
+#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE)        \
+  template <>                                                             \
+  inline bool WireFormatLite::ReadRepeatedPrimitive<                      \
+      CPPTYPE, WireFormatLite::DECLARED_TYPE>(                            \
+      int tag_size, uint32_t tag, io::CodedInputStream* input,            \
+      RepeatedField<CPPTYPE>* values) {                                   \
+    return ReadRepeatedFixedSizePrimitive<CPPTYPE,                        \
+                                          WireFormatLite::DECLARED_TYPE>( \
+        tag_size, tag, input, values);                                    \
+  }
+
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32_t, TYPE_FIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64_t, TYPE_FIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32_t, TYPE_SFIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64_t, TYPE_SFIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
+
+#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+bool WireFormatLite::ReadRepeatedPrimitiveNoInline(
+    int tag_size, uint32_t tag, io::CodedInputStream* input,
+    RepeatedField<CType>* value) {
+  return ReadRepeatedPrimitive<CType, DeclaredType>(tag_size, tag, input,
+                                                    value);
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
+                                                RepeatedField<CType>* values) {
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    CType value;
+    if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+    values->Add(value);
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
+    io::CodedInputStream* input, RepeatedField<CType>* values) {
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
+  const int old_entries = values->size();
+  const int new_entries = length / static_cast<int>(sizeof(CType));
+  const int new_bytes = new_entries * static_cast<int>(sizeof(CType));
+  if (new_bytes != length) return false;
+  // We would *like* to pre-allocate the buffer to write into (for
+  // speed), but *must* avoid performing a very large allocation due
+  // to a malicious user-supplied "length" above.  So we have a fast
+  // path that pre-allocates when the "length" is less than a bound.
+  // We determine the bound by calling BytesUntilTotalBytesLimit() and
+  // BytesUntilLimit().  These return -1 to mean "no limit set".
+  // There are four cases:
+  // TotalBytesLimit  Limit
+  // -1               -1     Use slow path.
+  // -1               >= 0   Use fast path if length <= Limit.
+  // >= 0             -1     Use slow path.
+  // >= 0             >= 0   Use fast path if length <= min(both limits).
+  int64_t bytes_limit = input->BytesUntilTotalBytesLimit();
+  if (bytes_limit == -1) {
+    bytes_limit = input->BytesUntilLimit();
+  } else {
+    // parentheses around (std::min) prevents macro expansion of min(...)
+    bytes_limit =
+        (std::min)(bytes_limit, static_cast<int64_t>(input->BytesUntilLimit()));
+  }
+  if (bytes_limit >= new_bytes) {
+    // Fast-path that pre-allocates *values to the final size.
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+    values->Resize(old_entries + new_entries, 0);
+    // values->mutable_data() may change after Resize(), so do this after:
+    void* dest = reinterpret_cast<void*>(values->mutable_data() + old_entries);
+    if (!input->ReadRaw(dest, new_bytes)) {
+      values->Truncate(old_entries);
+      return false;
+    }
+#else
+    values->Reserve(old_entries + new_entries);
+    CType value;
+    for (int i = 0; i < new_entries; ++i) {
+      if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+      values->AddAlreadyReserved(value);
+    }
+#endif
+  } else {
+    // This is the slow-path case where "length" may be too large to
+    // safely allocate.  We read as much as we can into *values
+    // without pre-allocating "length" bytes.
+    CType value;
+    for (int i = 0; i < new_entries; ++i) {
+      if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
+      values->Add(value);
+    }
+  }
+  return true;
+}
+
+// Specializations of ReadPackedPrimitive for the fixed size types, which use
+// an optimized code path.
+#define READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE)      \
+  template <>                                                                  \
+  inline bool                                                                  \
+  WireFormatLite::ReadPackedPrimitive<CPPTYPE, WireFormatLite::DECLARED_TYPE>( \
+      io::CodedInputStream * input, RepeatedField<CPPTYPE> * values) {         \
+    return ReadPackedFixedSizePrimitive<CPPTYPE,                               \
+                                        WireFormatLite::DECLARED_TYPE>(        \
+        input, values);                                                        \
+  }
+
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32_t, TYPE_FIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64_t, TYPE_FIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32_t, TYPE_SFIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64_t, TYPE_SFIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
+
+#undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE
+
+template <typename CType, enum WireFormatLite::FieldType DeclaredType>
+bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input,
+                                                 RepeatedField<CType>* values) {
+  return ReadPackedPrimitive<CType, DeclaredType>(input, values);
+}
+
+
+template <typename MessageType>
+inline bool WireFormatLite::ReadGroup(int field_number,
+                                      io::CodedInputStream* input,
+                                      MessageType* value) {
+  if (!input->IncrementRecursionDepth()) return false;
+  if (!value->MergePartialFromCodedStream(input)) return false;
+  input->UnsafeDecrementRecursionDepth();
+  // Make sure the last thing read was an end tag for this group.
+  if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) {
+    return false;
+  }
+  return true;
+}
+template <typename MessageType>
+inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input,
+                                        MessageType* value) {
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
+  std::pair<io::CodedInputStream::Limit, int> p =
+      input->IncrementRecursionDepthAndPushLimit(length);
+  if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false;
+  // Make sure that parsing stopped when the limit was hit, not at an endgroup
+  // tag.
+  return input->DecrementRecursionDepthAndPopLimit(p.first);
+}
+
+// ===================================================================
+
+inline void WireFormatLite::WriteTag(int field_number, WireType type,
+                                     io::CodedOutputStream* output) {
+  output->WriteTag(MakeTag(field_number, type));
+}
+
+inline void WireFormatLite::WriteInt32NoTag(int32_t value,
+                                            io::CodedOutputStream* output) {
+  output->WriteVarint32SignExtended(value);
+}
+inline void WireFormatLite::WriteInt64NoTag(int64_t value,
+                                            io::CodedOutputStream* output) {
+  output->WriteVarint64(static_cast<uint64_t>(value));
+}
+inline void WireFormatLite::WriteUInt32NoTag(uint32_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint32(value);
+}
+inline void WireFormatLite::WriteUInt64NoTag(uint64_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint64(value);
+}
+inline void WireFormatLite::WriteSInt32NoTag(int32_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint32(ZigZagEncode32(value));
+}
+inline void WireFormatLite::WriteSInt64NoTag(int64_t value,
+                                             io::CodedOutputStream* output) {
+  output->WriteVarint64(ZigZagEncode64(value));
+}
+inline void WireFormatLite::WriteFixed32NoTag(uint32_t value,
+                                              io::CodedOutputStream* output) {
+  output->WriteLittleEndian32(value);
+}
+inline void WireFormatLite::WriteFixed64NoTag(uint64_t value,
+                                              io::CodedOutputStream* output) {
+  output->WriteLittleEndian64(value);
+}
+inline void WireFormatLite::WriteSFixed32NoTag(int32_t value,
+                                               io::CodedOutputStream* output) {
+  output->WriteLittleEndian32(static_cast<uint32_t>(value));
+}
+inline void WireFormatLite::WriteSFixed64NoTag(int64_t value,
+                                               io::CodedOutputStream* output) {
+  output->WriteLittleEndian64(static_cast<uint64_t>(value));
+}
+inline void WireFormatLite::WriteFloatNoTag(float value,
+                                            io::CodedOutputStream* output) {
+  output->WriteLittleEndian32(EncodeFloat(value));
+}
+inline void WireFormatLite::WriteDoubleNoTag(double value,
+                                             io::CodedOutputStream* output) {
+  output->WriteLittleEndian64(EncodeDouble(value));
+}
+inline void WireFormatLite::WriteBoolNoTag(bool value,
+                                           io::CodedOutputStream* output) {
+  output->WriteVarint32(value ? 1 : 0);
+}
+inline void WireFormatLite::WriteEnumNoTag(int value,
+                                           io::CodedOutputStream* output) {
+  output->WriteVarint32SignExtended(value);
+}
+
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline void WireFormatLite::WriteGroupNoVirtual(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_START_GROUP, output);
+  value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
+  WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline void WireFormatLite::WriteMessageNoVirtual(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  output->WriteVarint32(
+      value.MessageType_WorkAroundCppLookupDefect::GetCachedSize());
+  value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output);
+}
+
+// ===================================================================
+
+inline uint8_t* WireFormatLite::WriteTagToArray(int field_number, WireType type,
+                                                uint8_t* target) {
+  return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type),
+                                                target);
+}
+
+inline uint8_t* WireFormatLite::WriteInt32NoTagToArray(int32_t value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(int64_t value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(
+      static_cast<uint64_t>(value), target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32NoTagToArray(uint32_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64NoTagToArray(uint64_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32NoTagToArray(int32_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value),
+                                                     target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64NoTagToArray(int64_t value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value),
+                                                     target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(uint32_t value,
+                                                         uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64NoTagToArray(uint64_t value,
+                                                         uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(int32_t value,
+                                                          uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian32ToArray(
+      static_cast<uint32_t>(value), target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64NoTagToArray(int64_t value,
+                                                          uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian64ToArray(
+      static_cast<uint64_t>(value), target);
+}
+inline uint8_t* WireFormatLite::WriteFloatNoTagToArray(float value,
+                                                       uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value),
+                                                           target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleNoTagToArray(double value,
+                                                        uint8_t* target) {
+  return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value),
+                                                           target);
+}
+inline uint8_t* WireFormatLite::WriteBoolNoTagToArray(bool value,
+                                                      uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumNoTagToArray(int value,
+                                                      uint8_t* target) {
+  return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target);
+}
+
+template <typename T>
+inline uint8_t* WireFormatLite::WritePrimitiveNoTagToArray(
+    const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+    uint8_t* target) {
+  const int n = value.size();
+  GOOGLE_DCHECK_GT(n, 0);
+
+  const T* ii = value.data();
+  int i = 0;
+  do {
+    target = Writer(ii[i], target);
+  } while (++i < n);
+
+  return target;
+}
+
+template <typename T>
+inline uint8_t* WireFormatLite::WriteFixedNoTagToArray(
+    const RepeatedField<T>& value, uint8_t* (*Writer)(T, uint8_t*),
+    uint8_t* target) {
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+  (void)Writer;
+
+  const int n = value.size();
+  GOOGLE_DCHECK_GT(n, 0);
+
+  const T* ii = value.data();
+  const int bytes = n * static_cast<int>(sizeof(ii[0]));
+  memcpy(target, ii, static_cast<size_t>(bytes));
+  return target + bytes;
+#else
+  return WritePrimitiveNoTagToArray(value, Writer, target);
+#endif
+}
+
+inline uint8_t* WireFormatLite::WriteInt32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteInt32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteInt64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32NoTagToArray(
+    const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteUInt32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64NoTagToArray(
+    const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteUInt64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteSInt32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteSInt64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(
+    const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteFixed32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64NoTagToArray(
+    const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteFixed64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(
+    const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteSFixed32NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64NoTagToArray(
+    const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteSFixed64NoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFloatNoTagToArray(
+    const RepeatedField<float>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteFloatNoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleNoTagToArray(
+    const RepeatedField<double>& value, uint8_t* target) {
+  return WriteFixedNoTagToArray(value, WriteDoubleNoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteBoolNoTagToArray(
+    const RepeatedField<bool>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteBoolNoTagToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumNoTagToArray(
+    const RepeatedField<int>& value, uint8_t* target) {
+  return WritePrimitiveNoTagToArray(value, WriteEnumNoTagToArray, target);
+}
+
+inline uint8_t* WireFormatLite::WriteInt32ToArray(int field_number,
+                                                  int32_t value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteInt32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64ToArray(int field_number,
+                                                  int64_t value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteInt64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32ToArray(int field_number,
+                                                   uint32_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteUInt32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64ToArray(int field_number,
+                                                   uint64_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteUInt64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32ToArray(int field_number,
+                                                   int32_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteSInt32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64ToArray(int field_number,
+                                                   int64_t value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteSInt64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32ToArray(int field_number,
+                                                    uint32_t value,
+                                                    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
+  return WriteFixed32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64ToArray(int field_number,
+                                                    uint64_t value,
+                                                    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
+  return WriteFixed64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32ToArray(int field_number,
+                                                     int32_t value,
+                                                     uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
+  return WriteSFixed32NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64ToArray(int field_number,
+                                                     int64_t value,
+                                                     uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
+  return WriteSFixed64NoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteFloatToArray(int field_number, float value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target);
+  return WriteFloatNoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleToArray(int field_number,
+                                                   double value,
+                                                   uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target);
+  return WriteDoubleNoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteBoolToArray(int field_number, bool value,
+                                                 uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteBoolNoTagToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumToArray(int field_number, int value,
+                                                 uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_VARINT, target);
+  return WriteEnumNoTagToArray(value, target);
+}
+
+template <typename T>
+inline uint8_t* WireFormatLite::WritePrimitiveToArray(
+    int field_number, const RepeatedField<T>& value,
+    uint8_t* (*Writer)(int, T, uint8_t*), uint8_t* target) {
+  const int n = value.size();
+  if (n == 0) {
+    return target;
+  }
+
+  const T* ii = value.data();
+  int i = 0;
+  do {
+    target = Writer(field_number, ii[i], target);
+  } while (++i < n);
+
+  return target;
+}
+
+inline uint8_t* WireFormatLite::WriteInt32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteInt32ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteInt64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteInt64ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt32ToArray(
+    int field_number, const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteUInt32ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteUInt64ToArray(
+    int field_number, const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteUInt64ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSInt32ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteSInt64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSInt64ToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteFixed32ToArray(
+    int field_number, const RepeatedField<uint32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteFixed32ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteFixed64ToArray(
+    int field_number, const RepeatedField<uint64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteFixed64ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed32ToArray(
+    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSFixed32ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteSFixed64ToArray(
+    int field_number, const RepeatedField<int64_t>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteSFixed64ToArray,
+                               target);
+}
+inline uint8_t* WireFormatLite::WriteFloatToArray(
+    int field_number, const RepeatedField<float>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteFloatToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteDoubleToArray(
+    int field_number, const RepeatedField<double>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteDoubleToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteBoolToArray(
+    int field_number, const RepeatedField<bool>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteBoolToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteEnumToArray(
+    int field_number, const RepeatedField<int>& value, uint8_t* target) {
+  return WritePrimitiveToArray(field_number, value, WriteEnumToArray, target);
+}
+inline uint8_t* WireFormatLite::WriteStringToArray(int field_number,
+                                                   const std::string& value,
+                                                   uint8_t* target) {
+  // String is for UTF-8 text only
+  // WARNING:  In wire_format.cc, both strings and bytes are handled by
+  //   WriteString() to avoid code duplication.  If the implementations become
+  //   different, you will need to update that usage.
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
+}
+inline uint8_t* WireFormatLite::WriteBytesToArray(int field_number,
+                                                  const std::string& value,
+                                                  uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  return io::CodedOutputStream::WriteStringWithSizeToArray(value, target);
+}
+
+
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline uint8_t* WireFormatLite::InternalWriteGroupNoVirtualToArray(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
+  target = value.MessageType_WorkAroundCppLookupDefect::
+               SerializeWithCachedSizesToArray(target);
+  return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
+}
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline uint8_t* WireFormatLite::InternalWriteMessageNoVirtualToArray(
+    int field_number, const MessageType_WorkAroundCppLookupDefect& value,
+    uint8_t* target) {
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(
+      static_cast<uint32_t>(
+          value.MessageType_WorkAroundCppLookupDefect::GetCachedSize()),
+      target);
+  return value
+      .MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizesToArray(
+          target);
+}
+
+// ===================================================================
+
+inline size_t WireFormatLite::Int32Size(int32_t value) {
+  return io::CodedOutputStream::VarintSize32SignExtended(value);
+}
+inline size_t WireFormatLite::Int64Size(int64_t value) {
+  return io::CodedOutputStream::VarintSize64(static_cast<uint64_t>(value));
+}
+inline size_t WireFormatLite::UInt32Size(uint32_t value) {
+  return io::CodedOutputStream::VarintSize32(value);
+}
+inline size_t WireFormatLite::UInt64Size(uint64_t value) {
+  return io::CodedOutputStream::VarintSize64(value);
+}
+inline size_t WireFormatLite::SInt32Size(int32_t value) {
+  return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value));
+}
+inline size_t WireFormatLite::SInt64Size(int64_t value) {
+  return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value));
+}
+inline size_t WireFormatLite::EnumSize(int value) {
+  return io::CodedOutputStream::VarintSize32SignExtended(value);
+}
+inline size_t WireFormatLite::Int32SizePlusOne(int32_t value) {
+  return io::CodedOutputStream::VarintSize32SignExtendedPlusOne(value);
+}
+inline size_t WireFormatLite::Int64SizePlusOne(int64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(
+      static_cast<uint64_t>(value));
+}
+inline size_t WireFormatLite::UInt32SizePlusOne(uint32_t value) {
+  return io::CodedOutputStream::VarintSize32PlusOne(value);
+}
+inline size_t WireFormatLite::UInt64SizePlusOne(uint64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(value);
+}
+inline size_t WireFormatLite::SInt32SizePlusOne(int32_t value) {
+  return io::CodedOutputStream::VarintSize32PlusOne(ZigZagEncode32(value));
+}
+inline size_t WireFormatLite::SInt64SizePlusOne(int64_t value) {
+  return io::CodedOutputStream::VarintSize64PlusOne(ZigZagEncode64(value));
+}
+inline size_t WireFormatLite::EnumSizePlusOne(int value) {
+  return io::CodedOutputStream::VarintSize32SignExtendedPlusOne(value);
+}
+
+inline size_t WireFormatLite::StringSize(const std::string& value) {
+  return LengthDelimitedSize(value.size());
+}
+inline size_t WireFormatLite::BytesSize(const std::string& value) {
+  return LengthDelimitedSize(value.size());
+}
+
+
+template <typename MessageType>
+inline size_t WireFormatLite::GroupSize(const MessageType& value) {
+  return value.ByteSizeLong();
+}
+template <typename MessageType>
+inline size_t WireFormatLite::MessageSize(const MessageType& value) {
+  return LengthDelimitedSize(value.ByteSizeLong());
+}
+
+// See comment on ReadGroupNoVirtual to understand the need for this template
+// parameter name.
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline size_t WireFormatLite::GroupSizeNoVirtual(
+    const MessageType_WorkAroundCppLookupDefect& value) {
+  return value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong();
+}
+template <typename MessageType_WorkAroundCppLookupDefect>
+inline size_t WireFormatLite::MessageSizeNoVirtual(
+    const MessageType_WorkAroundCppLookupDefect& value) {
+  return LengthDelimitedSize(
+      value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong());
+}
+
+inline size_t WireFormatLite::LengthDelimitedSize(size_t length) {
+  // The static_cast here prevents an error in certain compiler configurations
+  // but is not technically correct--if length is too large to fit in a uint32_t
+  // then it will be silently truncated. We will need to fix this if we ever
+  // decide to start supporting serialized messages greater than 2 GiB in size.
+  return length +
+         io::CodedOutputStream::VarintSize32(static_cast<uint32_t>(length));
+}
+
+template <typename MS>
+bool ParseMessageSetItemImpl(io::CodedInputStream* input, MS ms) {
+  // This method parses a group which should contain two fields:
+  //   required int32 type_id = 2;
+  //   required data message = 3;
+
+  uint32_t last_type_id = 0;
+
+  // If we see message data before the type_id, we'll append it to this so
+  // we can parse it later.
+  std::string message_data;
+
+  enum class State { kNoTag, kHasType, kHasPayload, kDone };
+  State state = State::kNoTag;
+
+  while (true) {
+    const uint32_t tag = input->ReadTagNoLastTag();
+    if (tag == 0) return false;
+
+    switch (tag) {
+      case WireFormatLite::kMessageSetTypeIdTag: {
+        uint32_t type_id;
+        if (!input->ReadVarint32(&type_id)) return false;
+        if (state == State::kNoTag) {
+          last_type_id = type_id;
+          state = State::kHasType;
+        } else if (state == State::kHasPayload) {
+          // We saw some message data before the type_id.  Have to parse it
+          // now.
+          io::CodedInputStream sub_input(
+              reinterpret_cast<const uint8_t*>(message_data.data()),
+              static_cast<int>(message_data.size()));
+          sub_input.SetRecursionLimit(input->RecursionBudget());
+          if (!ms.ParseField(type_id, &sub_input)) {
+            return false;
+          }
+          message_data.clear();
+          state = State::kDone;
+        }
+
+        break;
+      }
+
+      case WireFormatLite::kMessageSetMessageTag: {
+        if (state == State::kHasType) {
+          // Already saw type_id, so we can parse this directly.
+          if (!ms.ParseField(last_type_id, input)) {
+            return false;
+          }
+          state = State::kDone;
+        } else if (state == State::kNoTag) {
+          // We haven't seen a type_id yet.  Append this data to message_data.
+          uint32_t length;
+          if (!input->ReadVarint32(&length)) return false;
+          if (static_cast<int32_t>(length) < 0) return false;
+          uint32_t size = static_cast<uint32_t>(
+              length + io::CodedOutputStream::VarintSize32(length));
+          message_data.resize(size);
+          auto ptr = reinterpret_cast<uint8_t*>(&message_data[0]);
+          ptr = io::CodedOutputStream::WriteVarint32ToArray(length, ptr);
+          if (!input->ReadRaw(ptr, length)) return false;
+          state = State::kHasPayload;
+        } else {
+          if (!ms.SkipField(tag, input)) return false;
+        }
+
+        break;
+      }
+
+      case WireFormatLite::kMessageSetItemEndTag: {
+        return true;
+      }
+
+      default: {
+        if (!ms.SkipField(tag, input)) return false;
+      }
+    }
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wrappers.pb.h b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wrappers.pb.h
new file mode 100644
index 0000000..0f4b835
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/include/google/protobuf/wrappers.pb.h
@@ -0,0 +1,1741 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fwrappers_2eproto
+#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fwrappers_2eproto
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#if PROTOBUF_VERSION < 3021000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fwrappers_2eproto PROTOBUF_EXPORT
+PROTOBUF_NAMESPACE_OPEN
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+PROTOBUF_NAMESPACE_CLOSE
+
+// Internal implementation detail -- do not use these members.
+struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fwrappers_2eproto {
+  static const uint32_t offsets[];
+};
+PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto;
+PROTOBUF_NAMESPACE_OPEN
+class BoolValue;
+struct BoolValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern BoolValueDefaultTypeInternal _BoolValue_default_instance_;
+class BytesValue;
+struct BytesValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern BytesValueDefaultTypeInternal _BytesValue_default_instance_;
+class DoubleValue;
+struct DoubleValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern DoubleValueDefaultTypeInternal _DoubleValue_default_instance_;
+class FloatValue;
+struct FloatValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern FloatValueDefaultTypeInternal _FloatValue_default_instance_;
+class Int32Value;
+struct Int32ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern Int32ValueDefaultTypeInternal _Int32Value_default_instance_;
+class Int64Value;
+struct Int64ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern Int64ValueDefaultTypeInternal _Int64Value_default_instance_;
+class StringValue;
+struct StringValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern StringValueDefaultTypeInternal _StringValue_default_instance_;
+class UInt32Value;
+struct UInt32ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern UInt32ValueDefaultTypeInternal _UInt32Value_default_instance_;
+class UInt64Value;
+struct UInt64ValueDefaultTypeInternal;
+PROTOBUF_EXPORT extern UInt64ValueDefaultTypeInternal _UInt64Value_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::BoolValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::BoolValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::BytesValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::BytesValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::DoubleValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::DoubleValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FloatValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FloatValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Int32Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Int32Value>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Int64Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Int64Value>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::StringValue* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::StringValue>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UInt32Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UInt32Value>(Arena*);
+template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::UInt64Value* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::UInt64Value>(Arena*);
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class PROTOBUF_EXPORT DoubleValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DoubleValue) */ {
+ public:
+  inline DoubleValue() : DoubleValue(nullptr) {}
+  ~DoubleValue() override;
+  explicit PROTOBUF_CONSTEXPR DoubleValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  DoubleValue(const DoubleValue& from);
+  DoubleValue(DoubleValue&& from) noexcept
+    : DoubleValue() {
+    *this = ::std::move(from);
+  }
+
+  inline DoubleValue& operator=(const DoubleValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline DoubleValue& operator=(DoubleValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const DoubleValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const DoubleValue* internal_default_instance() {
+    return reinterpret_cast<const DoubleValue*>(
+               &_DoubleValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    0;
+
+  friend void swap(DoubleValue& a, DoubleValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(DoubleValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DoubleValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  DoubleValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<DoubleValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const DoubleValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const DoubleValue& from) {
+    DoubleValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(DoubleValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.DoubleValue";
+  }
+  protected:
+  explicit DoubleValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // double value = 1;
+  void clear_value();
+  double value() const;
+  void set_value(double value);
+  private:
+  double _internal_value() const;
+  void _internal_set_value(double value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DoubleValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    double value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT FloatValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FloatValue) */ {
+ public:
+  inline FloatValue() : FloatValue(nullptr) {}
+  ~FloatValue() override;
+  explicit PROTOBUF_CONSTEXPR FloatValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  FloatValue(const FloatValue& from);
+  FloatValue(FloatValue&& from) noexcept
+    : FloatValue() {
+    *this = ::std::move(from);
+  }
+
+  inline FloatValue& operator=(const FloatValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline FloatValue& operator=(FloatValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const FloatValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const FloatValue* internal_default_instance() {
+    return reinterpret_cast<const FloatValue*>(
+               &_FloatValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    1;
+
+  friend void swap(FloatValue& a, FloatValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(FloatValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FloatValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  FloatValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<FloatValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const FloatValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const FloatValue& from) {
+    FloatValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(FloatValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.FloatValue";
+  }
+  protected:
+  explicit FloatValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // float value = 1;
+  void clear_value();
+  float value() const;
+  void set_value(float value);
+  private:
+  float _internal_value() const;
+  void _internal_set_value(float value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FloatValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    float value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Int64Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int64Value) */ {
+ public:
+  inline Int64Value() : Int64Value(nullptr) {}
+  ~Int64Value() override;
+  explicit PROTOBUF_CONSTEXPR Int64Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Int64Value(const Int64Value& from);
+  Int64Value(Int64Value&& from) noexcept
+    : Int64Value() {
+    *this = ::std::move(from);
+  }
+
+  inline Int64Value& operator=(const Int64Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Int64Value& operator=(Int64Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Int64Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Int64Value* internal_default_instance() {
+    return reinterpret_cast<const Int64Value*>(
+               &_Int64Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    2;
+
+  friend void swap(Int64Value& a, Int64Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Int64Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Int64Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Int64Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Int64Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Int64Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Int64Value& from) {
+    Int64Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Int64Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Int64Value";
+  }
+  protected:
+  explicit Int64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // int64 value = 1;
+  void clear_value();
+  int64_t value() const;
+  void set_value(int64_t value);
+  private:
+  int64_t _internal_value() const;
+  void _internal_set_value(int64_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Int64Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int64_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UInt64Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt64Value) */ {
+ public:
+  inline UInt64Value() : UInt64Value(nullptr) {}
+  ~UInt64Value() override;
+  explicit PROTOBUF_CONSTEXPR UInt64Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UInt64Value(const UInt64Value& from);
+  UInt64Value(UInt64Value&& from) noexcept
+    : UInt64Value() {
+    *this = ::std::move(from);
+  }
+
+  inline UInt64Value& operator=(const UInt64Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UInt64Value& operator=(UInt64Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UInt64Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UInt64Value* internal_default_instance() {
+    return reinterpret_cast<const UInt64Value*>(
+               &_UInt64Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    3;
+
+  friend void swap(UInt64Value& a, UInt64Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UInt64Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UInt64Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UInt64Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UInt64Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UInt64Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UInt64Value& from) {
+    UInt64Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UInt64Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UInt64Value";
+  }
+  protected:
+  explicit UInt64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // uint64 value = 1;
+  void clear_value();
+  uint64_t value() const;
+  void set_value(uint64_t value);
+  private:
+  uint64_t _internal_value() const;
+  void _internal_set_value(uint64_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UInt64Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    uint64_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT Int32Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int32Value) */ {
+ public:
+  inline Int32Value() : Int32Value(nullptr) {}
+  ~Int32Value() override;
+  explicit PROTOBUF_CONSTEXPR Int32Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  Int32Value(const Int32Value& from);
+  Int32Value(Int32Value&& from) noexcept
+    : Int32Value() {
+    *this = ::std::move(from);
+  }
+
+  inline Int32Value& operator=(const Int32Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline Int32Value& operator=(Int32Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const Int32Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const Int32Value* internal_default_instance() {
+    return reinterpret_cast<const Int32Value*>(
+               &_Int32Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    4;
+
+  friend void swap(Int32Value& a, Int32Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(Int32Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Int32Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  Int32Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<Int32Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const Int32Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const Int32Value& from) {
+    Int32Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(Int32Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.Int32Value";
+  }
+  protected:
+  explicit Int32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // int32 value = 1;
+  void clear_value();
+  int32_t value() const;
+  void set_value(int32_t value);
+  private:
+  int32_t _internal_value() const;
+  void _internal_set_value(int32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Int32Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    int32_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT UInt32Value final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt32Value) */ {
+ public:
+  inline UInt32Value() : UInt32Value(nullptr) {}
+  ~UInt32Value() override;
+  explicit PROTOBUF_CONSTEXPR UInt32Value(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  UInt32Value(const UInt32Value& from);
+  UInt32Value(UInt32Value&& from) noexcept
+    : UInt32Value() {
+    *this = ::std::move(from);
+  }
+
+  inline UInt32Value& operator=(const UInt32Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline UInt32Value& operator=(UInt32Value&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const UInt32Value& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const UInt32Value* internal_default_instance() {
+    return reinterpret_cast<const UInt32Value*>(
+               &_UInt32Value_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    5;
+
+  friend void swap(UInt32Value& a, UInt32Value& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(UInt32Value* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UInt32Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  UInt32Value* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<UInt32Value>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const UInt32Value& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const UInt32Value& from) {
+    UInt32Value::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(UInt32Value* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.UInt32Value";
+  }
+  protected:
+  explicit UInt32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // uint32 value = 1;
+  void clear_value();
+  uint32_t value() const;
+  void set_value(uint32_t value);
+  private:
+  uint32_t _internal_value() const;
+  void _internal_set_value(uint32_t value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UInt32Value)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    uint32_t value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT BoolValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BoolValue) */ {
+ public:
+  inline BoolValue() : BoolValue(nullptr) {}
+  ~BoolValue() override;
+  explicit PROTOBUF_CONSTEXPR BoolValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  BoolValue(const BoolValue& from);
+  BoolValue(BoolValue&& from) noexcept
+    : BoolValue() {
+    *this = ::std::move(from);
+  }
+
+  inline BoolValue& operator=(const BoolValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline BoolValue& operator=(BoolValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const BoolValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const BoolValue* internal_default_instance() {
+    return reinterpret_cast<const BoolValue*>(
+               &_BoolValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    6;
+
+  friend void swap(BoolValue& a, BoolValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(BoolValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(BoolValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  BoolValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<BoolValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const BoolValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const BoolValue& from) {
+    BoolValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(BoolValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.BoolValue";
+  }
+  protected:
+  explicit BoolValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // bool value = 1;
+  void clear_value();
+  bool value() const;
+  void set_value(bool value);
+  private:
+  bool _internal_value() const;
+  void _internal_set_value(bool value);
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.BoolValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    bool value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT StringValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.StringValue) */ {
+ public:
+  inline StringValue() : StringValue(nullptr) {}
+  ~StringValue() override;
+  explicit PROTOBUF_CONSTEXPR StringValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  StringValue(const StringValue& from);
+  StringValue(StringValue&& from) noexcept
+    : StringValue() {
+    *this = ::std::move(from);
+  }
+
+  inline StringValue& operator=(const StringValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline StringValue& operator=(StringValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const StringValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const StringValue* internal_default_instance() {
+    return reinterpret_cast<const StringValue*>(
+               &_StringValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    7;
+
+  friend void swap(StringValue& a, StringValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(StringValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(StringValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  StringValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<StringValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const StringValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const StringValue& from) {
+    StringValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(StringValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.StringValue";
+  }
+  protected:
+  explicit StringValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // string value = 1;
+  void clear_value();
+  const std::string& value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_value();
+  PROTOBUF_NODISCARD std::string* release_value();
+  void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.StringValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// -------------------------------------------------------------------
+
+class PROTOBUF_EXPORT BytesValue final :
+    public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BytesValue) */ {
+ public:
+  inline BytesValue() : BytesValue(nullptr) {}
+  ~BytesValue() override;
+  explicit PROTOBUF_CONSTEXPR BytesValue(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
+
+  BytesValue(const BytesValue& from);
+  BytesValue(BytesValue&& from) noexcept
+    : BytesValue() {
+    *this = ::std::move(from);
+  }
+
+  inline BytesValue& operator=(const BytesValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  inline BytesValue& operator=(BytesValue&& from) noexcept {
+    if (this == &from) return *this;
+    if (GetOwningArena() == from.GetOwningArena()
+  #ifdef PROTOBUF_FORCE_COPY_IN_MOVE
+        && GetOwningArena() != nullptr
+  #endif  // !PROTOBUF_FORCE_COPY_IN_MOVE
+    ) {
+      InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
+    return GetDescriptor();
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
+    return default_instance().GetMetadata().descriptor;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
+    return default_instance().GetMetadata().reflection;
+  }
+  static const BytesValue& default_instance() {
+    return *internal_default_instance();
+  }
+  static inline const BytesValue* internal_default_instance() {
+    return reinterpret_cast<const BytesValue*>(
+               &_BytesValue_default_instance_);
+  }
+  static constexpr int kIndexInFileMessages =
+    8;
+
+  friend void swap(BytesValue& a, BytesValue& b) {
+    a.Swap(&b);
+  }
+  inline void Swap(BytesValue* other) {
+    if (other == this) return;
+  #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() != nullptr &&
+        GetOwningArena() == other->GetOwningArena()) {
+   #else  // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetOwningArena() == other->GetOwningArena()) {
+  #endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(BytesValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
+    InternalSwap(other);
+  }
+
+  // implements Message ----------------------------------------------
+
+  BytesValue* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
+    return CreateMaybeMessage<BytesValue>(arena);
+  }
+  using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
+  void CopyFrom(const BytesValue& from);
+  using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
+  void MergeFrom( const BytesValue& from) {
+    BytesValue::MergeImpl(*this, from);
+  }
+  private:
+  static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
+  public:
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
+  bool IsInitialized() const final;
+
+  size_t ByteSizeLong() const final;
+  const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
+  uint8_t* _InternalSerialize(
+      uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
+  int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
+
+  private:
+  void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
+  void SharedDtor();
+  void SetCachedSize(int size) const final;
+  void InternalSwap(BytesValue* other);
+
+  private:
+  friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
+  static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
+    return "google.protobuf.BytesValue";
+  }
+  protected:
+  explicit BytesValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                       bool is_message_owned = false);
+  public:
+
+  static const ClassData _class_data_;
+  const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
+
+  ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  enum : int {
+    kValueFieldNumber = 1,
+  };
+  // bytes value = 1;
+  void clear_value();
+  const std::string& value() const;
+  template <typename ArgT0 = const std::string&, typename... ArgT>
+  void set_value(ArgT0&& arg0, ArgT... args);
+  std::string* mutable_value();
+  PROTOBUF_NODISCARD std::string* release_value();
+  void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.BytesValue)
+ private:
+  class _Internal;
+
+  template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  struct Impl_ {
+    ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
+    mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
+  };
+  union { Impl_ _impl_; };
+  friend struct ::TableStruct_google_2fprotobuf_2fwrappers_2eproto;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// DoubleValue
+
+// double value = 1;
+inline void DoubleValue::clear_value() {
+  _impl_.value_ = 0;
+}
+inline double DoubleValue::_internal_value() const {
+  return _impl_.value_;
+}
+inline double DoubleValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DoubleValue.value)
+  return _internal_value();
+}
+inline void DoubleValue::_internal_set_value(double value) {
+  
+  _impl_.value_ = value;
+}
+inline void DoubleValue::set_value(double value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DoubleValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// FloatValue
+
+// float value = 1;
+inline void FloatValue::clear_value() {
+  _impl_.value_ = 0;
+}
+inline float FloatValue::_internal_value() const {
+  return _impl_.value_;
+}
+inline float FloatValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FloatValue.value)
+  return _internal_value();
+}
+inline void FloatValue::_internal_set_value(float value) {
+  
+  _impl_.value_ = value;
+}
+inline void FloatValue::set_value(float value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FloatValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// Int64Value
+
+// int64 value = 1;
+inline void Int64Value::clear_value() {
+  _impl_.value_ = int64_t{0};
+}
+inline int64_t Int64Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline int64_t Int64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int64Value.value)
+  return _internal_value();
+}
+inline void Int64Value::_internal_set_value(int64_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void Int64Value::set_value(int64_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Int64Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// UInt64Value
+
+// uint64 value = 1;
+inline void UInt64Value::clear_value() {
+  _impl_.value_ = uint64_t{0u};
+}
+inline uint64_t UInt64Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline uint64_t UInt64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt64Value.value)
+  return _internal_value();
+}
+inline void UInt64Value::_internal_set_value(uint64_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void UInt64Value::set_value(uint64_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt64Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// Int32Value
+
+// int32 value = 1;
+inline void Int32Value::clear_value() {
+  _impl_.value_ = 0;
+}
+inline int32_t Int32Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline int32_t Int32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int32Value.value)
+  return _internal_value();
+}
+inline void Int32Value::_internal_set_value(int32_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void Int32Value::set_value(int32_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Int32Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// UInt32Value
+
+// uint32 value = 1;
+inline void UInt32Value::clear_value() {
+  _impl_.value_ = 0u;
+}
+inline uint32_t UInt32Value::_internal_value() const {
+  return _impl_.value_;
+}
+inline uint32_t UInt32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt32Value.value)
+  return _internal_value();
+}
+inline void UInt32Value::_internal_set_value(uint32_t value) {
+  
+  _impl_.value_ = value;
+}
+inline void UInt32Value::set_value(uint32_t value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt32Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// BoolValue
+
+// bool value = 1;
+inline void BoolValue::clear_value() {
+  _impl_.value_ = false;
+}
+inline bool BoolValue::_internal_value() const {
+  return _impl_.value_;
+}
+inline bool BoolValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BoolValue.value)
+  return _internal_value();
+}
+inline void BoolValue::_internal_set_value(bool value) {
+  
+  _impl_.value_ = value;
+}
+inline void BoolValue::set_value(bool value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.BoolValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// StringValue
+
+// string value = 1;
+inline void StringValue::clear_value() {
+  _impl_.value_.ClearToEmpty();
+}
+inline const std::string& StringValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
+  return _internal_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void StringValue::set_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.value_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
+}
+inline std::string* StringValue::mutable_value() {
+  std::string* _s = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
+  return _s;
+}
+inline const std::string& StringValue::_internal_value() const {
+  return _impl_.value_.Get();
+}
+inline void StringValue::_internal_set_value(const std::string& value) {
+  
+  _impl_.value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* StringValue::_internal_mutable_value() {
+  
+  return _impl_.value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* StringValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value)
+  return _impl_.value_.Release();
+}
+inline void StringValue::set_allocated_value(std::string* value) {
+  if (value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.value_.SetAllocated(value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.value_.IsDefault()) {
+    _impl_.value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// BytesValue
+
+// bytes value = 1;
+inline void BytesValue::clear_value() {
+  _impl_.value_.ClearToEmpty();
+}
+inline const std::string& BytesValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
+  return _internal_value();
+}
+template <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void BytesValue::set_value(ArgT0&& arg0, ArgT... args) {
+ 
+ _impl_.value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
+  // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
+}
+inline std::string* BytesValue::mutable_value() {
+  std::string* _s = _internal_mutable_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
+  return _s;
+}
+inline const std::string& BytesValue::_internal_value() const {
+  return _impl_.value_.Get();
+}
+inline void BytesValue::_internal_set_value(const std::string& value) {
+  
+  _impl_.value_.Set(value, GetArenaForAllocation());
+}
+inline std::string* BytesValue::_internal_mutable_value() {
+  
+  return _impl_.value_.Mutable(GetArenaForAllocation());
+}
+inline std::string* BytesValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value)
+  return _impl_.value_.Release();
+}
+inline void BytesValue::set_allocated_value(std::string* value) {
+  if (value != nullptr) {
+    
+  } else {
+    
+  }
+  _impl_.value_.SetAllocated(value, GetArenaForAllocation());
+#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (_impl_.value_.IsDefault()) {
+    _impl_.value_.Set("", GetArenaForAllocation());
+  }
+#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fwrappers_2eproto
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/any.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/any.cpp
new file mode 100644
index 0000000..346fa19
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/any.cpp
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/any.h>
+
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+bool AnyMetadata::PackFrom(Arena* arena, const Message& message) {
+  return PackFrom(arena, message, kTypeGoogleApisComPrefix);
+}
+
+bool AnyMetadata::PackFrom(Arena* arena, const Message& message,
+                           StringPiece type_url_prefix) {
+  type_url_->Set(
+      GetTypeUrl(message.GetDescriptor()->full_name(), type_url_prefix), arena);
+  return message.SerializeToString(value_->Mutable(arena));
+}
+
+bool AnyMetadata::UnpackTo(Message* message) const {
+  if (!InternalIs(message->GetDescriptor()->full_name())) {
+    return false;
+  }
+  return message->ParseFromString(value_->Get());
+}
+
+bool GetAnyFieldDescriptors(const Message& message,
+                            const FieldDescriptor** type_url_field,
+                            const FieldDescriptor** value_field) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  if (descriptor->full_name() != kAnyFullTypeName) {
+    return false;
+  }
+  *type_url_field = descriptor->FindFieldByNumber(1);
+  *value_field = descriptor->FindFieldByNumber(2);
+  return (*type_url_field != nullptr &&
+          (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
+          *value_field != nullptr &&
+          (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/any.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/any.pb.cpp
new file mode 100644
index 0000000..c02f9eb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/any.pb.cpp
@@ -0,0 +1,368 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#include <google/protobuf/any.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+#if defined(__llvm__)
+  #pragma clang diagnostic push
+  #pragma clang diagnostic ignored "-Wuninitialized"
+#endif  // __llvm__
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Any::Any(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}} {}
+struct AnyDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR AnyDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~AnyDefaultTypeInternal() {}
+  union {
+    Any _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 AnyDefaultTypeInternal _Any_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fany_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _impl_.type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _impl_.value_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Any)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Any_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\031google/protobuf/any.proto\022\017google.prot"
+  "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
+  " \001(\014Bv\n\023com.google.protobufB\010AnyProtoP\001Z"
+  ",google.golang.org/protobuf/types/known/"
+  "anypb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownT"
+  "ypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fany_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
+    false, false, 212, descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
+    "google/protobuf/any.proto",
+    &descriptor_table_google_2fprotobuf_2fany_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fany_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fany_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fany_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fany_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fany_2eproto(&descriptor_table_google_2fprotobuf_2fany_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+bool Any::GetAnyFieldDescriptors(
+    const ::PROTOBUF_NAMESPACE_ID::Message& message,
+    const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
+    const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field) {
+  return ::_pbi::GetAnyFieldDescriptors(
+      message, type_url_field, value_field);
+}
+bool Any::ParseAnyTypeUrl(
+    ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,
+    std::string* full_type_name) {
+  return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);
+}
+
+class Any::_Internal {
+ public:
+};
+
+Any::Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Any)
+}
+Any::Any(const Any& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Any* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.type_url_){}
+    , decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_type_url().empty()) {
+    _this->_impl_.type_url_.Set(from._internal_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_value().empty()) {
+    _this->_impl_.value_.Set(from._internal_value(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
+}
+
+inline void Any::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.type_url_){}
+    , decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}
+  };
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Any::~Any() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Any)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Any::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.type_url_.Destroy();
+  _impl_.value_.Destroy();
+  _impl_._any_metadata_.~AnyMetadata();
+}
+
+void Any::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Any::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.type_url_.ClearToEmpty();
+  _impl_.value_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Any::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string type_url = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Any.type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bytes value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Any::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string type_url = 1;
+  if (!this->_internal_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Any.type_url");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_type_url(), target);
+  }
+
+  // bytes value = 2;
+  if (!this->_internal_value().empty()) {
+    target = stream->WriteBytesMaybeAliased(
+        2, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
+  return target;
+}
+
+size_t Any::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string type_url = 1;
+  if (!this->_internal_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_type_url());
+  }
+
+  // bytes value = 2;
+  if (!this->_internal_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
+        this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Any::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Any::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Any::GetClassData() const { return &_class_data_; }
+
+
+void Any::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Any*>(&to_msg);
+  auto& from = static_cast<const Any&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_type_url().empty()) {
+    _this->_internal_set_type_url(from._internal_type_url());
+  }
+  if (!from._internal_value().empty()) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Any::CopyFrom(const Any& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Any::IsInitialized() const {
+  return true;
+}
+
+void Any::InternalSwap(Any* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.type_url_, lhs_arena,
+      &other->_impl_.type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.value_, lhs_arena,
+      &other->_impl_.value_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Any::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fany_2eproto_getter, &descriptor_table_google_2fprotobuf_2fany_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fany_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Any*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Any >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Any >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#if defined(__llvm__)
+  #pragma clang diagnostic pop
+#endif  // __llvm__
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/any_lite.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/any_lite.cpp
new file mode 100644
index 0000000..f283a31
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/any_lite.cpp
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+std::string GetTypeUrl(StringPiece message_name,
+                       StringPiece type_url_prefix) {
+  if (!type_url_prefix.empty() &&
+      type_url_prefix[type_url_prefix.size() - 1] == '/') {
+    return StrCat(type_url_prefix, message_name);
+  } else {
+    return StrCat(type_url_prefix, "/", message_name);
+  }
+}
+
+const char kAnyFullTypeName[] = "google.protobuf.Any";
+const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
+
+bool AnyMetadata::InternalPackFrom(Arena* arena, const MessageLite& message,
+                                   StringPiece type_url_prefix,
+                                   StringPiece type_name) {
+  type_url_->Set(GetTypeUrl(type_name, type_url_prefix), arena);
+  return message.SerializeToString(value_->Mutable(arena));
+}
+
+bool AnyMetadata::InternalUnpackTo(StringPiece type_name,
+                                   MessageLite* message) const {
+  if (!InternalIs(type_name)) {
+    return false;
+  }
+  return message->ParseFromString(value_->Get());
+}
+
+bool AnyMetadata::InternalIs(StringPiece type_name) const {
+  StringPiece type_url = type_url_->Get();
+  return type_url.size() >= type_name.size() + 1 &&
+         type_url[type_url.size() - type_name.size() - 1] == '/' &&
+         HasSuffixString(type_url, type_name);
+}
+
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* url_prefix,
+                     std::string* full_type_name) {
+  size_t pos = type_url.find_last_of('/');
+  if (pos == std::string::npos || pos + 1 == type_url.size()) {
+    return false;
+  }
+  if (url_prefix) {
+    *url_prefix = std::string(type_url.substr(0, pos + 1));
+  }
+  *full_type_name = std::string(type_url.substr(pos + 1));
+  return true;
+}
+
+bool ParseAnyTypeUrl(StringPiece type_url, std::string* full_type_name) {
+  return ParseAnyTypeUrl(type_url, nullptr, full_type_name);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/api.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/api.pb.cpp
new file mode 100644
index 0000000..24b6049
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/api.pb.cpp
@@ -0,0 +1,1309 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#include <google/protobuf/api.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Api::Api(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.methods_)*/{}
+  , /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.mixins_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.version_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.source_context_)*/nullptr
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct ApiDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ApiDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ApiDefaultTypeInternal() {}
+  union {
+    Api _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ApiDefaultTypeInternal _Api_default_instance_;
+PROTOBUF_CONSTEXPR Method::Method(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.request_type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.response_type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.request_streaming_)*/false
+  , /*decltype(_impl_.response_streaming_)*/false
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct MethodDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MethodDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MethodDefaultTypeInternal() {}
+  union {
+    Method _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodDefaultTypeInternal _Method_default_instance_;
+PROTOBUF_CONSTEXPR Mixin::Mixin(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.root_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct MixinDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MixinDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MixinDefaultTypeInternal() {}
+  union {
+    Mixin _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MixinDefaultTypeInternal _Mixin_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fapi_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.methods_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.version_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.source_context_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.mixins_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Api, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.request_type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.request_streaming_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.response_type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.response_streaming_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Method, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, _impl_.root_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Api)},
+  { 13, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Method)},
+  { 26, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Mixin)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Api_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Method_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Mixin_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\031google/protobuf/api.proto\022\017google.prot"
+  "obuf\032$google/protobuf/source_context.pro"
+  "to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014"
+  "\n\004name\030\001 \001(\t\022(\n\007methods\030\002 \003(\0132\027.google.p"
+  "rotobuf.Method\022(\n\007options\030\003 \003(\0132\027.google"
+  ".protobuf.Option\022\017\n\007version\030\004 \001(\t\0226\n\016sou"
+  "rce_context\030\005 \001(\0132\036.google.protobuf.Sour"
+  "ceContext\022&\n\006mixins\030\006 \003(\0132\026.google.proto"
+  "buf.Mixin\022\'\n\006syntax\030\007 \001(\0162\027.google.proto"
+  "buf.Syntax\"\325\001\n\006Method\022\014\n\004name\030\001 \001(\t\022\030\n\020r"
+  "equest_type_url\030\002 \001(\t\022\031\n\021request_streami"
+  "ng\030\003 \001(\010\022\031\n\021response_type_url\030\004 \001(\t\022\032\n\022r"
+  "esponse_streaming\030\005 \001(\010\022(\n\007options\030\006 \003(\013"
+  "2\027.google.protobuf.Option\022\'\n\006syntax\030\007 \001("
+  "\0162\027.google.protobuf.Syntax\"#\n\005Mixin\022\014\n\004n"
+  "ame\030\001 \001(\t\022\014\n\004root\030\002 \001(\tBv\n\023com.google.pr"
+  "otobufB\010ApiProtoP\001Z,google.golang.org/pr"
+  "otobuf/types/known/apipb\242\002\003GPB\252\002\036Google."
+  "Protobuf.WellKnownTypesb\006proto3"
+  ;
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2fapi_2eproto_deps[2] = {
+  &::descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto,
+  &::descriptor_table_google_2fprotobuf_2ftype_2eproto,
+};
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fapi_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
+    false, false, 751, descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
+    "google/protobuf/api.proto",
+    &descriptor_table_google_2fprotobuf_2fapi_2eproto_once, descriptor_table_google_2fprotobuf_2fapi_2eproto_deps, 2, 3,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fapi_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fapi_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fapi_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fapi_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fapi_2eproto(&descriptor_table_google_2fprotobuf_2fapi_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Api::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context(const Api* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::SourceContext&
+Api::_Internal::source_context(const Api* msg) {
+  return *msg->_impl_.source_context_;
+}
+void Api::clear_options() {
+  _impl_.options_.Clear();
+}
+void Api::clear_source_context() {
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+}
+Api::Api(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Api)
+}
+Api::Api(const Api& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Api* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.methods_){from._impl_.methods_}
+    , decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.mixins_){from._impl_.mixins_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.version_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.version_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.version_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_version().empty()) {
+    _this->_impl_.version_.Set(from._internal_version(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
+  }
+  _this->_impl_.syntax_ = from._impl_.syntax_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Api)
+}
+
+inline void Api::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.methods_){arena}
+    , decltype(_impl_.options_){arena}
+    , decltype(_impl_.mixins_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.version_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.version_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.version_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Api::~Api() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Api)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Api::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.methods_.~RepeatedPtrField();
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.mixins_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  _impl_.version_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.source_context_;
+}
+
+void Api::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Api::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Api)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.methods_.Clear();
+  _impl_.options_.Clear();
+  _impl_.mixins_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.version_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+  _impl_.syntax_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Api::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Api.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Method methods = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_methods(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // string version = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_version();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Api.version"));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.SourceContext source_context = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Mixin mixins = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_mixins(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Api::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.Method methods = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_methods_size()); i < n; i++) {
+    const auto& repfield = this->_internal_methods(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // string version = 4;
+  if (!this->_internal_version().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_version().data(), static_cast<int>(this->_internal_version().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.version");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_version(), target);
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(5, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_mixins_size()); i < n; i++) {
+    const auto& repfield = this->_internal_mixins(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      7, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Api)
+  return target;
+}
+
+size_t Api::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Api)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Method methods = 2;
+  total_size += 1UL * this->_internal_methods_size();
+  for (const auto& msg : this->_impl_.methods_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  total_size += 1UL * this->_internal_mixins_size();
+  for (const auto& msg : this->_impl_.mixins_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string version = 4;
+  if (!this->_internal_version().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_version());
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.source_context_);
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Api::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Api::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Api::GetClassData() const { return &_class_data_; }
+
+
+void Api::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Api*>(&to_msg);
+  auto& from = static_cast<const Api&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Api)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.methods_.MergeFrom(from._impl_.methods_);
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  _this->_impl_.mixins_.MergeFrom(from._impl_.mixins_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_version().empty()) {
+    _this->_internal_set_version(from._internal_version());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
+        from._internal_source_context());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Api::CopyFrom(const Api& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Api)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Api::IsInitialized() const {
+  return true;
+}
+
+void Api::InternalSwap(Api* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.methods_.InternalSwap(&other->_impl_.methods_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  _impl_.mixins_.InternalSwap(&other->_impl_.mixins_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.version_, lhs_arena,
+      &other->_impl_.version_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Api, _impl_.syntax_)
+      + sizeof(Api::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Api, _impl_.source_context_)>(
+          reinterpret_cast<char*>(&_impl_.source_context_),
+          reinterpret_cast<char*>(&other->_impl_.source_context_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Api::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fapi_2eproto[0]);
+}
+
+// ===================================================================
+
+class Method::_Internal {
+ public:
+};
+
+void Method::clear_options() {
+  _impl_.options_.Clear();
+}
+Method::Method(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Method)
+}
+Method::Method(const Method& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Method* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.request_type_url_){}
+    , decltype(_impl_.response_type_url_){}
+    , decltype(_impl_.request_streaming_){}
+    , decltype(_impl_.response_streaming_){}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.request_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.request_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_request_type_url().empty()) {
+    _this->_impl_.request_type_url_.Set(from._internal_request_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.response_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.response_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_response_type_url().empty()) {
+    _this->_impl_.response_type_url_.Set(from._internal_response_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.request_streaming_, &from._impl_.request_streaming_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.syntax_) -
+    reinterpret_cast<char*>(&_impl_.request_streaming_)) + sizeof(_impl_.syntax_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Method)
+}
+
+inline void Method::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.request_type_url_){}
+    , decltype(_impl_.response_type_url_){}
+    , decltype(_impl_.request_streaming_){false}
+    , decltype(_impl_.response_streaming_){false}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.request_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.request_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.response_type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.response_type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Method::~Method() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Method)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Method::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  _impl_.request_type_url_.Destroy();
+  _impl_.response_type_url_.Destroy();
+}
+
+void Method::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Method::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Method)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.request_type_url_.ClearToEmpty();
+  _impl_.response_type_url_.ClearToEmpty();
+  ::memset(&_impl_.request_streaming_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.syntax_) -
+      reinterpret_cast<char*>(&_impl_.request_streaming_)) + sizeof(_impl_.syntax_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Method::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string request_type_url = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_request_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.request_type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bool request_streaming = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _impl_.request_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // string response_type_url = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_response_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.response_type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bool response_streaming = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _impl_.response_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Method::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // string request_type_url = 2;
+  if (!this->_internal_request_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_request_type_url().data(), static_cast<int>(this->_internal_request_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.request_type_url");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_request_type_url(), target);
+  }
+
+  // bool request_streaming = 3;
+  if (this->_internal_request_streaming() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_request_streaming(), target);
+  }
+
+  // string response_type_url = 4;
+  if (!this->_internal_response_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_response_type_url().data(), static_cast<int>(this->_internal_response_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.response_type_url");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_response_type_url(), target);
+  }
+
+  // bool response_streaming = 5;
+  if (this->_internal_response_streaming() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_response_streaming(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      7, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Method)
+  return target;
+}
+
+size_t Method::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Method)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Option options = 6;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string request_type_url = 2;
+  if (!this->_internal_request_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_request_type_url());
+  }
+
+  // string response_type_url = 4;
+  if (!this->_internal_response_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_response_type_url());
+  }
+
+  // bool request_streaming = 3;
+  if (this->_internal_request_streaming() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // bool response_streaming = 5;
+  if (this->_internal_response_streaming() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // .google.protobuf.Syntax syntax = 7;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Method::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Method::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Method::GetClassData() const { return &_class_data_; }
+
+
+void Method::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Method*>(&to_msg);
+  auto& from = static_cast<const Method&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Method)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_request_type_url().empty()) {
+    _this->_internal_set_request_type_url(from._internal_request_type_url());
+  }
+  if (!from._internal_response_type_url().empty()) {
+    _this->_internal_set_response_type_url(from._internal_response_type_url());
+  }
+  if (from._internal_request_streaming() != 0) {
+    _this->_internal_set_request_streaming(from._internal_request_streaming());
+  }
+  if (from._internal_response_streaming() != 0) {
+    _this->_internal_set_response_streaming(from._internal_response_streaming());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Method::CopyFrom(const Method& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Method)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Method::IsInitialized() const {
+  return true;
+}
+
+void Method::InternalSwap(Method* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.request_type_url_, lhs_arena,
+      &other->_impl_.request_type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.response_type_url_, lhs_arena,
+      &other->_impl_.response_type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Method, _impl_.syntax_)
+      + sizeof(Method::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Method, _impl_.request_streaming_)>(
+          reinterpret_cast<char*>(&_impl_.request_streaming_),
+          reinterpret_cast<char*>(&other->_impl_.request_streaming_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Method::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fapi_2eproto[1]);
+}
+
+// ===================================================================
+
+class Mixin::_Internal {
+ public:
+};
+
+Mixin::Mixin(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Mixin)
+}
+Mixin::Mixin(const Mixin& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Mixin* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.root_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.root_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.root_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_root().empty()) {
+    _this->_impl_.root_.Set(from._internal_root(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Mixin)
+}
+
+inline void Mixin::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.root_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.root_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.root_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Mixin::~Mixin() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Mixin)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Mixin::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.root_.Destroy();
+}
+
+void Mixin::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Mixin::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.name_.ClearToEmpty();
+  _impl_.root_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Mixin::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Mixin.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string root = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_root();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Mixin.root"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Mixin::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // string root = 2;
+  if (!this->_internal_root().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_root().data(), static_cast<int>(this->_internal_root().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.root");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_root(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Mixin)
+  return target;
+}
+
+size_t Mixin::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Mixin)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string root = 2;
+  if (!this->_internal_root().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_root());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Mixin::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Mixin::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Mixin::GetClassData() const { return &_class_data_; }
+
+
+void Mixin::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Mixin*>(&to_msg);
+  auto& from = static_cast<const Mixin&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Mixin)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_root().empty()) {
+    _this->_internal_set_root(from._internal_root());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Mixin::CopyFrom(const Mixin& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Mixin)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Mixin::IsInitialized() const {
+  return true;
+}
+
+void Mixin::InternalSwap(Mixin* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.root_, lhs_arena,
+      &other->_impl_.root_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Mixin::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fapi_2eproto[2]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Api*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Api >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Api >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Method*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Method >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Method >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Mixin*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Mixin >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Mixin >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/arena.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/arena.cpp
new file mode 100644
index 0000000..1944042
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/arena.cpp
@@ -0,0 +1,537 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arena.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <typeinfo>
+
+#include <google/protobuf/arena_impl.h>
+#include <google/protobuf/arenaz_sampler.h>
+#include <google/protobuf/port.h>
+
+#include <google/protobuf/stubs/mutex.h>
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif  // ADDRESS_SANITIZER
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+static SerialArena::Memory AllocateMemory(const AllocationPolicy* policy_ptr,
+                                          size_t last_size, size_t min_bytes) {
+  AllocationPolicy policy;  // default policy
+  if (policy_ptr) policy = *policy_ptr;
+  size_t size;
+  if (last_size != 0) {
+    // Double the current block size, up to a limit.
+    auto max_size = policy.max_block_size;
+    size = std::min(2 * last_size, max_size);
+  } else {
+    size = policy.start_block_size;
+  }
+  // Verify that min_bytes + kBlockHeaderSize won't overflow.
+  GOOGLE_CHECK_LE(min_bytes,
+           std::numeric_limits<size_t>::max() - SerialArena::kBlockHeaderSize);
+  size = std::max(size, SerialArena::kBlockHeaderSize + min_bytes);
+
+  void* mem;
+  if (policy.block_alloc == nullptr) {
+    mem = ::operator new(size);
+  } else {
+    mem = policy.block_alloc(size);
+  }
+  return {mem, size};
+}
+
+class GetDeallocator {
+ public:
+  GetDeallocator(const AllocationPolicy* policy, size_t* space_allocated)
+      : dealloc_(policy ? policy->block_dealloc : nullptr),
+        space_allocated_(space_allocated) {}
+
+  void operator()(SerialArena::Memory mem) const {
+#ifdef ADDRESS_SANITIZER
+    // This memory was provided by the underlying allocator as unpoisoned,
+    // so return it in an unpoisoned state.
+    ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
+#endif  // ADDRESS_SANITIZER
+    if (dealloc_) {
+      dealloc_(mem.ptr, mem.size);
+    } else {
+      internal::SizedDelete(mem.ptr, mem.size);
+    }
+    *space_allocated_ += mem.size;
+  }
+
+ private:
+  void (*dealloc_)(void*, size_t);
+  size_t* space_allocated_;
+};
+
+SerialArena::SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats)
+    : space_allocated_(b->size) {
+  owner_ = owner;
+  head_ = b;
+  ptr_ = b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize);
+  limit_ = b->Pointer(b->size & static_cast<size_t>(-8));
+  arena_stats_ = stats;
+}
+
+SerialArena* SerialArena::New(Memory mem, void* owner,
+                              ThreadSafeArenaStats* stats) {
+  GOOGLE_DCHECK_LE(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize, mem.size);
+  ThreadSafeArenaStats::RecordAllocateStats(
+      stats, /*requested=*/mem.size, /*allocated=*/mem.size, /*wasted=*/0);
+  auto b = new (mem.ptr) Block{nullptr, mem.size};
+  return new (b->Pointer(kBlockHeaderSize)) SerialArena(b, owner, stats);
+}
+
+template <typename Deallocator>
+SerialArena::Memory SerialArena::Free(Deallocator deallocator) {
+  Block* b = head_;
+  Memory mem = {b, b->size};
+  while (b->next) {
+    b = b->next;  // We must first advance before deleting this block
+    deallocator(mem);
+    mem = {b, b->size};
+  }
+  return mem;
+}
+
+PROTOBUF_NOINLINE
+std::pair<void*, SerialArena::CleanupNode*>
+SerialArena::AllocateAlignedWithCleanupFallback(
+    size_t n, const AllocationPolicy* policy) {
+  AllocateNewBlock(n + kCleanupSize, policy);
+  return AllocateFromExistingWithCleanupFallback(n);
+}
+
+PROTOBUF_NOINLINE
+void* SerialArena::AllocateAlignedFallback(size_t n,
+                                           const AllocationPolicy* policy) {
+  AllocateNewBlock(n, policy);
+  return AllocateFromExisting(n);
+}
+
+void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) {
+  // Sync limit to block
+  head_->start = reinterpret_cast<CleanupNode*>(limit_);
+
+  // Record how much used in this block.
+  size_t used = ptr_ - head_->Pointer(kBlockHeaderSize);
+  size_t wasted = head_->size - used;
+  space_used_ += used;
+
+  // TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a
+  // win. In preliminary testing showed increased memory savings as expected,
+  // but with a CPU regression. The regression might have been an artifact of
+  // the microbenchmark.
+
+  auto mem = AllocateMemory(policy, head_->size, n);
+  // We don't want to emit an expensive RMW instruction that requires
+  // exclusive access to a cacheline. Hence we write it in terms of a
+  // regular add.
+  auto relaxed = std::memory_order_relaxed;
+  space_allocated_.store(space_allocated_.load(relaxed) + mem.size, relaxed);
+  ThreadSafeArenaStats::RecordAllocateStats(arena_stats_, /*requested=*/n,
+                                            /*allocated=*/mem.size, wasted);
+  head_ = new (mem.ptr) Block{head_, mem.size};
+  ptr_ = head_->Pointer(kBlockHeaderSize);
+  limit_ = head_->Pointer(head_->size);
+
+#ifdef ADDRESS_SANITIZER
+  ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_);
+#endif  // ADDRESS_SANITIZER
+}
+
+uint64_t SerialArena::SpaceUsed() const {
+  uint64_t space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
+  space_used += space_used_;
+  // Remove the overhead of the SerialArena itself.
+  space_used -= ThreadSafeArena::kSerialArenaSize;
+  return space_used;
+}
+
+void SerialArena::CleanupList() {
+  Block* b = head_;
+  b->start = reinterpret_cast<CleanupNode*>(limit_);
+  do {
+    auto* limit = reinterpret_cast<CleanupNode*>(
+        b->Pointer(b->size & static_cast<size_t>(-8)));
+    auto it = b->start;
+    auto num = limit - it;
+    if (num > 0) {
+      for (; it < limit; it++) {
+        it->cleanup(it->elem);
+      }
+    }
+    b = b->next;
+  } while (b);
+}
+
+
+ThreadSafeArena::CacheAlignedLifecycleIdGenerator
+    ThreadSafeArena::lifecycle_id_generator_;
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
+  static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
+      new internal::ThreadLocalStorage<ThreadCache>();
+  return *thread_cache_->Get();
+}
+#elif defined(PROTOBUF_USE_DLLS)
+ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
+  static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_ = {
+      0, static_cast<LifecycleIdAtomic>(-1), nullptr};
+  return thread_cache_;
+}
+#else
+PROTOBUF_THREAD_LOCAL ThreadSafeArena::ThreadCache
+    ThreadSafeArena::thread_cache_ = {0, static_cast<LifecycleIdAtomic>(-1),
+                                      nullptr};
+#endif
+
+void ThreadSafeArena::InitializeFrom(void* mem, size_t size) {
+  GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
+  GOOGLE_DCHECK(!AllocPolicy());  // Reset should call InitializeWithPolicy instead.
+  Init();
+
+  // Ignore initial block if it is too small.
+  if (mem != nullptr && size >= kBlockHeaderSize + kSerialArenaSize) {
+    alloc_policy_.set_is_user_owned_initial_block(true);
+    SetInitialBlock(mem, size);
+  }
+}
+
+void ThreadSafeArena::InitializeWithPolicy(void* mem, size_t size,
+                                           AllocationPolicy policy) {
+#ifndef NDEBUG
+  const uint64_t old_alloc_policy = alloc_policy_.get_raw();
+  // If there was a policy (e.g., in Reset()), make sure flags were preserved.
+#define GOOGLE_DCHECK_POLICY_FLAGS_() \
+  if (old_alloc_policy > 3)    \
+    GOOGLE_CHECK_EQ(old_alloc_policy & 3, alloc_policy_.get_raw() & 3)
+#else
+#define GOOGLE_DCHECK_POLICY_FLAGS_()
+#endif  // NDEBUG
+
+  if (policy.IsDefault()) {
+    // Legacy code doesn't use the API above, but provides the initial block
+    // through ArenaOptions. I suspect most do not touch the allocation
+    // policy parameters.
+    InitializeFrom(mem, size);
+    GOOGLE_DCHECK_POLICY_FLAGS_();
+    return;
+  }
+  GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
+  Init();
+
+  // Ignore initial block if it is too small. We include an optional
+  // AllocationPolicy in this check, so that this can be allocated on the
+  // first block.
+  constexpr size_t kAPSize = internal::AlignUpTo8(sizeof(AllocationPolicy));
+  constexpr size_t kMinimumSize = kBlockHeaderSize + kSerialArenaSize + kAPSize;
+
+  // The value for alloc_policy_ stores whether or not allocations should be
+  // recorded.
+  alloc_policy_.set_should_record_allocs(
+      policy.metrics_collector != nullptr &&
+      policy.metrics_collector->RecordAllocs());
+  // Make sure we have an initial block to store the AllocationPolicy.
+  if (mem != nullptr && size >= kMinimumSize) {
+    alloc_policy_.set_is_user_owned_initial_block(true);
+  } else {
+    auto tmp = AllocateMemory(&policy, 0, kMinimumSize);
+    mem = tmp.ptr;
+    size = tmp.size;
+  }
+  SetInitialBlock(mem, size);
+
+  auto sa = threads_.load(std::memory_order_relaxed);
+  // We ensured enough space so this cannot fail.
+  void* p;
+  if (!sa || !sa->MaybeAllocateAligned(kAPSize, &p)) {
+    GOOGLE_LOG(FATAL) << "MaybeAllocateAligned cannot fail here.";
+    return;
+  }
+  new (p) AllocationPolicy{policy};
+  // Low bits store flags, so they mustn't be overwritten.
+  GOOGLE_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(p) & 3);
+  alloc_policy_.set_policy(reinterpret_cast<AllocationPolicy*>(p));
+  GOOGLE_DCHECK_POLICY_FLAGS_();
+
+#undef GOOGLE_DCHECK_POLICY_FLAGS_
+}
+
+void ThreadSafeArena::Init() {
+#ifndef NDEBUG
+  const bool was_message_owned = IsMessageOwned();
+#endif  // NDEBUG
+  ThreadCache& tc = thread_cache();
+  auto id = tc.next_lifecycle_id;
+  // We increment lifecycle_id's by multiples of two so we can use bit 0 as
+  // a tag.
+  constexpr uint64_t kDelta = 2;
+  constexpr uint64_t kInc = ThreadCache::kPerThreadIds * kDelta;
+  if (PROTOBUF_PREDICT_FALSE((id & (kInc - 1)) == 0)) {
+    constexpr auto relaxed = std::memory_order_relaxed;
+    // On platforms that don't support uint64_t atomics we can certainly not
+    // afford to increment by large intervals and expect uniqueness due to
+    // wrapping, hence we only add by 1.
+    id = lifecycle_id_generator_.id.fetch_add(1, relaxed) * kInc;
+  }
+  tc.next_lifecycle_id = id + kDelta;
+  // Message ownership is stored in tag_and_id_, and is set in the constructor.
+  // This flag bit must be preserved, even across calls to Reset().
+  tag_and_id_ = id | (tag_and_id_ & kMessageOwnedArena);
+  hint_.store(nullptr, std::memory_order_relaxed);
+  threads_.store(nullptr, std::memory_order_relaxed);
+#ifndef NDEBUG
+  GOOGLE_CHECK_EQ(was_message_owned, IsMessageOwned());
+#endif  // NDEBUG
+  arena_stats_ = Sample();
+}
+
+void ThreadSafeArena::SetInitialBlock(void* mem, size_t size) {
+  SerialArena* serial = SerialArena::New({mem, size}, &thread_cache(),
+                                         arena_stats_.MutableStats());
+  serial->set_next(NULL);
+  threads_.store(serial, std::memory_order_relaxed);
+  CacheSerialArena(serial);
+}
+
+ThreadSafeArena::~ThreadSafeArena() {
+  // Have to do this in a first pass, because some of the destructors might
+  // refer to memory in other blocks.
+  CleanupList();
+
+  size_t space_allocated = 0;
+  auto mem = Free(&space_allocated);
+
+  // Policy is about to get deleted.
+  auto* p = alloc_policy_.get();
+  ArenaMetricsCollector* collector = p ? p->metrics_collector : nullptr;
+
+  if (alloc_policy_.is_user_owned_initial_block()) {
+#ifdef ADDRESS_SANITIZER
+    // Unpoison the initial block, now that it's going back to the user.
+    ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
+#endif  // ADDRESS_SANITIZER
+    space_allocated += mem.size;
+  } else {
+    GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
+  }
+
+  if (collector) collector->OnDestroy(space_allocated);
+}
+
+SerialArena::Memory ThreadSafeArena::Free(size_t* space_allocated) {
+  SerialArena::Memory mem = {nullptr, 0};
+  auto deallocator = GetDeallocator(alloc_policy_.get(), space_allocated);
+  PerSerialArena([deallocator, &mem](SerialArena* a) {
+    if (mem.ptr) deallocator(mem);
+    mem = a->Free(deallocator);
+  });
+  return mem;
+}
+
+uint64_t ThreadSafeArena::Reset() {
+  // Have to do this in a first pass, because some of the destructors might
+  // refer to memory in other blocks.
+  CleanupList();
+
+  // Discard all blocks except the special block (if present).
+  size_t space_allocated = 0;
+  auto mem = Free(&space_allocated);
+  arena_stats_.RecordReset();
+
+  AllocationPolicy* policy = alloc_policy_.get();
+  if (policy) {
+    auto saved_policy = *policy;
+    if (alloc_policy_.is_user_owned_initial_block()) {
+      space_allocated += mem.size;
+    } else {
+      GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
+      mem.ptr = nullptr;
+      mem.size = 0;
+    }
+    ArenaMetricsCollector* collector = saved_policy.metrics_collector;
+    if (collector) collector->OnReset(space_allocated);
+    InitializeWithPolicy(mem.ptr, mem.size, saved_policy);
+  } else {
+    GOOGLE_DCHECK(!alloc_policy_.should_record_allocs());
+    // Nullptr policy
+    if (alloc_policy_.is_user_owned_initial_block()) {
+      space_allocated += mem.size;
+      InitializeFrom(mem.ptr, mem.size);
+    } else {
+      GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
+      Init();
+    }
+  }
+
+  return space_allocated;
+}
+
+std::pair<void*, SerialArena::CleanupNode*>
+ThreadSafeArena::AllocateAlignedWithCleanup(size_t n,
+                                            const std::type_info* type) {
+  SerialArena* arena = nullptr;
+  if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
+                            GetSerialArenaFast(&arena))) {
+    return arena->AllocateAlignedWithCleanup(n, alloc_policy_.get());
+  } else {
+    return AllocateAlignedWithCleanupFallback(n, type);
+  }
+}
+
+void ThreadSafeArena::AddCleanup(void* elem, void (*cleanup)(void*)) {
+  SerialArena* arena = nullptr;
+  if (PROTOBUF_PREDICT_FALSE(!GetSerialArenaFast(&arena))) {
+    arena = GetSerialArenaFallback(&thread_cache());
+  }
+  arena->AddCleanup(elem, cleanup, AllocPolicy());
+}
+
+PROTOBUF_NOINLINE
+void* ThreadSafeArena::AllocateAlignedFallback(size_t n,
+                                               const std::type_info* type) {
+  if (alloc_policy_.should_record_allocs()) {
+    alloc_policy_.RecordAlloc(type, n);
+    SerialArena* arena = nullptr;
+    if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+      return arena->AllocateAligned(n, alloc_policy_.get());
+    }
+  }
+  return GetSerialArenaFallback(&thread_cache())
+      ->AllocateAligned(n, alloc_policy_.get());
+}
+
+PROTOBUF_NOINLINE
+std::pair<void*, SerialArena::CleanupNode*>
+ThreadSafeArena::AllocateAlignedWithCleanupFallback(
+    size_t n, const std::type_info* type) {
+  if (alloc_policy_.should_record_allocs()) {
+    alloc_policy_.RecordAlloc(type, n);
+    SerialArena* arena;
+    if (GetSerialArenaFast(&arena)) {
+      return arena->AllocateAlignedWithCleanup(n, alloc_policy_.get());
+    }
+  }
+  return GetSerialArenaFallback(&thread_cache())
+      ->AllocateAlignedWithCleanup(n, alloc_policy_.get());
+}
+
+uint64_t ThreadSafeArena::SpaceAllocated() const {
+  SerialArena* serial = threads_.load(std::memory_order_acquire);
+  uint64_t res = 0;
+  for (; serial; serial = serial->next()) {
+    res += serial->SpaceAllocated();
+  }
+  return res;
+}
+
+uint64_t ThreadSafeArena::SpaceUsed() const {
+  SerialArena* serial = threads_.load(std::memory_order_acquire);
+  uint64_t space_used = 0;
+  for (; serial; serial = serial->next()) {
+    space_used += serial->SpaceUsed();
+  }
+  return space_used - (alloc_policy_.get() ? sizeof(AllocationPolicy) : 0);
+}
+
+void ThreadSafeArena::CleanupList() {
+  PerSerialArena([](SerialArena* a) { a->CleanupList(); });
+}
+
+PROTOBUF_NOINLINE
+SerialArena* ThreadSafeArena::GetSerialArenaFallback(void* me) {
+  // Look for this SerialArena in our linked list.
+  SerialArena* serial = threads_.load(std::memory_order_acquire);
+  for (; serial; serial = serial->next()) {
+    if (serial->owner() == me) {
+      break;
+    }
+  }
+
+  if (!serial) {
+    // This thread doesn't have any SerialArena, which also means it doesn't
+    // have any blocks yet.  So we'll allocate its first block now.
+    serial = SerialArena::New(
+        AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), me,
+        arena_stats_.MutableStats());
+
+    SerialArena* head = threads_.load(std::memory_order_relaxed);
+    do {
+      serial->set_next(head);
+    } while (!threads_.compare_exchange_weak(
+        head, serial, std::memory_order_release, std::memory_order_relaxed));
+  }
+
+  CacheSerialArena(serial);
+  return serial;
+}
+
+}  // namespace internal
+
+PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedNoHook(size_t n) {
+  return impl_.AllocateAligned(n, nullptr);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedWithHook(size_t n, const std::type_info* type) {
+  return impl_.AllocateAligned(n, type);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedWithHookForArray(size_t n,
+                                             const std::type_info* type) {
+  return impl_.AllocateAligned<internal::AllocationClient::kArray>(n, type);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
+std::pair<void*, internal::SerialArena::CleanupNode*>
+Arena::AllocateAlignedWithCleanup(size_t n, const std::type_info* type) {
+  return impl_.AllocateAlignedWithCleanup(n, type);
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/arenastring.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/arenastring.cpp
new file mode 100644
index 0000000..af0c9df
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/arenastring.cpp
@@ -0,0 +1,267 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arenastring.h>
+
+#include <cstddef>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace  {
+
+// TaggedStringPtr::Flags uses the lower 2 bits as tags.
+// Enforce that allocated data aligns to at least 4 bytes, and that
+// the alignment of the global const string value does as well.
+// The alignment guaranteed by `new std::string` depends on both:
+// - new align = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / max_align_t
+// - alignof(std::string)
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+constexpr size_t kNewAlign = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
+constexpr size_t kNewAlign = alignof(::max_align_t);
+#else
+constexpr size_t kNewAlign = alignof(std::max_align_t);
+#endif
+constexpr size_t kStringAlign = alignof(std::string);
+
+static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 4, "");
+static_assert(alignof(ExplicitlyConstructedArenaString) >= 4, "");
+
+}  // namespace
+
+const std::string& LazyString::Init() const {
+  static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
+  mu.Lock();
+  const std::string* res = inited_.load(std::memory_order_acquire);
+  if (res == nullptr) {
+    auto init_value = init_value_;
+    res = ::new (static_cast<void*>(string_buf_))
+        std::string(init_value.ptr, init_value.size);
+    inited_.store(res, std::memory_order_release);
+  }
+  mu.Unlock();
+  return *res;
+}
+
+namespace {
+
+
+#if defined(NDEBUG) || !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+class ScopedCheckPtrInvariants {
+ public:
+  explicit ScopedCheckPtrInvariants(const TaggedStringPtr*) {}
+};
+
+#endif  // NDEBUG || !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+// Creates a heap allocated std::string value.
+inline TaggedStringPtr CreateString(ConstStringParam value) {
+  TaggedStringPtr res;
+  res.SetAllocated(new std::string(value.data(), value.length()));
+  return res;
+}
+
+#if !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+// Creates an arena allocated std::string value.
+TaggedStringPtr CreateArenaString(Arena& arena, ConstStringParam s) {
+  TaggedStringPtr res;
+  res.SetMutableArena(Arena::Create<std::string>(&arena, s.data(), s.length()));
+  return res;
+}
+
+#endif  // !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+}  // namespace
+
+void ArenaStringPtr::Set(ConstStringParam value, Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) {
+    // If we're not on an arena, skip straight to a true string to avoid
+    // possible copy cost later.
+    tagged_ptr_ = arena != nullptr ? CreateArenaString(*arena, value)
+                                   : CreateString(value);
+  } else {
+    UnsafeMutablePointer()->assign(value.data(), value.length());
+  }
+}
+
+void ArenaStringPtr::Set(std::string&& value, Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) {
+    NewString(arena, std::move(value));
+  } else if (IsFixedSizeArena()) {
+    std::string* current = tagged_ptr_.Get();
+    auto* s = new (current) std::string(std::move(value));
+    arena->OwnDestructor(s);
+    tagged_ptr_.SetMutableArena(s);
+  } else /* !IsFixedSizeArena() */ {
+    *UnsafeMutablePointer() = std::move(value);
+  }
+}
+
+std::string* ArenaStringPtr::Mutable(Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (tagged_ptr_.IsMutable()) {
+    return tagged_ptr_.Get();
+  } else {
+    return MutableSlow(arena);
+  }
+}
+
+std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
+                                     Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (tagged_ptr_.IsMutable()) {
+    return tagged_ptr_.Get();
+  } else {
+    return MutableSlow(arena, default_value);
+  }
+}
+
+std::string* ArenaStringPtr::MutableNoCopy(Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (tagged_ptr_.IsMutable()) {
+    return tagged_ptr_.Get();
+  } else {
+    GOOGLE_DCHECK(IsDefault());
+    // Allocate empty. The contents are not relevant.
+    return NewString(arena);
+  }
+}
+
+template <typename... Lazy>
+std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
+                                         const Lazy&... lazy_default) {
+  GOOGLE_DCHECK(IsDefault());
+
+  // For empty defaults, this ends up calling the default constructor which is
+  // more efficient than a copy construction from
+  // GetEmptyStringAlreadyInited().
+  return NewString(arena, lazy_default.get()...);
+}
+
+std::string* ArenaStringPtr::Release() {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) return nullptr;
+
+  std::string* released = tagged_ptr_.Get();
+  if (tagged_ptr_.IsArena()) {
+    released = tagged_ptr_.IsMutable() ? new std::string(std::move(*released))
+                                       : new std::string(*released);
+  }
+  InitDefault();
+  return released;
+}
+
+void ArenaStringPtr::SetAllocated(std::string* value, Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  // Release what we have first.
+  Destroy();
+
+  if (value == nullptr) {
+    InitDefault();
+  } else {
+#ifndef NDEBUG
+    // On debug builds, copy the string so the address differs.  delete will
+    // fail if value was a stack-allocated temporary/etc., which would have
+    // failed when arena ran its cleanup list.
+    std::string* new_value = new std::string(std::move(*value));
+    delete value;
+    value = new_value;
+#endif  // !NDEBUG
+    InitAllocated(value, arena);
+  }
+}
+
+void ArenaStringPtr::Destroy() {
+  delete tagged_ptr_.GetIfAllocated();
+}
+
+void ArenaStringPtr::ClearToEmpty() {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  if (IsDefault()) {
+    // Already set to default -- do nothing.
+  } else {
+    // Unconditionally mask away the tag.
+    //
+    // UpdateArenaString uses assign when capacity is larger than the new
+    // value, which is trivially true in the donated string case.
+    // const_cast<std::string*>(PtrValue<std::string>())->clear();
+    tagged_ptr_.Get()->clear();
+  }
+}
+
+void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
+                                    ::google::protobuf::Arena* arena) {
+  ScopedCheckPtrInvariants check(&tagged_ptr_);
+  (void)arena;
+  if (IsDefault()) {
+    // Already set to default -- do nothing.
+  } else {
+    UnsafeMutablePointer()->assign(default_value.get());
+  }
+}
+
+const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
+                                                ArenaStringPtr* s,
+                                                Arena* arena) {
+  ScopedCheckPtrInvariants check(&s->tagged_ptr_);
+  GOOGLE_DCHECK(arena != nullptr);
+
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+
+  auto* str = s->NewString(arena);
+  ptr = ReadString(ptr, size, str);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ptr;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/arenaz_sampler.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/arenaz_sampler.cpp
new file mode 100644
index 0000000..0eac693
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/arenaz_sampler.cpp
@@ -0,0 +1,177 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/arenaz_sampler.h>
+
+#include <atomic>
+#include <cstdint>
+#include <limits>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler() {
+  static auto* sampler = new ThreadSafeArenazSampler();
+  return *sampler;
+}
+
+void UnsampleSlow(ThreadSafeArenaStats* info) {
+  GlobalThreadSafeArenazSampler().Unregister(info);
+}
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+namespace {
+
+PROTOBUF_CONSTINIT std::atomic<bool> g_arenaz_enabled{true};
+PROTOBUF_CONSTINIT std::atomic<int32_t> g_arenaz_sample_parameter{1 << 10};
+PROTOBUF_THREAD_LOCAL absl::profiling_internal::ExponentialBiased
+    g_exponential_biased_generator;
+
+}  // namespace
+
+PROTOBUF_THREAD_LOCAL int64_t global_next_sample = 1LL << 10;
+
+ThreadSafeArenaStats::ThreadSafeArenaStats() { PrepareForSampling(); }
+ThreadSafeArenaStats::~ThreadSafeArenaStats() = default;
+
+void ThreadSafeArenaStats::PrepareForSampling() {
+  num_allocations.store(0, std::memory_order_relaxed);
+  num_resets.store(0, std::memory_order_relaxed);
+  bytes_requested.store(0, std::memory_order_relaxed);
+  bytes_allocated.store(0, std::memory_order_relaxed);
+  bytes_wasted.store(0, std::memory_order_relaxed);
+  max_bytes_allocated.store(0, std::memory_order_relaxed);
+  thread_ids.store(0, std::memory_order_relaxed);
+  // The inliner makes hardcoded skip_count difficult (especially when combined
+  // with LTO).  We use the ability to exclude stacks by regex when encoding
+  // instead.
+  depth = absl::GetStackTrace(stack, kMaxStackDepth, /* skip_count= */ 0);
+}
+
+void RecordResetSlow(ThreadSafeArenaStats* info) {
+  const size_t max_bytes =
+      info->max_bytes_allocated.load(std::memory_order_relaxed);
+  const size_t allocated_bytes =
+      info->bytes_allocated.load(std::memory_order_relaxed);
+  if (max_bytes < allocated_bytes) {
+    info->max_bytes_allocated.store(allocated_bytes);
+  }
+  info->bytes_requested.store(0, std::memory_order_relaxed);
+  info->bytes_allocated.store(0, std::memory_order_relaxed);
+  info->bytes_wasted.fetch_add(0, std::memory_order_relaxed);
+  info->num_allocations.fetch_add(0, std::memory_order_relaxed);
+  info->num_resets.fetch_add(1, std::memory_order_relaxed);
+}
+
+void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
+                        size_t allocated, size_t wasted) {
+  info->bytes_requested.fetch_add(requested, std::memory_order_relaxed);
+  info->bytes_allocated.fetch_add(allocated, std::memory_order_relaxed);
+  info->bytes_wasted.fetch_add(wasted, std::memory_order_relaxed);
+  info->num_allocations.fetch_add(1, std::memory_order_relaxed);
+  const uint64_t tid = (1ULL << (GetCachedTID() % 63));
+  const uint64_t thread_ids = info->thread_ids.load(std::memory_order_relaxed);
+  if (!(thread_ids & tid)) {
+    info->thread_ids.store(thread_ids | tid, std::memory_order_relaxed);
+  }
+}
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
+  bool first = *next_sample < 0;
+  *next_sample = g_exponential_biased_generator.GetStride(
+      g_arenaz_sample_parameter.load(std::memory_order_relaxed));
+  // Small values of interval are equivalent to just sampling next time.
+  ABSL_ASSERT(*next_sample >= 1);
+
+  // g_arenaz_enabled can be dynamically flipped, we need to set a threshold low
+  // enough that we will start sampling in a reasonable time, so we just use the
+  // default sampling rate.
+  if (!g_arenaz_enabled.load(std::memory_order_relaxed)) return nullptr;
+  // We will only be negative on our first count, so we should just retry in
+  // that case.
+  if (first) {
+    if (PROTOBUF_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
+    return SampleSlow(next_sample);
+  }
+
+  return GlobalThreadSafeArenazSampler().Register();
+}
+
+void SetThreadSafeArenazEnabled(bool enabled) {
+  g_arenaz_enabled.store(enabled, std::memory_order_release);
+}
+
+void SetThreadSafeArenazSampleParameter(int32_t rate) {
+  if (rate > 0) {
+    g_arenaz_sample_parameter.store(rate, std::memory_order_release);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz sample rate: %lld",
+                 static_cast<long long>(rate));  // NOLINT(runtime/int)
+  }
+}
+
+void SetThreadSafeArenazMaxSamples(int32_t max) {
+  if (max > 0) {
+    GlobalThreadSafeArenazSampler().SetMaxSamples(max);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz max samples: %lld",
+                 static_cast<long long>(max));  // NOLINT(runtime/int)
+  }
+}
+
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {
+  if (next_sample >= 0) {
+    global_next_sample = next_sample;
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz next sample: %lld",
+                 static_cast<long long>(next_sample));  // NOLINT(runtime/int)
+  }
+}
+
+#else
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
+  *next_sample = std::numeric_limits<int64_t>::max();
+  return nullptr;
+}
+
+void SetThreadSafeArenazEnabled(bool enabled) {}
+void SetThreadSafeArenazSampleParameter(int32_t rate) {}
+void SetThreadSafeArenazMaxSamples(int32_t max) {}
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/compiler/importer.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/compiler/importer.cpp
new file mode 100644
index 0000000..678e87e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/compiler/importer.cpp
@@ -0,0 +1,524 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifdef _MSC_VER
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <memory>
+
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/compiler/parser.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/io_win32.h>
+
+#ifdef _WIN32
+#include <ctype.h>
+#endif
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+#ifdef _WIN32
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::open;
+#endif
+
+// Returns true if the text looks like a Windows-style absolute path, starting
+// with a drive letter.  Example:  "C:\foo".  TODO(kenton):  Share this with
+// copy in command_line_interface.cc?
+static bool IsWindowsAbsolutePath(const std::string& text) {
+#if defined(_WIN32) || defined(__CYGWIN__)
+  return text.size() >= 3 && text[1] == ':' && isalpha(text[0]) &&
+         (text[2] == '/' || text[2] == '\\') && text.find_last_of(':') == 1;
+#else
+  return false;
+#endif
+}
+
+MultiFileErrorCollector::~MultiFileErrorCollector() {}
+
+// This class serves two purposes:
+// - It implements the ErrorCollector interface (used by Tokenizer and Parser)
+//   in terms of MultiFileErrorCollector, using a particular filename.
+// - It lets us check if any errors have occurred.
+class SourceTreeDescriptorDatabase::SingleFileErrorCollector
+    : public io::ErrorCollector {
+ public:
+  SingleFileErrorCollector(const std::string& filename,
+                           MultiFileErrorCollector* multi_file_error_collector)
+      : filename_(filename),
+        multi_file_error_collector_(multi_file_error_collector),
+        had_errors_(false) {}
+  ~SingleFileErrorCollector() override {}
+
+  bool had_errors() { return had_errors_; }
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(int line, int column, const std::string& message) override {
+    if (multi_file_error_collector_ != nullptr) {
+      multi_file_error_collector_->AddError(filename_, line, column, message);
+    }
+    had_errors_ = true;
+  }
+
+ private:
+  std::string filename_;
+  MultiFileErrorCollector* multi_file_error_collector_;
+  bool had_errors_;
+};
+
+// ===================================================================
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+    SourceTree* source_tree)
+    : source_tree_(source_tree),
+      fallback_database_(nullptr),
+      error_collector_(nullptr),
+      using_validation_error_collector_(false),
+      validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+    SourceTree* source_tree, DescriptorDatabase* fallback_database)
+    : source_tree_(source_tree),
+      fallback_database_(fallback_database),
+      error_collector_(nullptr),
+      using_validation_error_collector_(false),
+      validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
+
+bool SourceTreeDescriptorDatabase::FindFileByName(const std::string& filename,
+                                                  FileDescriptorProto* output) {
+  std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
+  if (input == nullptr) {
+    if (fallback_database_ != nullptr &&
+        fallback_database_->FindFileByName(filename, output)) {
+      return true;
+    }
+    if (error_collector_ != nullptr) {
+      error_collector_->AddError(filename, -1, 0,
+                                 source_tree_->GetLastErrorMessage());
+    }
+    return false;
+  }
+
+  // Set up the tokenizer and parser.
+  SingleFileErrorCollector file_error_collector(filename, error_collector_);
+  io::Tokenizer tokenizer(input.get(), &file_error_collector);
+
+  Parser parser;
+  if (error_collector_ != nullptr) {
+    parser.RecordErrorsTo(&file_error_collector);
+  }
+  if (using_validation_error_collector_) {
+    parser.RecordSourceLocationsTo(&source_locations_);
+  }
+
+  // Parse it.
+  output->set_name(filename);
+  return parser.Parse(&tokenizer, output) && !file_error_collector.had_errors();
+}
+
+bool SourceTreeDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  return false;
+}
+
+bool SourceTreeDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  return false;
+}
+
+// -------------------------------------------------------------------
+
+SourceTreeDescriptorDatabase::ValidationErrorCollector::
+    ValidationErrorCollector(SourceTreeDescriptorDatabase* owner)
+    : owner_(owner) {}
+
+SourceTreeDescriptorDatabase::ValidationErrorCollector::
+    ~ValidationErrorCollector() {}
+
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError(
+    const std::string& filename, const std::string& element_name,
+    const Message* descriptor, ErrorLocation location,
+    const std::string& message) {
+  if (owner_->error_collector_ == nullptr) return;
+
+  int line, column;
+  if (location == DescriptorPool::ErrorCollector::IMPORT) {
+    owner_->source_locations_.FindImport(descriptor, element_name, &line,
+                                         &column);
+  } else {
+    owner_->source_locations_.Find(descriptor, location, &line, &column);
+  }
+  owner_->error_collector_->AddError(filename, line, column, message);
+}
+
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning(
+    const std::string& filename, const std::string& element_name,
+    const Message* descriptor, ErrorLocation location,
+    const std::string& message) {
+  if (owner_->error_collector_ == nullptr) return;
+
+  int line, column;
+  if (location == DescriptorPool::ErrorCollector::IMPORT) {
+    owner_->source_locations_.FindImport(descriptor, element_name, &line,
+                                         &column);
+  } else {
+    owner_->source_locations_.Find(descriptor, location, &line, &column);
+  }
+  owner_->error_collector_->AddWarning(filename, line, column, message);
+}
+
+// ===================================================================
+
+Importer::Importer(SourceTree* source_tree,
+                   MultiFileErrorCollector* error_collector)
+    : database_(source_tree),
+      pool_(&database_, database_.GetValidationErrorCollector()) {
+  pool_.EnforceWeakDependencies(true);
+  database_.RecordErrorsTo(error_collector);
+}
+
+Importer::~Importer() {}
+
+const FileDescriptor* Importer::Import(const std::string& filename) {
+  return pool_.FindFileByName(filename);
+}
+
+void Importer::AddUnusedImportTrackFile(const std::string& file_name,
+                                        bool is_error) {
+  pool_.AddUnusedImportTrackFile(file_name, is_error);
+}
+
+void Importer::ClearUnusedImportTrackFiles() {
+  pool_.ClearUnusedImportTrackFiles();
+}
+
+
+// ===================================================================
+
+SourceTree::~SourceTree() {}
+
+std::string SourceTree::GetLastErrorMessage() { return "File not found."; }
+
+DiskSourceTree::DiskSourceTree() {}
+
+DiskSourceTree::~DiskSourceTree() {}
+
+static inline char LastChar(const std::string& str) {
+  return str[str.size() - 1];
+}
+
+// Given a path, returns an equivalent path with these changes:
+// - On Windows, any backslashes are replaced with forward slashes.
+// - Any instances of the directory "." are removed.
+// - Any consecutive '/'s are collapsed into a single slash.
+// Note that the resulting string may be empty.
+//
+// TODO(kenton):  It would be nice to handle "..", e.g. so that we can figure
+//   out that "foo/bar.proto" is inside "baz/../foo".  However, if baz is a
+//   symlink or doesn't exist, then things get complicated, and we can't
+//   actually determine this without investigating the filesystem, probably
+//   in non-portable ways.  So, we punt.
+//
+// TODO(kenton):  It would be nice to use realpath() here except that it
+//   resolves symbolic links.  This could cause problems if people place
+//   symbolic links in their source tree.  For example, if you executed:
+//     protoc --proto_path=foo foo/bar/baz.proto
+//   then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize
+//   to a path which does not appear to be under foo, and thus the compiler
+//   will complain that baz.proto is not inside the --proto_path.
+static std::string CanonicalizePath(std::string path) {
+#ifdef _WIN32
+  // The Win32 API accepts forward slashes as a path delimiter even though
+  // backslashes are standard.  Let's avoid confusion and use only forward
+  // slashes.
+  if (HasPrefixString(path, "\\\\")) {
+    // Avoid converting two leading backslashes.
+    path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true);
+  } else {
+    path = StringReplace(path, "\\", "/", true);
+  }
+#endif
+
+  std::vector<std::string> canonical_parts;
+  std::vector<std::string> parts = Split(
+      path, "/", true);  // Note:  Removes empty parts.
+  for (const std::string& part : parts) {
+    if (part == ".") {
+      // Ignore.
+    } else {
+      canonical_parts.push_back(part);
+    }
+  }
+  std::string result = Join(canonical_parts, "/");
+  if (!path.empty() && path[0] == '/') {
+    // Restore leading slash.
+    result = '/' + result;
+  }
+  if (!path.empty() && LastChar(path) == '/' && !result.empty() &&
+      LastChar(result) != '/') {
+    // Restore trailing slash.
+    result += '/';
+  }
+  return result;
+}
+
+static inline bool ContainsParentReference(const std::string& path) {
+  return path == ".." || HasPrefixString(path, "../") ||
+         HasSuffixString(path, "/..") || path.find("/../") != std::string::npos;
+}
+
+// Maps a file from an old location to a new one.  Typically, old_prefix is
+// a virtual path and new_prefix is its corresponding disk path.  Returns
+// false if the filename did not start with old_prefix, otherwise replaces
+// old_prefix with new_prefix and stores the result in *result.  Examples:
+//   string result;
+//   assert(ApplyMapping("foo/bar", "", "baz", &result));
+//   assert(result == "baz/foo/bar");
+//
+//   assert(ApplyMapping("foo/bar", "foo", "baz", &result));
+//   assert(result == "baz/bar");
+//
+//   assert(ApplyMapping("foo", "foo", "bar", &result));
+//   assert(result == "bar");
+//
+//   assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
+//   assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
+//   assert(!ApplyMapping("foobar", "foo", "baz", &result));
+static bool ApplyMapping(const std::string& filename,
+                         const std::string& old_prefix,
+                         const std::string& new_prefix, std::string* result) {
+  if (old_prefix.empty()) {
+    // old_prefix matches any relative path.
+    if (ContainsParentReference(filename)) {
+      // We do not allow the file name to use "..".
+      return false;
+    }
+    if (HasPrefixString(filename, "/") || IsWindowsAbsolutePath(filename)) {
+      // This is an absolute path, so it isn't matched by the empty string.
+      return false;
+    }
+    result->assign(new_prefix);
+    if (!result->empty()) result->push_back('/');
+    result->append(filename);
+    return true;
+  } else if (HasPrefixString(filename, old_prefix)) {
+    // old_prefix is a prefix of the filename.  Is it the whole filename?
+    if (filename.size() == old_prefix.size()) {
+      // Yep, it's an exact match.
+      *result = new_prefix;
+      return true;
+    } else {
+      // Not an exact match.  Is the next character a '/'?  Otherwise,
+      // this isn't actually a match at all.  E.g. the prefix "foo/bar"
+      // does not match the filename "foo/barbaz".
+      int after_prefix_start = -1;
+      if (filename[old_prefix.size()] == '/') {
+        after_prefix_start = old_prefix.size() + 1;
+      } else if (filename[old_prefix.size() - 1] == '/') {
+        // old_prefix is never empty, and canonicalized paths never have
+        // consecutive '/' characters.
+        after_prefix_start = old_prefix.size();
+      }
+      if (after_prefix_start != -1) {
+        // Yep.  So the prefixes are directories and the filename is a file
+        // inside them.
+        std::string after_prefix = filename.substr(after_prefix_start);
+        if (ContainsParentReference(after_prefix)) {
+          // We do not allow the file name to use "..".
+          return false;
+        }
+        result->assign(new_prefix);
+        if (!result->empty()) result->push_back('/');
+        result->append(after_prefix);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+void DiskSourceTree::MapPath(const std::string& virtual_path,
+                             const std::string& disk_path) {
+  mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path)));
+}
+
+DiskSourceTree::DiskFileToVirtualFileResult
+DiskSourceTree::DiskFileToVirtualFile(const std::string& disk_file,
+                                      std::string* virtual_file,
+                                      std::string* shadowing_disk_file) {
+  int mapping_index = -1;
+  std::string canonical_disk_file = CanonicalizePath(disk_file);
+
+  for (size_t i = 0; i < mappings_.size(); i++) {
+    // Apply the mapping in reverse.
+    if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path,
+                     mappings_[i].virtual_path, virtual_file)) {
+      // Success.
+      mapping_index = i;
+      break;
+    }
+  }
+
+  if (mapping_index == -1) {
+    return NO_MAPPING;
+  }
+
+  // Iterate through all mappings with higher precedence and verify that none
+  // of them map this file to some other existing file.
+  for (int i = 0; i < mapping_index; i++) {
+    if (ApplyMapping(*virtual_file, mappings_[i].virtual_path,
+                     mappings_[i].disk_path, shadowing_disk_file)) {
+      if (access(shadowing_disk_file->c_str(), F_OK) >= 0) {
+        // File exists.
+        return SHADOWED;
+      }
+    }
+  }
+  shadowing_disk_file->clear();
+
+  // Verify that we can open the file.  Note that this also has the side-effect
+  // of verifying that we are not canonicalizing away any non-existent
+  // directories.
+  std::unique_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
+  if (stream == nullptr) {
+    return CANNOT_OPEN;
+  }
+
+  return SUCCESS;
+}
+
+bool DiskSourceTree::VirtualFileToDiskFile(const std::string& virtual_file,
+                                           std::string* disk_file) {
+  std::unique_ptr<io::ZeroCopyInputStream> stream(
+      OpenVirtualFile(virtual_file, disk_file));
+  return stream != nullptr;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::Open(const std::string& filename) {
+  return OpenVirtualFile(filename, nullptr);
+}
+
+std::string DiskSourceTree::GetLastErrorMessage() {
+  return last_error_message_;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
+    const std::string& virtual_file, std::string* disk_file) {
+  if (virtual_file != CanonicalizePath(virtual_file) ||
+      ContainsParentReference(virtual_file)) {
+    // We do not allow importing of paths containing things like ".." or
+    // consecutive slashes since the compiler expects files to be uniquely
+    // identified by file name.
+    last_error_message_ =
+        "Backslashes, consecutive slashes, \".\", or \"..\" "
+        "are not allowed in the virtual path";
+    return nullptr;
+  }
+
+  for (const auto& mapping : mappings_) {
+    std::string temp_disk_file;
+    if (ApplyMapping(virtual_file, mapping.virtual_path, mapping.disk_path,
+                     &temp_disk_file)) {
+      io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file);
+      if (stream != nullptr) {
+        if (disk_file != nullptr) {
+          *disk_file = temp_disk_file;
+        }
+        return stream;
+      }
+
+      if (errno == EACCES) {
+        // The file exists but is not readable.
+        last_error_message_ =
+            "Read access is denied for file: " + temp_disk_file;
+        return nullptr;
+      }
+    }
+  }
+  last_error_message_ = "File not found.";
+  return nullptr;
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile(
+    const std::string& filename) {
+  struct stat sb;
+  int ret = 0;
+  do {
+    ret = stat(filename.c_str(), &sb);
+  } while (ret != 0 && errno == EINTR);
+#if defined(_WIN32)
+  if (ret == 0 && sb.st_mode & S_IFDIR) {
+    last_error_message_ = "Input file is a directory.";
+    return nullptr;
+  }
+#else
+  if (ret == 0 && S_ISDIR(sb.st_mode)) {
+    last_error_message_ = "Input file is a directory.";
+    return nullptr;
+  }
+#endif
+  int file_descriptor;
+  do {
+    file_descriptor = open(filename.c_str(), O_RDONLY);
+  } while (file_descriptor < 0 && errno == EINTR);
+  if (file_descriptor >= 0) {
+    io::FileInputStream* result = new io::FileInputStream(file_descriptor);
+    result->SetCloseOnDelete(true);
+    return result;
+  } else {
+    return nullptr;
+  }
+}
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/compiler/parser.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/compiler/parser.cpp
new file mode 100644
index 0000000..e36a4a7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/compiler/parser.cpp
@@ -0,0 +1,2446 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Recursive descent FTW.
+
+#include <google/protobuf/compiler/parser.h>
+
+#include <float.h>
+
+#include <cstdint>
+#include <limits>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+using internal::WireFormat;
+
+namespace {
+
+typedef std::unordered_map<std::string, FieldDescriptorProto::Type> TypeNameMap;
+
+const TypeNameMap& GetTypeNameTable() {
+  static auto* table = new auto([]() {
+    TypeNameMap result;
+
+    result["double"] = FieldDescriptorProto::TYPE_DOUBLE;
+    result["float"] = FieldDescriptorProto::TYPE_FLOAT;
+    result["uint64"] = FieldDescriptorProto::TYPE_UINT64;
+    result["fixed64"] = FieldDescriptorProto::TYPE_FIXED64;
+    result["fixed32"] = FieldDescriptorProto::TYPE_FIXED32;
+    result["bool"] = FieldDescriptorProto::TYPE_BOOL;
+    result["string"] = FieldDescriptorProto::TYPE_STRING;
+    result["group"] = FieldDescriptorProto::TYPE_GROUP;
+
+    result["bytes"] = FieldDescriptorProto::TYPE_BYTES;
+    result["uint32"] = FieldDescriptorProto::TYPE_UINT32;
+    result["sfixed32"] = FieldDescriptorProto::TYPE_SFIXED32;
+    result["sfixed64"] = FieldDescriptorProto::TYPE_SFIXED64;
+    result["int32"] = FieldDescriptorProto::TYPE_INT32;
+    result["int64"] = FieldDescriptorProto::TYPE_INT64;
+    result["sint32"] = FieldDescriptorProto::TYPE_SINT32;
+    result["sint64"] = FieldDescriptorProto::TYPE_SINT64;
+
+    return result;
+  }());
+  return *table;
+}
+
+// Camel-case the field name and append "Entry" for generated map entry name.
+// e.g. map<KeyType, ValueType> foo_map => FooMapEntry
+std::string MapEntryName(const std::string& field_name) {
+  std::string result;
+  static const char kSuffix[] = "Entry";
+  result.reserve(field_name.size() + sizeof(kSuffix));
+  bool cap_next = true;
+  for (const char field_name_char : field_name) {
+    if (field_name_char == '_') {
+      cap_next = true;
+    } else if (cap_next) {
+      // Note: Do not use ctype.h due to locales.
+      if ('a' <= field_name_char && field_name_char <= 'z') {
+        result.push_back(field_name_char - 'a' + 'A');
+      } else {
+        result.push_back(field_name_char);
+      }
+      cap_next = false;
+    } else {
+      result.push_back(field_name_char);
+    }
+  }
+  result.append(kSuffix);
+  return result;
+}
+
+bool IsUppercase(char c) { return c >= 'A' && c <= 'Z'; }
+
+bool IsLowercase(char c) { return c >= 'a' && c <= 'z'; }
+
+bool IsNumber(char c) { return c >= '0' && c <= '9'; }
+
+bool IsUpperCamelCase(const std::string& name) {
+  if (name.empty()) {
+    return true;
+  }
+  // Name must start with an upper case character.
+  if (!IsUppercase(name[0])) {
+    return false;
+  }
+  // Must not contains underscore.
+  for (const char c : name) {
+    if (c == '_') {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IsUpperUnderscore(const std::string& name) {
+  for (const char c : name) {
+    if (!IsUppercase(c) && c != '_' && !IsNumber(c)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IsLowerUnderscore(const std::string& name) {
+  for (const char c : name) {
+    if (!IsLowercase(c) && c != '_' && !IsNumber(c)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IsNumberFollowUnderscore(const std::string& name) {
+  for (size_t i = 1; i < name.length(); i++) {
+    const char c = name[i];
+    if (IsNumber(c) && name[i - 1] == '_') {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // anonymous namespace
+
+// Makes code slightly more readable.  The meaning of "DO(foo)" is
+// "Execute foo and fail if it fails.", where failure is indicated by
+// returning false.
+#define DO(STATEMENT) \
+  if (STATEMENT) {    \
+  } else              \
+    return false
+
+// ===================================================================
+
+Parser::Parser()
+    : input_(nullptr),
+      error_collector_(nullptr),
+      source_location_table_(nullptr),
+      had_errors_(false),
+      require_syntax_identifier_(false),
+      stop_after_syntax_identifier_(false) {
+}
+
+Parser::~Parser() {}
+
+// ===================================================================
+
+inline bool Parser::LookingAt(const char* text) {
+  return input_->current().text == text;
+}
+
+inline bool Parser::LookingAtType(io::Tokenizer::TokenType token_type) {
+  return input_->current().type == token_type;
+}
+
+inline bool Parser::AtEnd() { return LookingAtType(io::Tokenizer::TYPE_END); }
+
+bool Parser::TryConsume(const char* text) {
+  if (LookingAt(text)) {
+    input_->Next();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool Parser::Consume(const char* text, const char* error) {
+  if (TryConsume(text)) {
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::Consume(const char* text) {
+  std::string error = "Expected \"" + std::string(text) + "\".";
+  return Consume(text, error.c_str());
+}
+
+bool Parser::ConsumeIdentifier(std::string* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+    *output = input_->current().text;
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeInteger(int* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+    uint64_t value = 0;
+    if (!io::Tokenizer::ParseInteger(input_->current().text,
+                                     std::numeric_limits<int32_t>::max(),
+                                     &value)) {
+      AddError("Integer out of range.");
+      // We still return true because we did, in fact, parse an integer.
+    }
+    *output = value;
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeSignedInteger(int* output, const char* error) {
+  bool is_negative = false;
+  uint64_t max_value = std::numeric_limits<int32_t>::max();
+  if (TryConsume("-")) {
+    is_negative = true;
+    max_value += 1;
+  }
+  uint64_t value = 0;
+  DO(ConsumeInteger64(max_value, &value, error));
+  if (is_negative) value *= -1;
+  *output = value;
+  return true;
+}
+
+bool Parser::ConsumeInteger64(uint64_t max_value, uint64_t* output,
+                              const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+    if (!io::Tokenizer::ParseInteger(input_->current().text, max_value,
+                                     output)) {
+      AddError("Integer out of range.");
+      // We still return true because we did, in fact, parse an integer.
+      *output = 0;
+    }
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeNumber(double* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
+    *output = io::Tokenizer::ParseFloat(input_->current().text);
+    input_->Next();
+    return true;
+  } else if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+    // Also accept integers.
+    uint64_t value = 0;
+    if (!io::Tokenizer::ParseInteger(input_->current().text,
+                                     std::numeric_limits<uint64_t>::max(),
+                                     &value)) {
+      AddError("Integer out of range.");
+      // We still return true because we did, in fact, parse a number.
+    }
+    *output = value;
+    input_->Next();
+    return true;
+  } else if (LookingAt("inf")) {
+    *output = std::numeric_limits<double>::infinity();
+    input_->Next();
+    return true;
+  } else if (LookingAt("nan")) {
+    *output = std::numeric_limits<double>::quiet_NaN();
+    input_->Next();
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::ConsumeString(std::string* output, const char* error) {
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    io::Tokenizer::ParseString(input_->current().text, output);
+    input_->Next();
+    // Allow C++ like concatenation of adjacent string tokens.
+    while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      io::Tokenizer::ParseStringAppend(input_->current().text, output);
+      input_->Next();
+    }
+    return true;
+  } else {
+    AddError(error);
+    return false;
+  }
+}
+
+bool Parser::TryConsumeEndOfDeclaration(const char* text,
+                                        const LocationRecorder* location) {
+  if (LookingAt(text)) {
+    std::string leading, trailing;
+    std::vector<std::string> detached;
+    input_->NextWithComments(&trailing, &detached, &leading);
+
+    // Save the leading comments for next time, and recall the leading comments
+    // from last time.
+    leading.swap(upcoming_doc_comments_);
+
+    if (location != nullptr) {
+      upcoming_detached_comments_.swap(detached);
+      location->AttachComments(&leading, &trailing, &detached);
+    } else if (strcmp(text, "}") == 0) {
+      // If the current location is null and we are finishing the current scope,
+      // drop pending upcoming detached comments.
+      upcoming_detached_comments_.swap(detached);
+    } else {
+      // Otherwise, append the new detached comments to the existing upcoming
+      // detached comments.
+      upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
+                                         detached.begin(), detached.end());
+    }
+
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool Parser::ConsumeEndOfDeclaration(const char* text,
+                                     const LocationRecorder* location) {
+  if (TryConsumeEndOfDeclaration(text, location)) {
+    return true;
+  } else {
+    AddError("Expected \"" + std::string(text) + "\".");
+    return false;
+  }
+}
+
+// -------------------------------------------------------------------
+
+void Parser::AddError(int line, int column, const std::string& error) {
+  if (error_collector_ != nullptr) {
+    error_collector_->AddError(line, column, error);
+  }
+  had_errors_ = true;
+}
+
+void Parser::AddError(const std::string& error) {
+  AddError(input_->current().line, input_->current().column, error);
+}
+
+void Parser::AddWarning(const std::string& warning) {
+  if (error_collector_ != nullptr) {
+    error_collector_->AddWarning(input_->current().line,
+                                 input_->current().column, warning);
+  }
+}
+
+// -------------------------------------------------------------------
+
+Parser::LocationRecorder::LocationRecorder(Parser* parser)
+    : parser_(parser),
+      source_code_info_(parser->source_code_info_),
+      location_(parser_->source_code_info_->add_location()) {
+  location_->add_span(parser_->input_->current().line);
+  location_->add_span(parser_->input_->current().column);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) {
+  Init(parent, parent.source_code_info_);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1,
+                                           SourceCodeInfo* source_code_info) {
+  Init(parent, source_code_info);
+  AddPath(path1);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1) {
+  Init(parent, parent.source_code_info_);
+  AddPath(path1);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1, int path2) {
+  Init(parent, parent.source_code_info_);
+  AddPath(path1);
+  AddPath(path2);
+}
+
+void Parser::LocationRecorder::Init(const LocationRecorder& parent,
+                                    SourceCodeInfo* source_code_info) {
+  parser_ = parent.parser_;
+  source_code_info_ = source_code_info;
+
+  location_ = source_code_info_->add_location();
+  location_->mutable_path()->CopyFrom(parent.location_->path());
+
+  location_->add_span(parser_->input_->current().line);
+  location_->add_span(parser_->input_->current().column);
+}
+
+Parser::LocationRecorder::~LocationRecorder() {
+  if (location_->span_size() <= 2) {
+    EndAt(parser_->input_->previous());
+  }
+}
+
+void Parser::LocationRecorder::AddPath(int path_component) {
+  location_->add_path(path_component);
+}
+
+void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) {
+  location_->set_span(0, token.line);
+  location_->set_span(1, token.column);
+}
+
+void Parser::LocationRecorder::StartAt(const LocationRecorder& other) {
+  location_->set_span(0, other.location_->span(0));
+  location_->set_span(1, other.location_->span(1));
+}
+
+void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) {
+  if (token.line != location_->span(0)) {
+    location_->add_span(token.line);
+  }
+  location_->add_span(token.end_column);
+}
+
+void Parser::LocationRecorder::RecordLegacyLocation(
+    const Message* descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location) {
+  if (parser_->source_location_table_ != nullptr) {
+    parser_->source_location_table_->Add(
+        descriptor, location, location_->span(0), location_->span(1));
+  }
+}
+
+void Parser::LocationRecorder::RecordLegacyImportLocation(
+    const Message* descriptor, const std::string& name) {
+  if (parser_->source_location_table_ != nullptr) {
+    parser_->source_location_table_->AddImport(
+        descriptor, name, location_->span(0), location_->span(1));
+  }
+}
+
+int Parser::LocationRecorder::CurrentPathSize() const {
+  return location_->path_size();
+}
+
+void Parser::LocationRecorder::AttachComments(
+    std::string* leading, std::string* trailing,
+    std::vector<std::string>* detached_comments) const {
+  GOOGLE_CHECK(!location_->has_leading_comments());
+  GOOGLE_CHECK(!location_->has_trailing_comments());
+
+  if (!leading->empty()) {
+    location_->mutable_leading_comments()->swap(*leading);
+  }
+  if (!trailing->empty()) {
+    location_->mutable_trailing_comments()->swap(*trailing);
+  }
+  for (size_t i = 0; i < detached_comments->size(); ++i) {
+    location_->add_leading_detached_comments()->swap((*detached_comments)[i]);
+  }
+  detached_comments->clear();
+}
+
+// -------------------------------------------------------------------
+
+void Parser::SkipStatement() {
+  while (true) {
+    if (AtEnd()) {
+      return;
+    } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
+      if (TryConsumeEndOfDeclaration(";", nullptr)) {
+        return;
+      } else if (TryConsume("{")) {
+        SkipRestOfBlock();
+        return;
+      } else if (LookingAt("}")) {
+        return;
+      }
+    }
+    input_->Next();
+  }
+}
+
+void Parser::SkipRestOfBlock() {
+  while (true) {
+    if (AtEnd()) {
+      return;
+    } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
+      if (TryConsumeEndOfDeclaration("}", nullptr)) {
+        return;
+      } else if (TryConsume("{")) {
+        SkipRestOfBlock();
+      }
+    }
+    input_->Next();
+  }
+}
+
+// ===================================================================
+
+bool Parser::ValidateEnum(const EnumDescriptorProto* proto) {
+  bool has_allow_alias = false;
+  bool allow_alias = false;
+
+  for (int i = 0; i < proto->options().uninterpreted_option_size(); i++) {
+    const UninterpretedOption option = proto->options().uninterpreted_option(i);
+    if (option.name_size() > 1) {
+      continue;
+    }
+    if (!option.name(0).is_extension() &&
+        option.name(0).name_part() == "allow_alias") {
+      has_allow_alias = true;
+      if (option.identifier_value() == "true") {
+        allow_alias = true;
+      }
+      break;
+    }
+  }
+
+  if (has_allow_alias && !allow_alias) {
+    std::string error =
+        "\"" + proto->name() +
+        "\" declares 'option allow_alias = false;' which has no effect. "
+        "Please remove the declaration.";
+    // This needlessly clutters declarations with nops.
+    AddError(error);
+    return false;
+  }
+
+  std::set<int> used_values;
+  bool has_duplicates = false;
+  for (int i = 0; i < proto->value_size(); ++i) {
+    const EnumValueDescriptorProto& enum_value = proto->value(i);
+    if (used_values.find(enum_value.number()) != used_values.end()) {
+      has_duplicates = true;
+      break;
+    } else {
+      used_values.insert(enum_value.number());
+    }
+  }
+  if (allow_alias && !has_duplicates) {
+    std::string error =
+        "\"" + proto->name() +
+        "\" declares support for enum aliases but no enum values share field "
+        "numbers. Please remove the unnecessary 'option allow_alias = true;' "
+        "declaration.";
+    // Generate an error if an enum declares support for duplicate enum values
+    // and does not use it protect future authors.
+    AddError(error);
+    return false;
+  }
+
+  // Enforce that enum constants must be UPPER_CASE except in case of
+  // enum_alias.
+  if (!allow_alias) {
+    for (const auto& enum_value : proto->value()) {
+      if (!IsUpperUnderscore(enum_value.name())) {
+        AddWarning(
+            "Enum constant should be in UPPER_CASE. Found: " +
+            enum_value.name() +
+            ". See https://developers.google.com/protocol-buffers/docs/style");
+      }
+    }
+  }
+
+  return true;
+}
+
+bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
+  input_ = input;
+  had_errors_ = false;
+  syntax_identifier_.clear();
+
+  // Note that |file| could be NULL at this point if
+  // stop_after_syntax_identifier_ is true.  So, we conservatively allocate
+  // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto
+  // later on.
+  SourceCodeInfo source_code_info;
+  source_code_info_ = &source_code_info;
+
+  if (LookingAtType(io::Tokenizer::TYPE_START)) {
+    // Advance to first token.
+    input_->NextWithComments(nullptr, &upcoming_detached_comments_,
+                             &upcoming_doc_comments_);
+  }
+
+  {
+    LocationRecorder root_location(this);
+    root_location.RecordLegacyLocation(file,
+                                       DescriptorPool::ErrorCollector::OTHER);
+
+    if (require_syntax_identifier_ || LookingAt("syntax")) {
+      if (!ParseSyntaxIdentifier(root_location)) {
+        // Don't attempt to parse the file if we didn't recognize the syntax
+        // identifier.
+        return false;
+      }
+      // Store the syntax into the file.
+      if (file != nullptr) file->set_syntax(syntax_identifier_);
+    } else if (!stop_after_syntax_identifier_) {
+      GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: " << file->name()
+                   << ". Please use 'syntax = \"proto2\";' "
+                   << "or 'syntax = \"proto3\";' to specify a syntax "
+                   << "version. (Defaulted to proto2 syntax.)";
+      syntax_identifier_ = "proto2";
+    }
+
+    if (stop_after_syntax_identifier_) return !had_errors_;
+
+    // Repeatedly parse statements until we reach the end of the file.
+    while (!AtEnd()) {
+      if (!ParseTopLevelStatement(file, root_location)) {
+        // This statement failed to parse.  Skip it, but keep looping to parse
+        // other statements.
+        SkipStatement();
+
+        if (LookingAt("}")) {
+          AddError("Unmatched \"}\".");
+          input_->NextWithComments(nullptr, &upcoming_detached_comments_,
+                                   &upcoming_doc_comments_);
+        }
+      }
+    }
+  }
+
+  input_ = nullptr;
+  source_code_info_ = nullptr;
+  assert(file != nullptr);
+  source_code_info.Swap(file->mutable_source_code_info());
+  return !had_errors_;
+}
+
+bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
+  LocationRecorder syntax_location(parent,
+                                   FileDescriptorProto::kSyntaxFieldNumber);
+  DO(Consume(
+      "syntax",
+      "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
+  DO(Consume("="));
+  io::Tokenizer::Token syntax_token = input_->current();
+  std::string syntax;
+  DO(ConsumeString(&syntax, "Expected syntax identifier."));
+  DO(ConsumeEndOfDeclaration(";", &syntax_location));
+
+  syntax_identifier_ = syntax;
+
+  if (syntax != "proto2" && syntax != "proto3" &&
+      !stop_after_syntax_identifier_) {
+    AddError(syntax_token.line, syntax_token.column,
+             "Unrecognized syntax identifier \"" + syntax +
+                 "\".  This parser "
+                 "only recognizes \"proto2\" and \"proto3\".");
+    return false;
+  }
+
+  return true;
+}
+
+bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
+                                    const LocationRecorder& root_location) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("message")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kMessageTypeFieldNumber,
+                              file->message_type_size());
+    return ParseMessageDefinition(file->add_message_type(), location, file);
+  } else if (LookingAt("enum")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kEnumTypeFieldNumber,
+                              file->enum_type_size());
+    return ParseEnumDefinition(file->add_enum_type(), location, file);
+  } else if (LookingAt("service")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kServiceFieldNumber,
+                              file->service_size());
+    return ParseServiceDefinition(file->add_service(), location, file);
+  } else if (LookingAt("extend")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kExtensionFieldNumber);
+    return ParseExtend(
+        file->mutable_extension(), file->mutable_message_type(), root_location,
+        FileDescriptorProto::kMessageTypeFieldNumber, location, file);
+  } else if (LookingAt("import")) {
+    return ParseImport(file->mutable_dependency(),
+                       file->mutable_public_dependency(),
+                       file->mutable_weak_dependency(), root_location, file);
+  } else if (LookingAt("package")) {
+    return ParsePackage(file, root_location, file);
+  } else if (LookingAt("option")) {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(file->mutable_options(), location, file,
+                       OPTION_STATEMENT);
+  } else {
+    AddError("Expected top-level statement (e.g. \"message\").");
+    return false;
+  }
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+bool Parser::ParseMessageDefinition(
+    DescriptorProto* message, const LocationRecorder& message_location,
+    const FileDescriptorProto* containing_file) {
+  DO(Consume("message"));
+  {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(message,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
+    if (!IsUpperCamelCase(message->name())) {
+      AddWarning(
+          "Message name should be in UpperCamelCase. Found: " +
+          message->name() +
+          ". See https://developers.google.com/protocol-buffers/docs/style");
+    }
+  }
+  DO(ParseMessageBlock(message, message_location, containing_file));
+
+  if (syntax_identifier_ == "proto3") {
+    // Add synthetic one-field oneofs for optional fields, except messages which
+    // already have presence in proto3.
+    //
+    // We have to make sure the oneof names don't conflict with any other
+    // field or oneof.
+    std::unordered_set<std::string> names;
+    for (const auto& field : message->field()) {
+      names.insert(field.name());
+    }
+    for (const auto& oneof : message->oneof_decl()) {
+      names.insert(oneof.name());
+    }
+
+    for (auto& field : *message->mutable_field()) {
+      if (field.proto3_optional()) {
+        std::string oneof_name = field.name();
+
+        // Prepend 'XXXXX_' until we are no longer conflicting.
+        // Avoid prepending a double-underscore because such names are
+        // reserved in C++.
+        if (oneof_name.empty() || oneof_name[0] != '_') {
+          oneof_name = '_' + oneof_name;
+        }
+        while (names.count(oneof_name) > 0) {
+          oneof_name = 'X' + oneof_name;
+        }
+
+        names.insert(oneof_name);
+        field.set_oneof_index(message->oneof_decl_size());
+        OneofDescriptorProto* oneof = message->add_oneof_decl();
+        oneof->set_name(oneof_name);
+      }
+    }
+  }
+
+  return true;
+}
+
+namespace {
+
+const int kMaxRangeSentinel = -1;
+
+bool IsMessageSetWireFormatMessage(const DescriptorProto& message) {
+  const MessageOptions& options = message.options();
+  for (int i = 0; i < options.uninterpreted_option_size(); ++i) {
+    const UninterpretedOption& uninterpreted = options.uninterpreted_option(i);
+    if (uninterpreted.name_size() == 1 &&
+        uninterpreted.name(0).name_part() == "message_set_wire_format" &&
+        uninterpreted.identifier_value() == "true") {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Modifies any extension ranges that specified 'max' as the end of the
+// extension range, and sets them to the type-specific maximum. The actual max
+// tag number can only be determined after all options have been parsed.
+void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) {
+  const bool is_message_set = IsMessageSetWireFormatMessage(*message);
+  const int max_extension_number = is_message_set
+                                       ? std::numeric_limits<int32_t>::max()
+                                       : FieldDescriptor::kMaxNumber + 1;
+  for (int i = 0; i < message->extension_range_size(); ++i) {
+    if (message->extension_range(i).end() == kMaxRangeSentinel) {
+      message->mutable_extension_range(i)->set_end(max_extension_number);
+    }
+  }
+}
+
+// Modifies any reserved ranges that specified 'max' as the end of the
+// reserved range, and sets them to the type-specific maximum. The actual max
+// tag number can only be determined after all options have been parsed.
+void AdjustReservedRangesWithMaxEndNumber(DescriptorProto* message) {
+  const bool is_message_set = IsMessageSetWireFormatMessage(*message);
+  const int max_field_number = is_message_set
+                                   ? std::numeric_limits<int32_t>::max()
+                                   : FieldDescriptor::kMaxNumber + 1;
+  for (int i = 0; i < message->reserved_range_size(); ++i) {
+    if (message->reserved_range(i).end() == kMaxRangeSentinel) {
+      message->mutable_reserved_range(i)->set_end(max_field_number);
+    }
+  }
+}
+
+}  // namespace
+
+bool Parser::ParseMessageBlock(DescriptorProto* message,
+                               const LocationRecorder& message_location,
+                               const FileDescriptorProto* containing_file) {
+  DO(ConsumeEndOfDeclaration("{", &message_location));
+
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in message definition (missing '}').");
+      return false;
+    }
+
+    if (!ParseMessageStatement(message, message_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  }
+
+  if (message->extension_range_size() > 0) {
+    AdjustExtensionRangesWithMaxEndNumber(message);
+  }
+  if (message->reserved_range_size() > 0) {
+    AdjustReservedRangesWithMaxEndNumber(message);
+  }
+  return true;
+}
+
+bool Parser::ParseMessageStatement(DescriptorProto* message,
+                                   const LocationRecorder& message_location,
+                                   const FileDescriptorProto* containing_file) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("message")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kNestedTypeFieldNumber,
+                              message->nested_type_size());
+    return ParseMessageDefinition(message->add_nested_type(), location,
+                                  containing_file);
+  } else if (LookingAt("enum")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kEnumTypeFieldNumber,
+                              message->enum_type_size());
+    return ParseEnumDefinition(message->add_enum_type(), location,
+                               containing_file);
+  } else if (LookingAt("extensions")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kExtensionRangeFieldNumber);
+    return ParseExtensions(message, location, containing_file);
+  } else if (LookingAt("reserved")) {
+    return ParseReserved(message, message_location);
+  } else if (LookingAt("extend")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kExtensionFieldNumber);
+    return ParseExtend(message->mutable_extension(),
+                       message->mutable_nested_type(), message_location,
+                       DescriptorProto::kNestedTypeFieldNumber, location,
+                       containing_file);
+  } else if (LookingAt("option")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kOptionsFieldNumber);
+    return ParseOption(message->mutable_options(), location, containing_file,
+                       OPTION_STATEMENT);
+  } else if (LookingAt("oneof")) {
+    int oneof_index = message->oneof_decl_size();
+    LocationRecorder oneof_location(
+        message_location, DescriptorProto::kOneofDeclFieldNumber, oneof_index);
+
+    return ParseOneof(message->add_oneof_decl(), message, oneof_index,
+                      oneof_location, message_location, containing_file);
+  } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kFieldFieldNumber,
+                              message->field_size());
+    return ParseMessageField(
+        message->add_field(), message->mutable_nested_type(), message_location,
+        DescriptorProto::kNestedTypeFieldNumber, location, containing_file);
+  }
+}
+
+bool Parser::ParseMessageField(FieldDescriptorProto* field,
+                               RepeatedPtrField<DescriptorProto>* messages,
+                               const LocationRecorder& parent_location,
+                               int location_field_number_for_nested_type,
+                               const LocationRecorder& field_location,
+                               const FileDescriptorProto* containing_file) {
+  {
+    FieldDescriptorProto::Label label;
+    if (ParseLabel(&label, field_location)) {
+      field->set_label(label);
+      if (label == FieldDescriptorProto::LABEL_OPTIONAL &&
+          syntax_identifier_ == "proto3") {
+        field->set_proto3_optional(true);
+      }
+    }
+  }
+
+  return ParseMessageFieldNoLabel(field, messages, parent_location,
+                                  location_field_number_for_nested_type,
+                                  field_location, containing_file);
+}
+
+bool Parser::ParseMessageFieldNoLabel(
+    FieldDescriptorProto* field, RepeatedPtrField<DescriptorProto>* messages,
+    const LocationRecorder& parent_location,
+    int location_field_number_for_nested_type,
+    const LocationRecorder& field_location,
+    const FileDescriptorProto* containing_file) {
+  MapField map_field;
+  // Parse type.
+  {
+    LocationRecorder location(field_location);  // add path later
+    location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE);
+
+    bool type_parsed = false;
+    FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
+    std::string type_name;
+
+    // Special case map field. We only treat the field as a map field if the
+    // field type name starts with the word "map" with a following "<".
+    if (TryConsume("map")) {
+      if (LookingAt("<")) {
+        map_field.is_map_field = true;
+        DO(ParseMapType(&map_field, field, location));
+      } else {
+        // False positive
+        type_parsed = true;
+        type_name = "map";
+      }
+    }
+    if (!map_field.is_map_field) {
+      // Handle the case where no explicit label is given for a non-map field.
+      if (!field->has_label() && DefaultToOptionalFields()) {
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+      }
+      if (!field->has_label()) {
+        AddError("Expected \"required\", \"optional\", or \"repeated\".");
+        // We can actually reasonably recover here by just assuming the user
+        // forgot the label altogether.
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+      }
+
+      // Handle the case where the actual type is a message or enum named
+      // "map", which we already consumed in the code above.
+      if (!type_parsed) {
+        DO(ParseType(&type, &type_name));
+      }
+      if (type_name.empty()) {
+        location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
+        field->set_type(type);
+      } else {
+        location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
+        field->set_type_name(type_name);
+      }
+    }
+  }
+
+  // Parse name and '='.
+  io::Tokenizer::Token name_token = input_->current();
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
+
+    if (!IsLowerUnderscore(field->name())) {
+      AddWarning(
+          "Field name should be lowercase. Found: " + field->name() +
+          ". See: https://developers.google.com/protocol-buffers/docs/style");
+    }
+    if (IsNumberFollowUnderscore(field->name())) {
+      AddWarning(
+          "Number should not come right after an underscore. Found: " +
+          field->name() +
+          ". See: https://developers.google.com/protocol-buffers/docs/style");
+    }
+  }
+  DO(Consume("=", "Missing field number."));
+
+  // Parse field number.
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kNumberFieldNumber);
+    location.RecordLegacyLocation(field,
+                                  DescriptorPool::ErrorCollector::NUMBER);
+    int number;
+    DO(ConsumeInteger(&number, "Expected field number."));
+    field->set_number(number);
+  }
+
+  // Parse options.
+  DO(ParseFieldOptions(field, field_location, containing_file));
+
+  // Deal with groups.
+  if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) {
+    // Awkward:  Since a group declares both a message type and a field, we
+    //   have to create overlapping locations.
+    LocationRecorder group_location(parent_location);
+    group_location.StartAt(field_location);
+    group_location.AddPath(location_field_number_for_nested_type);
+    group_location.AddPath(messages->size());
+
+    DescriptorProto* group = messages->Add();
+    group->set_name(field->name());
+
+    // Record name location to match the field name's location.
+    {
+      LocationRecorder location(group_location,
+                                DescriptorProto::kNameFieldNumber);
+      location.StartAt(name_token);
+      location.EndAt(name_token);
+      location.RecordLegacyLocation(group,
+                                    DescriptorPool::ErrorCollector::NAME);
+    }
+
+    // The field's type_name also comes from the name.  Confusing!
+    {
+      LocationRecorder location(field_location,
+                                FieldDescriptorProto::kTypeNameFieldNumber);
+      location.StartAt(name_token);
+      location.EndAt(name_token);
+    }
+
+    // As a hack for backwards-compatibility, we force the group name to start
+    // with a capital letter and lower-case the field name.  New code should
+    // not use groups; it should use nested messages.
+    if (group->name()[0] < 'A' || 'Z' < group->name()[0]) {
+      AddError(name_token.line, name_token.column,
+               "Group names must start with a capital letter.");
+    }
+    LowerString(field->mutable_name());
+
+    field->set_type_name(group->name());
+    if (LookingAt("{")) {
+      DO(ParseMessageBlock(group, group_location, containing_file));
+    } else {
+      AddError("Missing group body.");
+      return false;
+    }
+  } else {
+    DO(ConsumeEndOfDeclaration(";", &field_location));
+  }
+
+  // Create a map entry type if this is a map field.
+  if (map_field.is_map_field) {
+    GenerateMapEntry(map_field, field, messages);
+  }
+
+  return true;
+}
+
+bool Parser::ParseMapType(MapField* map_field, FieldDescriptorProto* field,
+                          LocationRecorder& type_name_location) {
+  if (field->has_oneof_index()) {
+    AddError("Map fields are not allowed in oneofs.");
+    return false;
+  }
+  if (field->has_label()) {
+    AddError(
+        "Field labels (required/optional/repeated) are not allowed on "
+        "map fields.");
+    return false;
+  }
+  if (field->has_extendee()) {
+    AddError("Map fields are not allowed to be extensions.");
+    return false;
+  }
+  field->set_label(FieldDescriptorProto::LABEL_REPEATED);
+  DO(Consume("<"));
+  DO(ParseType(&map_field->key_type, &map_field->key_type_name));
+  DO(Consume(","));
+  DO(ParseType(&map_field->value_type, &map_field->value_type_name));
+  DO(Consume(">"));
+  // Defer setting of the type name of the map field until the
+  // field name is parsed. Add the source location though.
+  type_name_location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
+  return true;
+}
+
+void Parser::GenerateMapEntry(const MapField& map_field,
+                              FieldDescriptorProto* field,
+                              RepeatedPtrField<DescriptorProto>* messages) {
+  DescriptorProto* entry = messages->Add();
+  std::string entry_name = MapEntryName(field->name());
+  field->set_type_name(entry_name);
+  entry->set_name(entry_name);
+  entry->mutable_options()->set_map_entry(true);
+  FieldDescriptorProto* key_field = entry->add_field();
+  key_field->set_name("key");
+  key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  key_field->set_number(1);
+  if (map_field.key_type_name.empty()) {
+    key_field->set_type(map_field.key_type);
+  } else {
+    key_field->set_type_name(map_field.key_type_name);
+  }
+  FieldDescriptorProto* value_field = entry->add_field();
+  value_field->set_name("value");
+  value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  value_field->set_number(2);
+  if (map_field.value_type_name.empty()) {
+    value_field->set_type(map_field.value_type);
+  } else {
+    value_field->set_type_name(map_field.value_type_name);
+  }
+  // Propagate the "enforce_utf8" option to key and value fields if they
+  // are strings. This helps simplify the implementation of code generators
+  // and also reflection-based parsing code.
+  //
+  // The following definition:
+  //   message Foo {
+  //     map<string, string> value = 1 [enforce_utf8 = false];
+  //   }
+  // will be interpreted as:
+  //   message Foo {
+  //     message ValueEntry {
+  //       option map_entry = true;
+  //       string key = 1 [enforce_utf8 = false];
+  //       string value = 2 [enforce_utf8 = false];
+  //     }
+  //     repeated ValueEntry value = 1 [enforce_utf8 = false];
+  //  }
+  //
+  // TODO(xiaofeng): Remove this when the "enforce_utf8" option is removed
+  // from protocol compiler.
+  for (int i = 0; i < field->options().uninterpreted_option_size(); ++i) {
+    const UninterpretedOption& option =
+        field->options().uninterpreted_option(i);
+    if (option.name_size() == 1 &&
+        option.name(0).name_part() == "enforce_utf8" &&
+        !option.name(0).is_extension()) {
+      if (key_field->type() == FieldDescriptorProto::TYPE_STRING) {
+        key_field->mutable_options()->add_uninterpreted_option()->CopyFrom(
+            option);
+      }
+      if (value_field->type() == FieldDescriptorProto::TYPE_STRING) {
+        value_field->mutable_options()->add_uninterpreted_option()->CopyFrom(
+            option);
+      }
+    }
+  }
+}
+
+bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
+                               const LocationRecorder& field_location,
+                               const FileDescriptorProto* containing_file) {
+  if (!LookingAt("[")) return true;
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kOptionsFieldNumber);
+
+  DO(Consume("["));
+
+  // Parse field options.
+  do {
+    if (LookingAt("default")) {
+      // We intentionally pass field_location rather than location here, since
+      // the default value is not actually an option.
+      DO(ParseDefaultAssignment(field, field_location, containing_file));
+    } else if (LookingAt("json_name")) {
+      // Like default value, this "json_name" is not an actual option.
+      DO(ParseJsonName(field, field_location, containing_file));
+    } else {
+      DO(ParseOption(field->mutable_options(), location, containing_file,
+                     OPTION_ASSIGNMENT));
+    }
+  } while (TryConsume(","));
+
+  DO(Consume("]"));
+  return true;
+}
+
+bool Parser::ParseDefaultAssignment(
+    FieldDescriptorProto* field, const LocationRecorder& field_location,
+    const FileDescriptorProto* containing_file) {
+  if (field->has_default_value()) {
+    AddError("Already set option \"default\".");
+    field->clear_default_value();
+  }
+
+  DO(Consume("default"));
+  DO(Consume("="));
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kDefaultValueFieldNumber);
+  location.RecordLegacyLocation(field,
+                                DescriptorPool::ErrorCollector::DEFAULT_VALUE);
+  std::string* default_value = field->mutable_default_value();
+
+  if (!field->has_type()) {
+    // The field has a type name, but we don't know if it is a message or an
+    // enum yet. (If it were a primitive type, |field| would have a type set
+    // already.) In this case, simply take the current string as the default
+    // value; we will catch the error later if it is not a valid enum value.
+    // (N.B. that we do not check whether the current token is an identifier:
+    // doing so throws strange errors when the user mistypes a primitive
+    // typename and we assume it's an enum. E.g.: "optional int foo = 1 [default
+    // = 42]". In such a case the fundamental error is really that "int" is not
+    // a type, not that "42" is not an identifier. See b/12533582.)
+    *default_value = input_->current().text;
+    input_->Next();
+    return true;
+  }
+
+  switch (field->type()) {
+    case FieldDescriptorProto::TYPE_INT32:
+    case FieldDescriptorProto::TYPE_INT64:
+    case FieldDescriptorProto::TYPE_SINT32:
+    case FieldDescriptorProto::TYPE_SINT64:
+    case FieldDescriptorProto::TYPE_SFIXED32:
+    case FieldDescriptorProto::TYPE_SFIXED64: {
+      uint64_t max_value = std::numeric_limits<int64_t>::max();
+      if (field->type() == FieldDescriptorProto::TYPE_INT32 ||
+          field->type() == FieldDescriptorProto::TYPE_SINT32 ||
+          field->type() == FieldDescriptorProto::TYPE_SFIXED32) {
+        max_value = std::numeric_limits<int32_t>::max();
+      }
+
+      // These types can be negative.
+      if (TryConsume("-")) {
+        default_value->append("-");
+        // Two's complement always has one more negative value than positive.
+        ++max_value;
+      }
+      // Parse the integer to verify that it is not out-of-range.
+      uint64_t value;
+      DO(ConsumeInteger64(max_value, &value,
+                          "Expected integer for field default value."));
+      // And stringify it again.
+      default_value->append(StrCat(value));
+      break;
+    }
+
+    case FieldDescriptorProto::TYPE_UINT32:
+    case FieldDescriptorProto::TYPE_UINT64:
+    case FieldDescriptorProto::TYPE_FIXED32:
+    case FieldDescriptorProto::TYPE_FIXED64: {
+      uint64_t max_value = std::numeric_limits<uint64_t>::max();
+      if (field->type() == FieldDescriptorProto::TYPE_UINT32 ||
+          field->type() == FieldDescriptorProto::TYPE_FIXED32) {
+        max_value = std::numeric_limits<uint32_t>::max();
+      }
+
+      // Numeric, not negative.
+      if (TryConsume("-")) {
+        AddError("Unsigned field can't have negative default value.");
+      }
+      // Parse the integer to verify that it is not out-of-range.
+      uint64_t value;
+      DO(ConsumeInteger64(max_value, &value,
+                          "Expected integer for field default value."));
+      // And stringify it again.
+      default_value->append(StrCat(value));
+      break;
+    }
+
+    case FieldDescriptorProto::TYPE_FLOAT:
+    case FieldDescriptorProto::TYPE_DOUBLE:
+      // These types can be negative.
+      if (TryConsume("-")) {
+        default_value->append("-");
+      }
+      // Parse the integer because we have to convert hex integers to decimal
+      // floats.
+      double value;
+      DO(ConsumeNumber(&value, "Expected number."));
+      // And stringify it again.
+      default_value->append(SimpleDtoa(value));
+      break;
+
+    case FieldDescriptorProto::TYPE_BOOL:
+      if (TryConsume("true")) {
+        default_value->assign("true");
+      } else if (TryConsume("false")) {
+        default_value->assign("false");
+      } else {
+        AddError("Expected \"true\" or \"false\".");
+        return false;
+      }
+      break;
+
+    case FieldDescriptorProto::TYPE_STRING:
+      // Note: When file option java_string_check_utf8 is true, if a
+      // non-string representation (eg byte[]) is later supported, it must
+      // be checked for UTF-8-ness.
+      DO(ConsumeString(default_value,
+                       "Expected string for field default "
+                       "value."));
+      break;
+
+    case FieldDescriptorProto::TYPE_BYTES:
+      DO(ConsumeString(default_value, "Expected string."));
+      *default_value = CEscape(*default_value);
+      break;
+
+    case FieldDescriptorProto::TYPE_ENUM:
+      DO(ConsumeIdentifier(default_value,
+                           "Expected enum identifier for field "
+                           "default value."));
+      break;
+
+    case FieldDescriptorProto::TYPE_MESSAGE:
+    case FieldDescriptorProto::TYPE_GROUP:
+      AddError("Messages can't have default values.");
+      return false;
+  }
+
+  return true;
+}
+
+bool Parser::ParseJsonName(FieldDescriptorProto* field,
+                           const LocationRecorder& field_location,
+                           const FileDescriptorProto* containing_file) {
+  if (field->has_json_name()) {
+    AddError("Already set option \"json_name\".");
+    field->clear_json_name();
+  }
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kJsonNameFieldNumber);
+  location.RecordLegacyLocation(field,
+                                DescriptorPool::ErrorCollector::OPTION_NAME);
+
+  DO(Consume("json_name"));
+  DO(Consume("="));
+
+  LocationRecorder value_location(location);
+  value_location.RecordLegacyLocation(
+      field, DescriptorPool::ErrorCollector::OPTION_VALUE);
+
+  DO(ConsumeString(field->mutable_json_name(),
+                   "Expected string for JSON name."));
+  return true;
+}
+
+bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
+                                 const LocationRecorder& part_location,
+                                 const FileDescriptorProto* containing_file) {
+  UninterpretedOption::NamePart* name = uninterpreted_option->add_name();
+  std::string identifier;  // We parse identifiers into this string.
+  if (LookingAt("(")) {    // This is an extension.
+    DO(Consume("("));
+
+    {
+      LocationRecorder location(
+          part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
+      // An extension name consists of dot-separated identifiers, and may begin
+      // with a dot.
+      if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+        DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+        name->mutable_name_part()->append(identifier);
+      }
+      while (LookingAt(".")) {
+        DO(Consume("."));
+        name->mutable_name_part()->append(".");
+        DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+        name->mutable_name_part()->append(identifier);
+      }
+    }
+
+    DO(Consume(")"));
+    name->set_is_extension(true);
+  } else {  // This is a regular field.
+    LocationRecorder location(
+        part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    name->mutable_name_part()->append(identifier);
+    name->set_is_extension(false);
+  }
+  return true;
+}
+
+bool Parser::ParseUninterpretedBlock(std::string* value) {
+  // Note that enclosing braces are not added to *value.
+  // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting
+  // an expression, not a block of statements.
+  DO(Consume("{"));
+  int brace_depth = 1;
+  while (!AtEnd()) {
+    if (LookingAt("{")) {
+      brace_depth++;
+    } else if (LookingAt("}")) {
+      brace_depth--;
+      if (brace_depth == 0) {
+        input_->Next();
+        return true;
+      }
+    }
+    // TODO(sanjay): Interpret line/column numbers to preserve formatting
+    if (!value->empty()) value->push_back(' ');
+    value->append(input_->current().text);
+    input_->Next();
+  }
+  AddError("Unexpected end of stream while parsing aggregate value.");
+  return false;
+}
+
+// We don't interpret the option here. Instead we store it in an
+// UninterpretedOption, to be interpreted later.
+bool Parser::ParseOption(Message* options,
+                         const LocationRecorder& options_location,
+                         const FileDescriptorProto* containing_file,
+                         OptionStyle style) {
+  // Create an entry in the uninterpreted_option field.
+  const FieldDescriptor* uninterpreted_option_field =
+      options->GetDescriptor()->FindFieldByName("uninterpreted_option");
+  GOOGLE_CHECK(uninterpreted_option_field != nullptr)
+      << "No field named \"uninterpreted_option\" in the Options proto.";
+
+  const Reflection* reflection = options->GetReflection();
+
+  LocationRecorder location(
+      options_location, uninterpreted_option_field->number(),
+      reflection->FieldSize(*options, uninterpreted_option_field));
+
+  if (style == OPTION_STATEMENT) {
+    DO(Consume("option"));
+  }
+
+  UninterpretedOption* uninterpreted_option =
+      down_cast<UninterpretedOption*>(options->GetReflection()->AddMessage(
+          options, uninterpreted_option_field));
+
+  // Parse dot-separated name.
+  {
+    LocationRecorder name_location(location,
+                                   UninterpretedOption::kNameFieldNumber);
+    name_location.RecordLegacyLocation(
+        uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME);
+
+    {
+      LocationRecorder part_location(name_location,
+                                     uninterpreted_option->name_size());
+      DO(ParseOptionNamePart(uninterpreted_option, part_location,
+                             containing_file));
+    }
+
+    while (LookingAt(".")) {
+      DO(Consume("."));
+      LocationRecorder part_location(name_location,
+                                     uninterpreted_option->name_size());
+      DO(ParseOptionNamePart(uninterpreted_option, part_location,
+                             containing_file));
+    }
+  }
+
+  DO(Consume("="));
+
+  {
+    LocationRecorder value_location(location);
+    value_location.RecordLegacyLocation(
+        uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
+
+    // All values are a single token, except for negative numbers, which consist
+    // of a single '-' symbol, followed by a positive number.
+    bool is_negative = TryConsume("-");
+
+    switch (input_->current().type) {
+      case io::Tokenizer::TYPE_START:
+        GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
+        return false;
+
+      case io::Tokenizer::TYPE_END:
+        AddError("Unexpected end of stream while parsing option value.");
+        return false;
+
+      case io::Tokenizer::TYPE_WHITESPACE:
+      case io::Tokenizer::TYPE_NEWLINE:
+        GOOGLE_CHECK(!input_->report_whitespace() && !input_->report_newlines())
+            << "Whitespace tokens were not requested.";
+        GOOGLE_LOG(FATAL) << "Tokenizer reported whitespace.";
+        return false;
+
+      case io::Tokenizer::TYPE_IDENTIFIER: {
+        value_location.AddPath(
+            UninterpretedOption::kIdentifierValueFieldNumber);
+        if (is_negative) {
+          AddError("Invalid '-' symbol before identifier.");
+          return false;
+        }
+        std::string value;
+        DO(ConsumeIdentifier(&value, "Expected identifier."));
+        uninterpreted_option->set_identifier_value(value);
+        break;
+      }
+
+      case io::Tokenizer::TYPE_INTEGER: {
+        uint64_t value;
+        uint64_t max_value =
+            is_negative
+                ? static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1
+                : std::numeric_limits<uint64_t>::max();
+        DO(ConsumeInteger64(max_value, &value, "Expected integer."));
+        if (is_negative) {
+          value_location.AddPath(
+              UninterpretedOption::kNegativeIntValueFieldNumber);
+          uninterpreted_option->set_negative_int_value(
+              static_cast<int64_t>(0 - value));
+        } else {
+          value_location.AddPath(
+              UninterpretedOption::kPositiveIntValueFieldNumber);
+          uninterpreted_option->set_positive_int_value(value);
+        }
+        break;
+      }
+
+      case io::Tokenizer::TYPE_FLOAT: {
+        value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
+        double value;
+        DO(ConsumeNumber(&value, "Expected number."));
+        uninterpreted_option->set_double_value(is_negative ? -value : value);
+        break;
+      }
+
+      case io::Tokenizer::TYPE_STRING: {
+        value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
+        if (is_negative) {
+          AddError("Invalid '-' symbol before string.");
+          return false;
+        }
+        std::string value;
+        DO(ConsumeString(&value, "Expected string."));
+        uninterpreted_option->set_string_value(value);
+        break;
+      }
+
+      case io::Tokenizer::TYPE_SYMBOL:
+        if (LookingAt("{")) {
+          value_location.AddPath(
+              UninterpretedOption::kAggregateValueFieldNumber);
+          DO(ParseUninterpretedBlock(
+              uninterpreted_option->mutable_aggregate_value()));
+        } else {
+          AddError("Expected option value.");
+          return false;
+        }
+        break;
+    }
+  }
+
+  if (style == OPTION_STATEMENT) {
+    DO(ConsumeEndOfDeclaration(";", &location));
+  }
+
+  return true;
+}
+
+bool Parser::ParseExtensions(DescriptorProto* message,
+                             const LocationRecorder& extensions_location,
+                             const FileDescriptorProto* containing_file) {
+  // Parse the declaration.
+  DO(Consume("extensions"));
+
+  int old_range_size = message->extension_range_size();
+
+  do {
+    // Note that kExtensionRangeFieldNumber was already pushed by the parent.
+    LocationRecorder location(extensions_location,
+                              message->extension_range_size());
+
+    DescriptorProto::ExtensionRange* range = message->add_extension_range();
+    location.RecordLegacyLocation(range,
+                                  DescriptorPool::ErrorCollector::NUMBER);
+
+    int start, end;
+    io::Tokenizer::Token start_token;
+
+    {
+      LocationRecorder start_location(
+          location, DescriptorProto::ExtensionRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeInteger(&start, "Expected field number range."));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, DescriptorProto::ExtensionRange::kEndFieldNumber);
+      if (TryConsume("max")) {
+        // Set to the sentinel value - 1 since we increment the value below.
+        // The actual value of the end of the range should be set with
+        // AdjustExtensionRangesWithMaxEndNumber.
+        end = kMaxRangeSentinel - 1;
+      } else {
+        DO(ConsumeInteger(&end, "Expected integer."));
+      }
+    } else {
+      LocationRecorder end_location(
+          location, DescriptorProto::ExtensionRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
+      end = start;
+    }
+
+    // Users like to specify inclusive ranges, but in code we like the end
+    // number to be exclusive.
+    ++end;
+
+    range->set_start(start);
+    range->set_end(end);
+  } while (TryConsume(","));
+
+  if (LookingAt("[")) {
+    int range_number_index = extensions_location.CurrentPathSize();
+    SourceCodeInfo info;
+
+    // Parse extension range options in the first range.
+    ExtensionRangeOptions* options =
+        message->mutable_extension_range(old_range_size)->mutable_options();
+
+    {
+      LocationRecorder index_location(
+          extensions_location, 0 /* we fill this in w/ actual index below */,
+          &info);
+      LocationRecorder location(
+          index_location, DescriptorProto::ExtensionRange::kOptionsFieldNumber);
+      DO(Consume("["));
+
+      do {
+        DO(ParseOption(options, location, containing_file, OPTION_ASSIGNMENT));
+      } while (TryConsume(","));
+
+      DO(Consume("]"));
+    }
+
+    // Then copy the extension range options to all of the other ranges we've
+    // parsed.
+    for (int i = old_range_size + 1; i < message->extension_range_size(); i++) {
+      message->mutable_extension_range(i)->mutable_options()->CopyFrom(
+          *options);
+    }
+    // and copy source locations to the other ranges, too
+    for (int i = old_range_size; i < message->extension_range_size(); i++) {
+      for (int j = 0; j < info.location_size(); j++) {
+        if (info.location(j).path_size() == range_number_index + 1) {
+          // this location's path is up to the extension range index, but
+          // doesn't include options; so it's redundant with location above
+          continue;
+        }
+        SourceCodeInfo_Location* dest = source_code_info_->add_location();
+        *dest = info.location(j);
+        dest->set_path(range_number_index, i);
+      }
+    }
+  }
+
+  DO(ConsumeEndOfDeclaration(";", &extensions_location));
+  return true;
+}
+
+// This is similar to extension range parsing, except that it accepts field
+// name literals.
+bool Parser::ParseReserved(DescriptorProto* message,
+                           const LocationRecorder& message_location) {
+  io::Tokenizer::Token start_token = input_->current();
+  // Parse the declaration.
+  DO(Consume("reserved"));
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedNameFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNames(message, location);
+  } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedRangeFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNumbers(message, location);
+  }
+}
+
+bool Parser::ParseReservedNames(DescriptorProto* message,
+                                const LocationRecorder& parent_location) {
+  do {
+    LocationRecorder location(parent_location, message->reserved_name_size());
+    DO(ConsumeString(message->add_reserved_name(), "Expected field name."));
+  } while (TryConsume(","));
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseReservedNumbers(DescriptorProto* message,
+                                  const LocationRecorder& parent_location) {
+  bool first = true;
+  do {
+    LocationRecorder location(parent_location, message->reserved_range_size());
+
+    DescriptorProto::ReservedRange* range = message->add_reserved_range();
+    int start, end;
+    io::Tokenizer::Token start_token;
+    {
+      LocationRecorder start_location(
+          location, DescriptorProto::ReservedRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeInteger(&start, (first ? "Expected field name or number range."
+                                       : "Expected field number range.")));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, DescriptorProto::ReservedRange::kEndFieldNumber);
+      if (TryConsume("max")) {
+        // Set to the sentinel value - 1 since we increment the value below.
+        // The actual value of the end of the range should be set with
+        // AdjustExtensionRangesWithMaxEndNumber.
+        end = kMaxRangeSentinel - 1;
+      } else {
+        DO(ConsumeInteger(&end, "Expected integer."));
+      }
+    } else {
+      LocationRecorder end_location(
+          location, DescriptorProto::ReservedRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
+      end = start;
+    }
+
+    // Users like to specify inclusive ranges, but in code we like the end
+    // number to be exclusive.
+    ++end;
+
+    range->set_start(start);
+    range->set_end(end);
+    first = false;
+  } while (TryConsume(","));
+
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseReserved(EnumDescriptorProto* message,
+                           const LocationRecorder& message_location) {
+  io::Tokenizer::Token start_token = input_->current();
+  // Parse the declaration.
+  DO(Consume("reserved"));
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    LocationRecorder location(message_location,
+                              EnumDescriptorProto::kReservedNameFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNames(message, location);
+  } else {
+    LocationRecorder location(message_location,
+                              EnumDescriptorProto::kReservedRangeFieldNumber);
+    location.StartAt(start_token);
+    return ParseReservedNumbers(message, location);
+  }
+}
+
+bool Parser::ParseReservedNames(EnumDescriptorProto* message,
+                                const LocationRecorder& parent_location) {
+  do {
+    LocationRecorder location(parent_location, message->reserved_name_size());
+    DO(ConsumeString(message->add_reserved_name(), "Expected enum value."));
+  } while (TryConsume(","));
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseReservedNumbers(EnumDescriptorProto* message,
+                                  const LocationRecorder& parent_location) {
+  bool first = true;
+  do {
+    LocationRecorder location(parent_location, message->reserved_range_size());
+
+    EnumDescriptorProto::EnumReservedRange* range =
+        message->add_reserved_range();
+    int start, end;
+    io::Tokenizer::Token start_token;
+    {
+      LocationRecorder start_location(
+          location, EnumDescriptorProto::EnumReservedRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeSignedInteger(&start,
+                              (first ? "Expected enum value or number range."
+                                     : "Expected enum number range.")));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber);
+      if (TryConsume("max")) {
+        // This is in the enum descriptor path, which doesn't have the message
+        // set duality to fix up, so it doesn't integrate with the sentinel.
+        end = INT_MAX;
+      } else {
+        DO(ConsumeSignedInteger(&end, "Expected integer."));
+      }
+    } else {
+      LocationRecorder end_location(
+          location, EnumDescriptorProto::EnumReservedRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
+      end = start;
+    }
+
+    range->set_start(start);
+    range->set_end(end);
+    first = false;
+  } while (TryConsume(","));
+
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
+                         RepeatedPtrField<DescriptorProto>* messages,
+                         const LocationRecorder& parent_location,
+                         int location_field_number_for_nested_type,
+                         const LocationRecorder& extend_location,
+                         const FileDescriptorProto* containing_file) {
+  DO(Consume("extend"));
+
+  // Parse the extendee type.
+  io::Tokenizer::Token extendee_start = input_->current();
+  std::string extendee;
+  DO(ParseUserDefinedType(&extendee));
+  io::Tokenizer::Token extendee_end = input_->previous();
+
+  // Parse the block.
+  DO(ConsumeEndOfDeclaration("{", &extend_location));
+
+  bool is_first = true;
+
+  do {
+    if (AtEnd()) {
+      AddError("Reached end of input in extend definition (missing '}').");
+      return false;
+    }
+
+    // Note that kExtensionFieldNumber was already pushed by the parent.
+    LocationRecorder location(extend_location, extensions->size());
+
+    FieldDescriptorProto* field = extensions->Add();
+
+    {
+      LocationRecorder extendee_location(
+          location, FieldDescriptorProto::kExtendeeFieldNumber);
+      extendee_location.StartAt(extendee_start);
+      extendee_location.EndAt(extendee_end);
+
+      if (is_first) {
+        extendee_location.RecordLegacyLocation(
+            field, DescriptorPool::ErrorCollector::EXTENDEE);
+        is_first = false;
+      }
+    }
+
+    field->set_extendee(extendee);
+
+    if (!ParseMessageField(field, messages, parent_location,
+                           location_field_number_for_nested_type, location,
+                           containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  } while (!TryConsumeEndOfDeclaration("}", nullptr));
+
+  return true;
+}
+
+bool Parser::ParseOneof(OneofDescriptorProto* oneof_decl,
+                        DescriptorProto* containing_type, int oneof_index,
+                        const LocationRecorder& oneof_location,
+                        const LocationRecorder& containing_type_location,
+                        const FileDescriptorProto* containing_file) {
+  DO(Consume("oneof"));
+
+  {
+    LocationRecorder name_location(oneof_location,
+                                   OneofDescriptorProto::kNameFieldNumber);
+    DO(ConsumeIdentifier(oneof_decl->mutable_name(), "Expected oneof name."));
+  }
+
+  DO(ConsumeEndOfDeclaration("{", &oneof_location));
+
+  do {
+    if (AtEnd()) {
+      AddError("Reached end of input in oneof definition (missing '}').");
+      return false;
+    }
+
+    if (LookingAt("option")) {
+      LocationRecorder option_location(
+          oneof_location, OneofDescriptorProto::kOptionsFieldNumber);
+      if (!ParseOption(oneof_decl->mutable_options(), option_location,
+                       containing_file, OPTION_STATEMENT)) {
+        return false;
+      }
+      continue;
+    }
+
+    // Print a nice error if the user accidentally tries to place a label
+    // on an individual member of a oneof.
+    if (LookingAt("required") || LookingAt("optional") ||
+        LookingAt("repeated")) {
+      AddError(
+          "Fields in oneofs must not have labels (required / optional "
+          "/ repeated).");
+      // We can continue parsing here because we understand what the user
+      // meant.  The error report will still make parsing fail overall.
+      input_->Next();
+    }
+
+    LocationRecorder field_location(containing_type_location,
+                                    DescriptorProto::kFieldFieldNumber,
+                                    containing_type->field_size());
+
+    FieldDescriptorProto* field = containing_type->add_field();
+    field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+    field->set_oneof_index(oneof_index);
+
+    if (!ParseMessageFieldNoLabel(field, containing_type->mutable_nested_type(),
+                                  containing_type_location,
+                                  DescriptorProto::kNestedTypeFieldNumber,
+                                  field_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  } while (!TryConsumeEndOfDeclaration("}", nullptr));
+
+  return true;
+}
+
+// -------------------------------------------------------------------
+// Enums
+
+bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
+                                 const LocationRecorder& enum_location,
+                                 const FileDescriptorProto* containing_file) {
+  DO(Consume("enum"));
+
+  {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(enum_type,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
+  }
+
+  DO(ParseEnumBlock(enum_type, enum_location, containing_file));
+
+  DO(ValidateEnum(enum_type));
+
+  return true;
+}
+
+bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
+                            const LocationRecorder& enum_location,
+                            const FileDescriptorProto* containing_file) {
+  DO(ConsumeEndOfDeclaration("{", &enum_location));
+
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in enum definition (missing '}').");
+      return false;
+    }
+
+    if (!ParseEnumStatement(enum_type, enum_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  }
+
+  return true;
+}
+
+bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
+                                const LocationRecorder& enum_location,
+                                const FileDescriptorProto* containing_file) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("option")) {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(enum_type->mutable_options(), location, containing_file,
+                       OPTION_STATEMENT);
+  } else if (LookingAt("reserved")) {
+    return ParseReserved(enum_type, enum_location);
+  } else {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kValueFieldNumber,
+                              enum_type->value_size());
+    return ParseEnumConstant(enum_type->add_value(), location, containing_file);
+  }
+}
+
+bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
+                               const LocationRecorder& enum_value_location,
+                               const FileDescriptorProto* containing_file) {
+  // Parse name.
+  {
+    LocationRecorder location(enum_value_location,
+                              EnumValueDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(enum_value,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(enum_value->mutable_name(),
+                         "Expected enum constant name."));
+  }
+
+  DO(Consume("=", "Missing numeric value for enum constant."));
+
+  // Parse value.
+  {
+    LocationRecorder location(enum_value_location,
+                              EnumValueDescriptorProto::kNumberFieldNumber);
+    location.RecordLegacyLocation(enum_value,
+                                  DescriptorPool::ErrorCollector::NUMBER);
+
+    int number;
+    DO(ConsumeSignedInteger(&number, "Expected integer."));
+    enum_value->set_number(number);
+  }
+
+  DO(ParseEnumConstantOptions(enum_value, enum_value_location,
+                              containing_file));
+
+  DO(ConsumeEndOfDeclaration(";", &enum_value_location));
+
+  return true;
+}
+
+bool Parser::ParseEnumConstantOptions(
+    EnumValueDescriptorProto* value,
+    const LocationRecorder& enum_value_location,
+    const FileDescriptorProto* containing_file) {
+  if (!LookingAt("[")) return true;
+
+  LocationRecorder location(enum_value_location,
+                            EnumValueDescriptorProto::kOptionsFieldNumber);
+
+  DO(Consume("["));
+
+  do {
+    DO(ParseOption(value->mutable_options(), location, containing_file,
+                   OPTION_ASSIGNMENT));
+  } while (TryConsume(","));
+
+  DO(Consume("]"));
+  return true;
+}
+
+// -------------------------------------------------------------------
+// Services
+
+bool Parser::ParseServiceDefinition(
+    ServiceDescriptorProto* service, const LocationRecorder& service_location,
+    const FileDescriptorProto* containing_file) {
+  DO(Consume("service"));
+
+  {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(service,
+                                  DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
+  }
+
+  DO(ParseServiceBlock(service, service_location, containing_file));
+  return true;
+}
+
+bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
+                               const LocationRecorder& service_location,
+                               const FileDescriptorProto* containing_file) {
+  DO(ConsumeEndOfDeclaration("{", &service_location));
+
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in service definition (missing '}').");
+      return false;
+    }
+
+    if (!ParseServiceStatement(service, service_location, containing_file)) {
+      // This statement failed to parse.  Skip it, but keep looping to parse
+      // other statements.
+      SkipStatement();
+    }
+  }
+
+  return true;
+}
+
+bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
+                                   const LocationRecorder& service_location,
+                                   const FileDescriptorProto* containing_file) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
+    // empty statement; ignore
+    return true;
+  } else if (LookingAt("option")) {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(service->mutable_options(), location, containing_file,
+                       OPTION_STATEMENT);
+  } else {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kMethodFieldNumber,
+                              service->method_size());
+    return ParseServiceMethod(service->add_method(), location, containing_file);
+  }
+}
+
+bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
+                                const LocationRecorder& method_location,
+                                const FileDescriptorProto* containing_file) {
+  DO(Consume("rpc"));
+
+  {
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(method, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
+  }
+
+  // Parse input type.
+  DO(Consume("("));
+  {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
+      location.RecordLegacyLocation(method,
+                                    DescriptorPool::ErrorCollector::OTHER);
+      method->set_client_streaming(true);
+      DO(Consume("stream"));
+    }
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kInputTypeFieldNumber);
+    location.RecordLegacyLocation(method,
+                                  DescriptorPool::ErrorCollector::INPUT_TYPE);
+    DO(ParseUserDefinedType(method->mutable_input_type()));
+  }
+  DO(Consume(")"));
+
+  // Parse output type.
+  DO(Consume("returns"));
+  DO(Consume("("));
+  {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
+      location.RecordLegacyLocation(method,
+                                    DescriptorPool::ErrorCollector::OTHER);
+      DO(Consume("stream"));
+      method->set_server_streaming(true);
+    }
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kOutputTypeFieldNumber);
+    location.RecordLegacyLocation(method,
+                                  DescriptorPool::ErrorCollector::OUTPUT_TYPE);
+    DO(ParseUserDefinedType(method->mutable_output_type()));
+  }
+  DO(Consume(")"));
+
+  if (LookingAt("{")) {
+    // Options!
+    DO(ParseMethodOptions(method_location, containing_file,
+                          MethodDescriptorProto::kOptionsFieldNumber,
+                          method->mutable_options()));
+  } else {
+    DO(ConsumeEndOfDeclaration(";", &method_location));
+  }
+
+  return true;
+}
+
+bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
+                                const FileDescriptorProto* containing_file,
+                                const int optionsFieldNumber,
+                                Message* mutable_options) {
+  // Options!
+  ConsumeEndOfDeclaration("{", &parent_location);
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
+    if (AtEnd()) {
+      AddError("Reached end of input in method options (missing '}').");
+      return false;
+    }
+
+    if (TryConsumeEndOfDeclaration(";", nullptr)) {
+      // empty statement; ignore
+    } else {
+      LocationRecorder location(parent_location, optionsFieldNumber);
+      if (!ParseOption(mutable_options, location, containing_file,
+                       OPTION_STATEMENT)) {
+        // This statement failed to parse.  Skip it, but keep looping to
+        // parse other statements.
+        SkipStatement();
+      }
+    }
+  }
+
+  return true;
+}
+
+// -------------------------------------------------------------------
+
+bool Parser::ParseLabel(FieldDescriptorProto::Label* label,
+                        const LocationRecorder& field_location) {
+  if (!LookingAt("optional") && !LookingAt("repeated") &&
+      !LookingAt("required")) {
+    return false;
+  }
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kLabelFieldNumber);
+  if (TryConsume("optional")) {
+    *label = FieldDescriptorProto::LABEL_OPTIONAL;
+  } else if (TryConsume("repeated")) {
+    *label = FieldDescriptorProto::LABEL_REPEATED;
+  } else {
+    Consume("required");
+    *label = FieldDescriptorProto::LABEL_REQUIRED;
+  }
+  return true;
+}
+
+bool Parser::ParseType(FieldDescriptorProto::Type* type,
+                       std::string* type_name) {
+  const auto& type_names_table = GetTypeNameTable();
+  auto iter = type_names_table.find(input_->current().text);
+  if (iter != type_names_table.end()) {
+    *type = iter->second;
+    input_->Next();
+  } else {
+    DO(ParseUserDefinedType(type_name));
+  }
+  return true;
+}
+
+bool Parser::ParseUserDefinedType(std::string* type_name) {
+  type_name->clear();
+
+  const auto& type_names_table = GetTypeNameTable();
+  auto iter = type_names_table.find(input_->current().text);
+  if (iter != type_names_table.end()) {
+    // Note:  The only place enum types are allowed is for field types, but
+    //   if we are parsing a field type then we would not get here because
+    //   primitives are allowed there as well.  So this error message doesn't
+    //   need to account for enums.
+    AddError("Expected message type.");
+
+    // Pretend to accept this type so that we can go on parsing.
+    *type_name = input_->current().text;
+    input_->Next();
+    return true;
+  }
+
+  // A leading "." means the name is fully-qualified.
+  if (TryConsume(".")) type_name->append(".");
+
+  // Consume the first part of the name.
+  std::string identifier;
+  DO(ConsumeIdentifier(&identifier, "Expected type name."));
+  type_name->append(identifier);
+
+  // Consume more parts.
+  while (TryConsume(".")) {
+    type_name->append(".");
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    type_name->append(identifier);
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+bool Parser::ParsePackage(FileDescriptorProto* file,
+                          const LocationRecorder& root_location,
+                          const FileDescriptorProto* containing_file) {
+  if (file->has_package()) {
+    AddError("Multiple package definitions.");
+    // Don't append the new package to the old one.  Just replace it.  Not
+    // that it really matters since this is an error anyway.
+    file->clear_package();
+  }
+
+  LocationRecorder location(root_location,
+                            FileDescriptorProto::kPackageFieldNumber);
+  location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
+
+  DO(Consume("package"));
+
+  while (true) {
+    std::string identifier;
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    file->mutable_package()->append(identifier);
+    if (!TryConsume(".")) break;
+    file->mutable_package()->append(".");
+  }
+
+  DO(ConsumeEndOfDeclaration(";", &location));
+
+  return true;
+}
+
+bool Parser::ParseImport(RepeatedPtrField<std::string>* dependency,
+                         RepeatedField<int32_t>* public_dependency,
+                         RepeatedField<int32_t>* weak_dependency,
+                         const LocationRecorder& root_location,
+                         const FileDescriptorProto* containing_file) {
+  LocationRecorder location(root_location,
+                            FileDescriptorProto::kDependencyFieldNumber,
+                            dependency->size());
+
+  DO(Consume("import"));
+
+  if (LookingAt("public")) {
+    LocationRecorder public_location(
+        root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
+        public_dependency->size());
+    DO(Consume("public"));
+    *public_dependency->Add() = dependency->size();
+  } else if (LookingAt("weak")) {
+    LocationRecorder weak_location(
+        root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
+        weak_dependency->size());
+    weak_location.RecordLegacyImportLocation(containing_file, "weak");
+    DO(Consume("weak"));
+    *weak_dependency->Add() = dependency->size();
+  }
+
+  std::string import_file;
+  DO(ConsumeString(&import_file,
+                   "Expected a string naming the file to import."));
+  *dependency->Add() = import_file;
+  location.RecordLegacyImportLocation(containing_file, import_file);
+
+  DO(ConsumeEndOfDeclaration(";", &location));
+
+  return true;
+}
+
+// ===================================================================
+
+SourceLocationTable::SourceLocationTable() {}
+SourceLocationTable::~SourceLocationTable() {}
+
+bool SourceLocationTable::Find(
+    const Message* descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location, int* line,
+    int* column) const {
+  const std::pair<int, int>* result =
+      FindOrNull(location_map_, std::make_pair(descriptor, location));
+  if (result == nullptr) {
+    *line = -1;
+    *column = 0;
+    return false;
+  } else {
+    *line = result->first;
+    *column = result->second;
+    return true;
+  }
+}
+
+bool SourceLocationTable::FindImport(const Message* descriptor,
+                                     const std::string& name, int* line,
+                                     int* column) const {
+  const std::pair<int, int>* result =
+      FindOrNull(import_location_map_, std::make_pair(descriptor, name));
+  if (result == nullptr) {
+    *line = -1;
+    *column = 0;
+    return false;
+  } else {
+    *line = result->first;
+    *column = result->second;
+    return true;
+  }
+}
+
+void SourceLocationTable::Add(
+    const Message* descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location, int line,
+    int column) {
+  location_map_[std::make_pair(descriptor, location)] =
+      std::make_pair(line, column);
+}
+
+void SourceLocationTable::AddImport(const Message* descriptor,
+                                    const std::string& name, int line,
+                                    int column) {
+  import_location_map_[std::make_pair(descriptor, name)] =
+      std::make_pair(line, column);
+}
+
+void SourceLocationTable::Clear() { location_map_.clear(); }
+
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor.cpp
new file mode 100644
index 0000000..5f3427d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor.cpp
@@ -0,0 +1,8340 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/descriptor.h>
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <limits>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+#undef PACKAGE  // autoheader #defines this.  :(
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+const int kPackageLimit = 100;
+
+// Note:  I distrust ctype.h due to locales.
+char ToUpper(char ch) {
+  return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
+}
+
+char ToLower(char ch) {
+  return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
+}
+
+std::string ToCamelCase(const std::string& input, bool lower_first) {
+  bool capitalize_next = !lower_first;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpper(character));
+      capitalize_next = false;
+    } else {
+      result.push_back(character);
+    }
+  }
+
+  // Lower-case the first letter.
+  if (lower_first && !result.empty()) {
+    result[0] = ToLower(result[0]);
+  }
+
+  return result;
+}
+
+std::string ToJsonName(const std::string& input) {
+  bool capitalize_next = false;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpper(character));
+      capitalize_next = false;
+    } else {
+      result.push_back(character);
+    }
+  }
+
+  return result;
+}
+
+// Backport of fold expressions for the comma operator to C++11.
+// Usage:  Fold({expr...});
+// Guaranteed to evaluate left-to-right
+struct ExpressionEater {
+  template <typename T>
+  ExpressionEater(T&&) {}  // NOLINT
+};
+void Fold(std::initializer_list<ExpressionEater>) {}
+
+template <int R>
+constexpr size_t RoundUpTo(size_t n) {
+  static_assert((R & (R - 1)) == 0, "Must be power of two");
+  return (n + (R - 1)) & ~(R - 1);
+}
+
+constexpr size_t Max(size_t a, size_t b) { return a > b ? a : b; }
+template <typename T, typename... Ts>
+constexpr size_t Max(T a, Ts... b) {
+  return Max(a, Max(b...));
+}
+
+template <typename T>
+constexpr size_t EffectiveAlignof() {
+  // `char` is special in that it gets aligned to 8. It is where we drop the
+  // trivial structs.
+  return std::is_same<T, char>::value ? 8 : alignof(T);
+}
+
+template <int align, typename U, typename... T>
+using AppendIfAlign =
+    typename std::conditional<EffectiveAlignof<U>() == align, void (*)(T..., U),
+                              void (*)(T...)>::type;
+
+// Metafunction to sort types in descending order of alignment.
+// Useful for the flat allocator to ensure proper alignment of all elements
+// without having to add padding.
+// Instead of implementing a proper sort metafunction we just do a
+// filter+merge, which is much simpler to write as a metafunction.
+// We have a fixed set of alignments we can filter on.
+// For simplicity we use a function pointer as a type list.
+template <typename In, typename T16, typename T8, typename T4, typename T2,
+          typename T1>
+struct TypeListSortImpl;
+
+template <typename... T16, typename... T8, typename... T4, typename... T2,
+          typename... T1>
+struct TypeListSortImpl<void (*)(), void (*)(T16...), void (*)(T8...),
+                        void (*)(T4...), void (*)(T2...), void (*)(T1...)> {
+  using type = void (*)(T16..., T8..., T4..., T2..., T1...);
+};
+
+template <typename First, typename... Rest, typename... T16, typename... T8,
+          typename... T4, typename... T2, typename... T1>
+struct TypeListSortImpl<void (*)(First, Rest...), void (*)(T16...),
+                        void (*)(T8...), void (*)(T4...), void (*)(T2...),
+                        void (*)(T1...)> {
+  using type = typename TypeListSortImpl<
+      void (*)(Rest...), AppendIfAlign<16, First, T16...>,
+      AppendIfAlign<8, First, T8...>, AppendIfAlign<4, First, T4...>,
+      AppendIfAlign<2, First, T2...>, AppendIfAlign<1, First, T1...>>::type;
+};
+
+template <typename... T>
+using SortByAlignment =
+    typename TypeListSortImpl<void (*)(T...), void (*)(), void (*)(),
+                              void (*)(), void (*)(), void (*)()>::type;
+
+template <template <typename...> class C, typename... T>
+auto ApplyTypeList(void (*)(T...)) -> C<T...>;
+
+template <typename T>
+constexpr int FindTypeIndex() {
+  return -1;
+}
+
+template <typename T, typename T1, typename... Ts>
+constexpr int FindTypeIndex() {
+  return std::is_same<T, T1>::value ? 0 : FindTypeIndex<T, Ts...>() + 1;
+}
+
+// A type to value map, where the possible keys as specified in `Keys...`.
+// The values for key `K` is `ValueT<K>`
+template <template <typename> class ValueT, typename... Keys>
+class TypeMap {
+ public:
+  template <typename K>
+  ValueT<K>& Get() {
+    return static_cast<Base<K>&>(payload_).value;
+  }
+
+  template <typename K>
+  const ValueT<K>& Get() const {
+    return static_cast<const Base<K>&>(payload_).value;
+  }
+
+ private:
+  template <typename K>
+  struct Base {
+    ValueT<K> value{};
+  };
+  struct Payload : Base<Keys>... {};
+  Payload payload_;
+};
+
+template <typename T>
+using IntT = int;
+template <typename T>
+using PointerT = T*;
+
+// Manages an allocation of sequential arrays of type `T...`.
+// It is more space efficient than storing N (ptr, size) pairs, by storing only
+// the pointer to the head and the boundaries between the arrays.
+template <typename... T>
+class FlatAllocation {
+ public:
+  static constexpr size_t kMaxAlign = Max(alignof(T)...);
+
+  FlatAllocation(const TypeMap<IntT, T...>& ends) : ends_(ends) {
+    // The arrays start just after FlatAllocation, so adjust the ends.
+    Fold({(ends_.template Get<T>() +=
+           RoundUpTo<kMaxAlign>(sizeof(FlatAllocation)))...});
+    Fold({Init<T>()...});
+  }
+
+  void Destroy() {
+    Fold({Destroy<T>()...});
+    internal::SizedDelete(this, total_bytes());
+  }
+
+  template <int I>
+  using type = typename std::tuple_element<I, std::tuple<T...>>::type;
+
+  // Gets a tuple of the head pointers for the arrays
+  TypeMap<PointerT, T...> Pointers() const {
+    TypeMap<PointerT, T...> out;
+    Fold({(out.template Get<T>() = Begin<T>())...});
+    return out;
+  }
+
+
+ private:
+  // Total number of bytes used by all arrays.
+  int total_bytes() const {
+    // Get the last end.
+    return ends_.template Get<typename std::tuple_element<
+        sizeof...(T) - 1, std::tuple<T...>>::type>();
+  }
+
+
+  template <typename U>
+  int BeginOffset() const {
+    constexpr int type_index = FindTypeIndex<U, T...>();
+    // Avoid a negative value here to keep it compiling when type_index == 0
+    constexpr int prev_type_index = type_index == 0 ? 0 : type_index - 1;
+    using PrevType =
+        typename std::tuple_element<prev_type_index, std::tuple<T...>>::type;
+    // Ensure the types are properly aligned.
+    static_assert(EffectiveAlignof<PrevType>() >= EffectiveAlignof<U>(), "");
+    return type_index == 0 ? RoundUpTo<kMaxAlign>(sizeof(FlatAllocation))
+                           : ends_.template Get<PrevType>();
+  }
+
+  template <typename U>
+  int EndOffset() const {
+    return ends_.template Get<U>();
+  }
+
+  // Avoid the reinterpret_cast if the array is empty.
+  // Clang's Control Flow Integrity does not like the cast pointing to memory
+  // that is not yet initialized to be of that type.
+  // (from -fsanitize=cfi-unrelated-cast)
+  template <typename U>
+  U* Begin() const {
+    int begin = BeginOffset<U>(), end = EndOffset<U>();
+    if (begin == end) return nullptr;
+    return reinterpret_cast<U*>(data() + begin);
+  }
+
+  template <typename U>
+  U* End() const {
+    int begin = BeginOffset<U>(), end = EndOffset<U>();
+    if (begin == end) return nullptr;
+    return reinterpret_cast<U*>(data() + end);
+  }
+
+  template <typename U>
+  bool Init() {
+    // Skip for the `char` block. No need to zero initialize it.
+    if (std::is_same<U, char>::value) return true;
+    for (char *p = data() + BeginOffset<U>(), *end = data() + EndOffset<U>();
+         p != end; p += sizeof(U)) {
+      ::new (p) U{};
+    }
+    return true;
+  }
+
+  template <typename U>
+  bool Destroy() {
+    if (std::is_trivially_destructible<U>::value) return true;
+    for (U* it = Begin<U>(), *end = End<U>(); it != end; ++it) {
+      it->~U();
+    }
+    return true;
+  }
+
+  char* data() const {
+    return const_cast<char*>(reinterpret_cast<const char*>(this));
+  }
+
+  TypeMap<IntT, T...> ends_;
+};
+
+template <typename... T>
+TypeMap<IntT, T...> CalculateEnds(const TypeMap<IntT, T...>& sizes) {
+  int total = 0;
+  TypeMap<IntT, T...> out;
+  Fold({(out.template Get<T>() = total +=
+         sizeof(T) * sizes.template Get<T>())...});
+  return out;
+}
+
+// The implementation for FlatAllocator below.
+// This separate class template makes it easier to have methods that fold on
+// `T...`.
+template <typename... T>
+class FlatAllocatorImpl {
+ public:
+  using Allocation = FlatAllocation<T...>;
+
+  template <typename U>
+  void PlanArray(int array_size) {
+    // We can't call PlanArray after FinalizePlanning has been called.
+    GOOGLE_CHECK(!has_allocated());
+    if (std::is_trivially_destructible<U>::value) {
+      // Trivial types are aligned to 8 bytes.
+      static_assert(alignof(U) <= 8, "");
+      total_.template Get<char>() += RoundUpTo<8>(array_size * sizeof(U));
+    } else {
+      // Since we can't use `if constexpr`, just make the expression compile
+      // when this path is not taken.
+      using TypeToUse =
+          typename std::conditional<std::is_trivially_destructible<U>::value,
+                                    char, U>::type;
+      total_.template Get<TypeToUse>() += array_size;
+    }
+  }
+
+  template <typename U>
+  U* AllocateArray(int array_size) {
+    constexpr bool trivial = std::is_trivially_destructible<U>::value;
+    using TypeToUse = typename std::conditional<trivial, char, U>::type;
+
+    // We can only allocate after FinalizePlanning has been called.
+    GOOGLE_CHECK(has_allocated());
+
+    TypeToUse*& data = pointers_.template Get<TypeToUse>();
+    int& used = used_.template Get<TypeToUse>();
+    U* res = reinterpret_cast<U*>(data + used);
+    used += trivial ? RoundUpTo<8>(array_size * sizeof(U)) : array_size;
+    GOOGLE_CHECK_LE(used, total_.template Get<TypeToUse>());
+    return res;
+  }
+
+  template <typename... In>
+  const std::string* AllocateStrings(In&&... in) {
+    std::string* strings = AllocateArray<std::string>(sizeof...(in));
+    std::string* res = strings;
+    Fold({(*strings++ = std::string(std::forward<In>(in)))...});
+    return res;
+  }
+
+  // Allocate all 5 names of the field:
+  // name, full name, lowercase, camelcase and json.
+  // It will dedup the strings when possible.
+  // The resulting array contains `name` at index 0, `full_name` at index 1
+  // and the other 3 indices are specified in the result.
+  void PlanFieldNames(const std::string& name,
+                      const std::string* opt_json_name) {
+    GOOGLE_CHECK(!has_allocated());
+
+    // Fast path for snake_case names, which follow the style guide.
+    if (opt_json_name == nullptr) {
+      switch (GetFieldNameCase(name)) {
+        case FieldNameCase::kAllLower:
+          // Case 1: they are all the same.
+          return PlanArray<std::string>(2);
+        case FieldNameCase::kSnakeCase:
+          // Case 2: name==lower, camel==json
+          return PlanArray<std::string>(3);
+        default:
+          break;
+      }
+    }
+
+    std::string lowercase_name = name;
+    LowerString(&lowercase_name);
+
+    std::string camelcase_name = ToCamelCase(name, /* lower_first = */ true);
+    std::string json_name =
+        opt_json_name != nullptr ? *opt_json_name : ToJsonName(name);
+
+    StringPiece all_names[] = {name, lowercase_name, camelcase_name,
+                                     json_name};
+    std::sort(all_names, all_names + 4);
+    int unique =
+        static_cast<int>(std::unique(all_names, all_names + 4) - all_names);
+
+    PlanArray<std::string>(unique + 1);
+  }
+
+  struct FieldNamesResult {
+    const std::string* array;
+    int lowercase_index;
+    int camelcase_index;
+    int json_index;
+  };
+  FieldNamesResult AllocateFieldNames(const std::string& name,
+                                      const std::string& scope,
+                                      const std::string* opt_json_name) {
+    GOOGLE_CHECK(has_allocated());
+
+    std::string full_name =
+        scope.empty() ? name : StrCat(scope, ".", name);
+
+    // Fast path for snake_case names, which follow the style guide.
+    if (opt_json_name == nullptr) {
+      switch (GetFieldNameCase(name)) {
+        case FieldNameCase::kAllLower:
+          // Case 1: they are all the same.
+          return {AllocateStrings(name, std::move(full_name)), 0, 0, 0};
+        case FieldNameCase::kSnakeCase:
+          // Case 2: name==lower, camel==json
+          return {AllocateStrings(name, std::move(full_name),
+                                  ToCamelCase(name, /* lower_first = */ true)),
+                  0, 2, 2};
+        default:
+          break;
+      }
+    }
+
+    std::vector<std::string> names;
+    names.push_back(name);
+    names.push_back(std::move(full_name));
+
+    const auto push_name = [&](std::string new_name) {
+      for (size_t i = 0; i < names.size(); ++i) {
+        // Do not compare the full_name. It is unlikely to match, except in
+        // custom json_name. We are not taking this into account in
+        // PlanFieldNames so better to not try it.
+        if (i == 1) continue;
+        if (names[i] == new_name) return i;
+      }
+      names.push_back(std::move(new_name));
+      return names.size() - 1;
+    };
+
+    FieldNamesResult result{nullptr, 0, 0, 0};
+
+    std::string lowercase_name = name;
+    LowerString(&lowercase_name);
+    result.lowercase_index = push_name(std::move(lowercase_name));
+    result.camelcase_index =
+        push_name(ToCamelCase(name, /* lower_first = */ true));
+    result.json_index =
+        push_name(opt_json_name != nullptr ? *opt_json_name : ToJsonName(name));
+
+    std::string* all_names = AllocateArray<std::string>(names.size());
+    result.array = all_names;
+    std::move(names.begin(), names.end(), all_names);
+
+    return result;
+  }
+
+  template <typename Alloc>
+  void FinalizePlanning(Alloc& alloc) {
+    GOOGLE_CHECK(!has_allocated());
+
+    pointers_ = alloc->CreateFlatAlloc(total_)->Pointers();
+
+    GOOGLE_CHECK(has_allocated());
+  }
+
+  void ExpectConsumed() const {
+    // We verify that we consumed all the memory requested if there was no
+    // error in processing.
+    Fold({ExpectConsumed<T>()...});
+  }
+
+ private:
+  bool has_allocated() const {
+    return pointers_.template Get<char>() != nullptr;
+  }
+
+  static bool IsLower(char c) { return 'a' <= c && c <= 'z'; }
+  static bool IsDigit(char c) { return '0' <= c && c <= '9'; }
+  static bool IsLowerOrDigit(char c) { return IsLower(c) || IsDigit(c); }
+
+  enum class FieldNameCase { kAllLower, kSnakeCase, kOther };
+  FieldNameCase GetFieldNameCase(const std::string& name) {
+    if (!IsLower(name[0])) return FieldNameCase::kOther;
+    FieldNameCase best = FieldNameCase::kAllLower;
+    for (char c : name) {
+      if (IsLowerOrDigit(c)) {
+        // nothing to do
+      } else if (c == '_') {
+        best = FieldNameCase::kSnakeCase;
+      } else {
+        return FieldNameCase::kOther;
+      }
+    }
+    return best;
+  }
+
+  template <typename U>
+  bool ExpectConsumed() const {
+    GOOGLE_CHECK_EQ(total_.template Get<U>(), used_.template Get<U>());
+    return true;
+  }
+
+  TypeMap<PointerT, T...> pointers_;
+  TypeMap<IntT, T...> total_;
+  TypeMap<IntT, T...> used_;
+};
+
+}  // namespace
+
+class Symbol {
+ public:
+  enum Type {
+    NULL_SYMBOL,
+    MESSAGE,
+    FIELD,
+    ONEOF,
+    ENUM,
+    ENUM_VALUE,
+    ENUM_VALUE_OTHER_PARENT,
+    SERVICE,
+    METHOD,
+    FULL_PACKAGE,
+    SUB_PACKAGE,
+    QUERY_KEY
+  };
+
+  Symbol() {
+    static constexpr internal::SymbolBase null_symbol{};
+    static_assert(null_symbol.symbol_type_ == NULL_SYMBOL, "");
+    // Initialize with a sentinel to make sure `ptr_` is never null.
+    ptr_ = &null_symbol;
+  }
+
+  // Every object we store derives from internal::SymbolBase, where we store the
+  // symbol type enum.
+  // Storing in the object can be done without using more space in most cases,
+  // while storing it in the Symbol type would require 8 bytes.
+#define DEFINE_MEMBERS(TYPE, TYPE_CONSTANT, FIELD)                             \
+  explicit Symbol(TYPE* value) : ptr_(value) {                                 \
+    value->symbol_type_ = TYPE_CONSTANT;                                       \
+  }                                                                            \
+  const TYPE* FIELD() const {                                                  \
+    return type() == TYPE_CONSTANT ? static_cast<const TYPE*>(ptr_) : nullptr; \
+  }
+
+  DEFINE_MEMBERS(Descriptor, MESSAGE, descriptor)
+  DEFINE_MEMBERS(FieldDescriptor, FIELD, field_descriptor)
+  DEFINE_MEMBERS(OneofDescriptor, ONEOF, oneof_descriptor)
+  DEFINE_MEMBERS(EnumDescriptor, ENUM, enum_descriptor)
+  DEFINE_MEMBERS(ServiceDescriptor, SERVICE, service_descriptor)
+  DEFINE_MEMBERS(MethodDescriptor, METHOD, method_descriptor)
+  DEFINE_MEMBERS(FileDescriptor, FULL_PACKAGE, file_descriptor)
+
+  // We use a special node for subpackage FileDescriptor.
+  // It is potentially added to the table with multiple different names, so we
+  // need a separate place to put the name.
+  struct Subpackage : internal::SymbolBase {
+    int name_size;
+    const FileDescriptor* file;
+  };
+  DEFINE_MEMBERS(Subpackage, SUB_PACKAGE, sub_package_file_descriptor)
+
+  // Enum values have two different parents.
+  // We use two different identitied for the same object to determine the two
+  // different insertions in the map.
+  static Symbol EnumValue(EnumValueDescriptor* value, int n) {
+    Symbol s;
+    internal::SymbolBase* ptr;
+    if (n == 0) {
+      ptr = static_cast<internal::SymbolBaseN<0>*>(value);
+      ptr->symbol_type_ = ENUM_VALUE;
+    } else {
+      ptr = static_cast<internal::SymbolBaseN<1>*>(value);
+      ptr->symbol_type_ = ENUM_VALUE_OTHER_PARENT;
+    }
+    s.ptr_ = ptr;
+    return s;
+  }
+
+  const EnumValueDescriptor* enum_value_descriptor() const {
+    return type() == ENUM_VALUE
+               ? static_cast<const EnumValueDescriptor*>(
+                     static_cast<const internal::SymbolBaseN<0>*>(ptr_))
+           : type() == ENUM_VALUE_OTHER_PARENT
+               ? static_cast<const EnumValueDescriptor*>(
+                     static_cast<const internal::SymbolBaseN<1>*>(ptr_))
+               : nullptr;
+  }
+
+  // Not a real symbol.
+  // Only used for heterogeneous lookups and never actually inserted in the
+  // tables.
+  // TODO(b/215557658): If we templetize QueryKey on the expected object type we
+  // can skip the switches for the eq function altogether.
+  struct QueryKey : internal::SymbolBase {
+    StringPiece name;
+    const void* parent;
+    int field_number;
+
+    // Adaptor functions to look like a Symbol to the comparators.
+    StringPiece full_name() const { return name; }
+    std::pair<const void*, int> parent_number_key() const {
+      return {parent, field_number};
+    }
+    std::pair<const void*, StringPiece> parent_name_key() const {
+      return {parent, name};
+    }
+  };
+  // This constructor is implicit to allow for non-transparent lookups when
+  // necessary.
+  // For transparent lookup cases we query directly with the object without the
+  // type erasure layer.
+  Symbol(QueryKey& value) : ptr_(&value) {  // NOLINT
+    value.symbol_type_ = QUERY_KEY;
+  }
+  const QueryKey* query_key() const {
+    return type() == QUERY_KEY ? static_cast<const QueryKey*>(ptr_) : nullptr;
+  }
+#undef DEFINE_MEMBERS
+
+  Type type() const { return static_cast<Type>(ptr_->symbol_type_); }
+  bool IsNull() const { return type() == NULL_SYMBOL; }
+  bool IsType() const { return type() == MESSAGE || type() == ENUM; }
+  bool IsAggregate() const {
+    return IsType() || IsPackage() || type() == SERVICE;
+  }
+  bool IsPackage() const {
+    return type() == FULL_PACKAGE || type() == SUB_PACKAGE;
+  }
+
+  const FileDescriptor* GetFile() const {
+    switch (type()) {
+      case MESSAGE:
+        return descriptor()->file();
+      case FIELD:
+        return field_descriptor()->file();
+      case ONEOF:
+        return oneof_descriptor()->containing_type()->file();
+      case ENUM:
+        return enum_descriptor()->file();
+      case ENUM_VALUE:
+        return enum_value_descriptor()->type()->file();
+      case SERVICE:
+        return service_descriptor()->file();
+      case METHOD:
+        return method_descriptor()->service()->file();
+      case FULL_PACKAGE:
+        return file_descriptor();
+      case SUB_PACKAGE:
+        return sub_package_file_descriptor()->file;
+      default:
+        return nullptr;
+    }
+  }
+
+  StringPiece full_name() const {
+    switch (type()) {
+      case MESSAGE:
+        return descriptor()->full_name();
+      case FIELD:
+        return field_descriptor()->full_name();
+      case ONEOF:
+        return oneof_descriptor()->full_name();
+      case ENUM:
+        return enum_descriptor()->full_name();
+      case ENUM_VALUE:
+        return enum_value_descriptor()->full_name();
+      case SERVICE:
+        return service_descriptor()->full_name();
+      case METHOD:
+        return method_descriptor()->full_name();
+      case FULL_PACKAGE:
+        return file_descriptor()->package();
+      case SUB_PACKAGE:
+        return StringPiece(sub_package_file_descriptor()->file->package())
+            .substr(0, sub_package_file_descriptor()->name_size);
+      case QUERY_KEY:
+        return query_key()->full_name();
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return "";
+  }
+
+  std::pair<const void*, StringPiece> parent_name_key() const {
+    const auto or_file = [&](const void* p) { return p ? p : GetFile(); };
+    switch (type()) {
+      case MESSAGE:
+        return {or_file(descriptor()->containing_type()), descriptor()->name()};
+      case FIELD: {
+        auto* field = field_descriptor();
+        return {or_file(field->is_extension() ? field->extension_scope()
+                                              : field->containing_type()),
+                field->name()};
+      }
+      case ONEOF:
+        return {oneof_descriptor()->containing_type(),
+                oneof_descriptor()->name()};
+      case ENUM:
+        return {or_file(enum_descriptor()->containing_type()),
+                enum_descriptor()->name()};
+      case ENUM_VALUE:
+        return {or_file(enum_value_descriptor()->type()->containing_type()),
+                enum_value_descriptor()->name()};
+      case ENUM_VALUE_OTHER_PARENT:
+        return {enum_value_descriptor()->type(),
+                enum_value_descriptor()->name()};
+      case SERVICE:
+        return {GetFile(), service_descriptor()->name()};
+      case METHOD:
+        return {method_descriptor()->service(), method_descriptor()->name()};
+      case QUERY_KEY:
+        return query_key()->parent_name_key();
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return {};
+  }
+
+  std::pair<const void*, int> parent_number_key() const {
+    switch (type()) {
+      case FIELD:
+        return {field_descriptor()->containing_type(),
+                field_descriptor()->number()};
+      case ENUM_VALUE:
+        return {enum_value_descriptor()->type(),
+                enum_value_descriptor()->number()};
+      case QUERY_KEY:
+        return query_key()->parent_number_key();
+      default:
+        GOOGLE_CHECK(false);
+    }
+    return {};
+  }
+
+ private:
+  const internal::SymbolBase* ptr_;
+};
+
+const FieldDescriptor::CppType
+    FieldDescriptor::kTypeToCppTypeMap[MAX_TYPE + 1] = {
+        static_cast<CppType>(0),  // 0 is reserved for errors
+
+        CPPTYPE_DOUBLE,   // TYPE_DOUBLE
+        CPPTYPE_FLOAT,    // TYPE_FLOAT
+        CPPTYPE_INT64,    // TYPE_INT64
+        CPPTYPE_UINT64,   // TYPE_UINT64
+        CPPTYPE_INT32,    // TYPE_INT32
+        CPPTYPE_UINT64,   // TYPE_FIXED64
+        CPPTYPE_UINT32,   // TYPE_FIXED32
+        CPPTYPE_BOOL,     // TYPE_BOOL
+        CPPTYPE_STRING,   // TYPE_STRING
+        CPPTYPE_MESSAGE,  // TYPE_GROUP
+        CPPTYPE_MESSAGE,  // TYPE_MESSAGE
+        CPPTYPE_STRING,   // TYPE_BYTES
+        CPPTYPE_UINT32,   // TYPE_UINT32
+        CPPTYPE_ENUM,     // TYPE_ENUM
+        CPPTYPE_INT32,    // TYPE_SFIXED32
+        CPPTYPE_INT64,    // TYPE_SFIXED64
+        CPPTYPE_INT32,    // TYPE_SINT32
+        CPPTYPE_INT64,    // TYPE_SINT64
+};
+
+const char* const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = {
+    "ERROR",  // 0 is reserved for errors
+
+    "double",    // TYPE_DOUBLE
+    "float",     // TYPE_FLOAT
+    "int64",     // TYPE_INT64
+    "uint64",    // TYPE_UINT64
+    "int32",     // TYPE_INT32
+    "fixed64",   // TYPE_FIXED64
+    "fixed32",   // TYPE_FIXED32
+    "bool",      // TYPE_BOOL
+    "string",    // TYPE_STRING
+    "group",     // TYPE_GROUP
+    "message",   // TYPE_MESSAGE
+    "bytes",     // TYPE_BYTES
+    "uint32",    // TYPE_UINT32
+    "enum",      // TYPE_ENUM
+    "sfixed32",  // TYPE_SFIXED32
+    "sfixed64",  // TYPE_SFIXED64
+    "sint32",    // TYPE_SINT32
+    "sint64",    // TYPE_SINT64
+};
+
+const char* const FieldDescriptor::kCppTypeToName[MAX_CPPTYPE + 1] = {
+    "ERROR",  // 0 is reserved for errors
+
+    "int32",    // CPPTYPE_INT32
+    "int64",    // CPPTYPE_INT64
+    "uint32",   // CPPTYPE_UINT32
+    "uint64",   // CPPTYPE_UINT64
+    "double",   // CPPTYPE_DOUBLE
+    "float",    // CPPTYPE_FLOAT
+    "bool",     // CPPTYPE_BOOL
+    "enum",     // CPPTYPE_ENUM
+    "string",   // CPPTYPE_STRING
+    "message",  // CPPTYPE_MESSAGE
+};
+
+const char* const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = {
+    "ERROR",  // 0 is reserved for errors
+
+    "optional",  // LABEL_OPTIONAL
+    "required",  // LABEL_REQUIRED
+    "repeated",  // LABEL_REPEATED
+};
+
+const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) {
+  switch (syntax) {
+    case SYNTAX_PROTO2:
+      return "proto2";
+    case SYNTAX_PROTO3:
+      return "proto3";
+    case SYNTAX_UNKNOWN:
+      return "unknown";
+  }
+  GOOGLE_LOG(FATAL) << "can't reach here.";
+  return nullptr;
+}
+
+static const char* const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
+
+#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
+const int FieldDescriptor::kMaxNumber;
+const int FieldDescriptor::kFirstReservedNumber;
+const int FieldDescriptor::kLastReservedNumber;
+#endif
+
+namespace {
+
+std::string EnumValueToPascalCase(const std::string& input) {
+  bool next_upper = true;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      next_upper = true;
+    } else {
+      if (next_upper) {
+        result.push_back(ToUpper(character));
+      } else {
+        result.push_back(ToLower(character));
+      }
+      next_upper = false;
+    }
+  }
+
+  return result;
+}
+
+// Class to remove an enum prefix from enum values.
+class PrefixRemover {
+ public:
+  PrefixRemover(StringPiece prefix) {
+    // Strip underscores and lower-case the prefix.
+    for (char character : prefix) {
+      if (character != '_') {
+        prefix_ += ascii_tolower(character);
+      }
+    }
+  }
+
+  // Tries to remove the enum prefix from this enum value.
+  // If this is not possible, returns the input verbatim.
+  std::string MaybeRemove(StringPiece str) {
+    // We can't just lowercase and strip str and look for a prefix.
+    // We need to properly recognize the difference between:
+    //
+    //   enum Foo {
+    //     FOO_BAR_BAZ = 0;
+    //     FOO_BARBAZ = 1;
+    //   }
+    //
+    // This is acceptable (though perhaps not advisable) because even when
+    // we PascalCase, these two will still be distinct (BarBaz vs. Barbaz).
+    size_t i, j;
+
+    // Skip past prefix_ in str if we can.
+    for (i = 0, j = 0; i < str.size() && j < prefix_.size(); i++) {
+      if (str[i] == '_') {
+        continue;
+      }
+
+      if (ascii_tolower(str[i]) != prefix_[j++]) {
+        return std::string(str);
+      }
+    }
+
+    // If we didn't make it through the prefix, we've failed to strip the
+    // prefix.
+    if (j < prefix_.size()) {
+      return std::string(str);
+    }
+
+    // Skip underscores between prefix and further characters.
+    while (i < str.size() && str[i] == '_') {
+      i++;
+    }
+
+    // Enum label can't be the empty string.
+    if (i == str.size()) {
+      return std::string(str);
+    }
+
+    // We successfully stripped the prefix.
+    str.remove_prefix(i);
+    return std::string(str);
+  }
+
+ private:
+  std::string prefix_;
+};
+
+// A DescriptorPool contains a bunch of hash-maps to implement the
+// various Find*By*() methods.  Since hashtable lookups are O(1), it's
+// most efficient to construct a fixed set of large hash-maps used by
+// all objects in the pool rather than construct one or more small
+// hash-maps for each object.
+//
+// The keys to these hash-maps are (parent, name) or (parent, number) pairs.
+
+typedef std::pair<const void*, StringPiece> PointerStringPair;
+
+typedef std::pair<const Descriptor*, int> DescriptorIntPair;
+
+#define HASH_MAP std::unordered_map
+#define HASH_SET std::unordered_set
+#define HASH_FXN hash
+
+template <typename PairType>
+struct PointerIntegerPairHash {
+  size_t operator()(const PairType& p) const {
+    static const size_t prime1 = 16777499;
+    static const size_t prime2 = 16777619;
+    return reinterpret_cast<size_t>(p.first) * prime1 ^
+           static_cast<size_t>(p.second) * prime2;
+  }
+
+#ifdef _MSC_VER
+  // Used only by MSVC and platforms where hash_map is not available.
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+#endif
+  inline bool operator()(const PairType& a, const PairType& b) const {
+    return a < b;
+  }
+};
+
+struct PointerStringPairHash {
+  size_t operator()(const PointerStringPair& p) const {
+    static const size_t prime = 16777619;
+    hash<StringPiece> string_hash;
+    return reinterpret_cast<size_t>(p.first) * prime ^
+           static_cast<size_t>(string_hash(p.second));
+  }
+
+#ifdef _MSC_VER
+  // Used only by MSVC and platforms where hash_map is not available.
+  static const size_t bucket_size = 4;
+  static const size_t min_buckets = 8;
+#endif
+  inline bool operator()(const PointerStringPair& a,
+                         const PointerStringPair& b) const {
+    return a < b;
+  }
+};
+
+
+struct SymbolByFullNameHash {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
+    return HASH_FXN<StringPiece>{}(s.full_name());
+  }
+};
+struct SymbolByFullNameEq {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a.full_name() == b.full_name();
+  }
+};
+using SymbolsByNameSet =
+    HASH_SET<Symbol, SymbolByFullNameHash, SymbolByFullNameEq>;
+
+struct SymbolByParentHash {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
+    return PointerStringPairHash{}(s.parent_name_key());
+  }
+};
+struct SymbolByParentEq {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a.parent_name_key() == b.parent_name_key();
+  }
+};
+using SymbolsByParentSet =
+    HASH_SET<Symbol, SymbolByParentHash, SymbolByParentEq>;
+
+typedef HASH_MAP<StringPiece, const FileDescriptor*,
+                 HASH_FXN<StringPiece>>
+    FilesByNameMap;
+
+typedef HASH_MAP<PointerStringPair, const FieldDescriptor*,
+                 PointerStringPairHash>
+    FieldsByNameMap;
+
+struct FieldsByNumberHash {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
+    return PointerIntegerPairHash<std::pair<const void*, int>>{}(
+        s.parent_number_key());
+  }
+};
+struct FieldsByNumberEq {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a.parent_number_key() == b.parent_number_key();
+  }
+};
+using FieldsByNumberSet =
+    HASH_SET<Symbol, FieldsByNumberHash, FieldsByNumberEq>;
+using EnumValuesByNumberSet = FieldsByNumberSet;
+
+// This is a map rather than a hash-map, since we use it to iterate
+// through all the extensions that extend a given Descriptor, and an
+// ordered data structure that implements lower_bound is convenient
+// for that.
+typedef std::map<DescriptorIntPair, const FieldDescriptor*>
+    ExtensionsGroupedByDescriptorMap;
+typedef HASH_MAP<std::string, const SourceCodeInfo_Location*>
+    LocationsByPathMap;
+
+std::set<std::string>* NewAllowedProto3Extendee() {
+  auto allowed_proto3_extendees = new std::set<std::string>;
+  const char* kOptionNames[] = {
+      "FileOptions",   "MessageOptions",   "FieldOptions",
+      "EnumOptions",   "EnumValueOptions", "ServiceOptions",
+      "MethodOptions", "OneofOptions",     "ExtensionRangeOptions"};
+  for (const char* option_name : kOptionNames) {
+    // descriptor.proto has a different package name in opensource. We allow
+    // both so the opensource protocol compiler can also compile internal
+    // proto3 files with custom options. See: b/27567912
+    allowed_proto3_extendees->insert(std::string("google.protobuf.") +
+                                     option_name);
+    // Split the word to trick the opensource processing scripts so they
+    // will keep the original package name.
+    allowed_proto3_extendees->insert(std::string("proto") + "2." + option_name);
+  }
+  return allowed_proto3_extendees;
+}
+
+// Checks whether the extendee type is allowed in proto3.
+// Only extensions to descriptor options are allowed. We use name comparison
+// instead of comparing the descriptor directly because the extensions may be
+// defined in a different pool.
+bool AllowedExtendeeInProto3(const std::string& name) {
+  static auto allowed_proto3_extendees =
+      internal::OnShutdownDelete(NewAllowedProto3Extendee());
+  return allowed_proto3_extendees->find(name) !=
+         allowed_proto3_extendees->end();
+}
+}  // anonymous namespace
+
+// Contains tables specific to a particular file.  These tables are not
+// modified once the file has been constructed, so they need not be
+// protected by a mutex.  This makes operations that depend only on the
+// contents of a single file -- e.g. Descriptor::FindFieldByName() --
+// lock-free.
+//
+// For historical reasons, the definitions of the methods of
+// FileDescriptorTables and DescriptorPool::Tables are interleaved below.
+// These used to be a single class.
+class FileDescriptorTables {
+ public:
+  FileDescriptorTables();
+  ~FileDescriptorTables();
+
+  // Empty table, used with placeholder files.
+  inline static const FileDescriptorTables& GetEmptyInstance();
+
+  // -----------------------------------------------------------------
+  // Finding items.
+
+  // Returns a null Symbol (symbol.IsNull() is true) if not found.
+  inline Symbol FindNestedSymbol(const void* parent,
+                                 StringPiece name) const;
+
+  // These return nullptr if not found.
+  inline const FieldDescriptor* FindFieldByNumber(const Descriptor* parent,
+                                                  int number) const;
+  inline const FieldDescriptor* FindFieldByLowercaseName(
+      const void* parent, StringPiece lowercase_name) const;
+  inline const FieldDescriptor* FindFieldByCamelcaseName(
+      const void* parent, StringPiece camelcase_name) const;
+  inline const EnumValueDescriptor* FindEnumValueByNumber(
+      const EnumDescriptor* parent, int number) const;
+  // This creates a new EnumValueDescriptor if not found, in a thread-safe way.
+  inline const EnumValueDescriptor* FindEnumValueByNumberCreatingIfUnknown(
+      const EnumDescriptor* parent, int number) const;
+
+  // -----------------------------------------------------------------
+  // Adding items.
+
+  // These add items to the corresponding tables.  They return false if
+  // the key already exists in the table.
+  bool AddAliasUnderParent(const void* parent, const std::string& name,
+                           Symbol symbol);
+  bool AddFieldByNumber(FieldDescriptor* field);
+  bool AddEnumValueByNumber(EnumValueDescriptor* value);
+
+  // Populates p->first->locations_by_path_ from p->second.
+  // Unusual signature dictated by internal::call_once.
+  static void BuildLocationsByPath(
+      std::pair<const FileDescriptorTables*, const SourceCodeInfo*>* p);
+
+  // Returns the location denoted by the specified path through info,
+  // or nullptr if not found.
+  // The value of info must be that of the corresponding FileDescriptor.
+  // (Conceptually a pure function, but stateful as an optimisation.)
+  const SourceCodeInfo_Location* GetSourceLocation(
+      const std::vector<int>& path, const SourceCodeInfo* info) const;
+
+  // Must be called after BuildFileImpl(), even if the build failed and
+  // we are going to roll back to the last checkpoint.
+  void FinalizeTables();
+
+ private:
+  const void* FindParentForFieldsByMap(const FieldDescriptor* field) const;
+  static void FieldsByLowercaseNamesLazyInitStatic(
+      const FileDescriptorTables* tables);
+  void FieldsByLowercaseNamesLazyInitInternal() const;
+  static void FieldsByCamelcaseNamesLazyInitStatic(
+      const FileDescriptorTables* tables);
+  void FieldsByCamelcaseNamesLazyInitInternal() const;
+
+  SymbolsByParentSet symbols_by_parent_;
+  mutable internal::once_flag fields_by_lowercase_name_once_;
+  mutable internal::once_flag fields_by_camelcase_name_once_;
+  // Make these fields atomic to avoid race conditions with
+  // GetEstimatedOwnedMemoryBytesSize. Once the pointer is set the map won't
+  // change anymore.
+  mutable std::atomic<const FieldsByNameMap*> fields_by_lowercase_name_{};
+  mutable std::atomic<const FieldsByNameMap*> fields_by_camelcase_name_{};
+  FieldsByNumberSet fields_by_number_;  // Not including extensions.
+  EnumValuesByNumberSet enum_values_by_number_;
+  mutable EnumValuesByNumberSet unknown_enum_values_by_number_
+      PROTOBUF_GUARDED_BY(unknown_enum_values_mu_);
+
+  // Populated on first request to save space, hence constness games.
+  mutable internal::once_flag locations_by_path_once_;
+  mutable LocationsByPathMap locations_by_path_;
+
+  // Mutex to protect the unknown-enum-value map due to dynamic
+  // EnumValueDescriptor creation on unknown values.
+  mutable internal::WrappedMutex unknown_enum_values_mu_;
+};
+
+namespace internal {
+
+// Small sequential allocator to be used within a single file.
+// Most of the memory for a single FileDescriptor and everything under it is
+// allocated in a single block of memory, with the FlatAllocator giving it out
+// in parts later.
+// The code first plans the total number of bytes needed by calling PlanArray
+// with all the allocations that will happen afterwards, then calls
+// FinalizePlanning passing the underlying allocator (the DescriptorPool::Tables
+// instance), and then proceeds to get the memory via
+// `AllocateArray`/`AllocateString` calls. The calls to PlanArray and
+// The calls have to match between planning and allocating, though not
+// necessarily in the same order.
+class FlatAllocator
+    : public decltype(ApplyTypeList<FlatAllocatorImpl>(
+          SortByAlignment<char, std::string, SourceCodeInfo,
+                          FileDescriptorTables,
+                          // Option types
+                          MessageOptions, FieldOptions, EnumOptions,
+                          EnumValueOptions, ExtensionRangeOptions, OneofOptions,
+                          ServiceOptions, MethodOptions, FileOptions>())) {};
+
+}  // namespace internal
+
+// ===================================================================
+// DescriptorPool::Tables
+
+class DescriptorPool::Tables {
+ public:
+  Tables();
+  ~Tables();
+
+  // Record the current state of the tables to the stack of checkpoints.
+  // Each call to AddCheckpoint() must be paired with exactly one call to either
+  // ClearLastCheckpoint() or RollbackToLastCheckpoint().
+  //
+  // This is used when building files, since some kinds of validation errors
+  // cannot be detected until the file's descriptors have already been added to
+  // the tables.
+  //
+  // This supports recursive checkpoints, since building a file may trigger
+  // recursive building of other files. Note that recursive checkpoints are not
+  // normally necessary; explicit dependencies are built prior to checkpointing.
+  // So although we recursively build transitive imports, there is at most one
+  // checkpoint in the stack during dependency building.
+  //
+  // Recursive checkpoints only arise during cross-linking of the descriptors.
+  // Symbol references must be resolved, via DescriptorBuilder::FindSymbol and
+  // friends. If the pending file references an unknown symbol
+  // (e.g., it is not defined in the pending file's explicit dependencies), and
+  // the pool is using a fallback database, and that database contains a file
+  // defining that symbol, and that file has not yet been built by the pool,
+  // the pool builds the file during cross-linking, leading to another
+  // checkpoint.
+  void AddCheckpoint();
+
+  // Mark the last checkpoint as having cleared successfully, removing it from
+  // the stack. If the stack is empty, all pending symbols will be committed.
+  //
+  // Note that this does not guarantee that the symbols added since the last
+  // checkpoint won't be rolled back: if a checkpoint gets rolled back,
+  // everything past that point gets rolled back, including symbols added after
+  // checkpoints that were pushed onto the stack after it and marked as cleared.
+  void ClearLastCheckpoint();
+
+  // Roll back the Tables to the state of the checkpoint at the top of the
+  // stack, removing everything that was added after that point.
+  void RollbackToLastCheckpoint();
+
+  // The stack of files which are currently being built.  Used to detect
+  // cyclic dependencies when loading files from a DescriptorDatabase.  Not
+  // used when fallback_database_ == nullptr.
+  std::vector<std::string> pending_files_;
+
+  // A set of files which we have tried to load from the fallback database
+  // and encountered errors.  We will not attempt to load them again during
+  // execution of the current public API call, but for compatibility with
+  // legacy clients, this is cleared at the beginning of each public API call.
+  // Not used when fallback_database_ == nullptr.
+  HASH_SET<std::string> known_bad_files_;
+
+  // A set of symbols which we have tried to load from the fallback database
+  // and encountered errors. We will not attempt to load them again during
+  // execution of the current public API call, but for compatibility with
+  // legacy clients, this is cleared at the beginning of each public API call.
+  HASH_SET<std::string> known_bad_symbols_;
+
+  // The set of descriptors for which we've already loaded the full
+  // set of extensions numbers from fallback_database_.
+  HASH_SET<const Descriptor*> extensions_loaded_from_db_;
+
+  // Maps type name to Descriptor::WellKnownType.  This is logically global
+  // and const, but we make it a member here to simplify its construction and
+  // destruction.  This only has 20-ish entries and is one per DescriptorPool,
+  // so the overhead is small.
+  HASH_MAP<std::string, Descriptor::WellKnownType> well_known_types_;
+
+  // -----------------------------------------------------------------
+  // Finding items.
+
+  // Find symbols.  This returns a null Symbol (symbol.IsNull() is true)
+  // if not found.
+  inline Symbol FindSymbol(StringPiece key) const;
+
+  // This implements the body of DescriptorPool::Find*ByName().  It should
+  // really be a private method of DescriptorPool, but that would require
+  // declaring Symbol in descriptor.h, which would drag all kinds of other
+  // stuff into the header.  Yay C++.
+  Symbol FindByNameHelper(const DescriptorPool* pool, StringPiece name);
+
+  // These return nullptr if not found.
+  inline const FileDescriptor* FindFile(StringPiece key) const;
+  inline const FieldDescriptor* FindExtension(const Descriptor* extendee,
+                                              int number) const;
+  inline void FindAllExtensions(const Descriptor* extendee,
+                                std::vector<const FieldDescriptor*>* out) const;
+
+  // -----------------------------------------------------------------
+  // Adding items.
+
+  // These add items to the corresponding tables.  They return false if
+  // the key already exists in the table.  For AddSymbol(), the string passed
+  // in must be one that was constructed using AllocateString(), as it will
+  // be used as a key in the symbols_by_name_ map without copying.
+  bool AddSymbol(const std::string& full_name, Symbol symbol);
+  bool AddFile(const FileDescriptor* file);
+  bool AddExtension(const FieldDescriptor* field);
+
+  // -----------------------------------------------------------------
+  // Allocating memory.
+
+  // Allocate an object which will be reclaimed when the pool is
+  // destroyed.  Note that the object's destructor will never be called,
+  // so its fields must be plain old data (primitive data types and
+  // pointers).  All of the descriptor types are such objects.
+  template <typename Type>
+  Type* Allocate();
+
+  // Allocate some bytes which will be reclaimed when the pool is
+  // destroyed. Memory is aligned to 8 bytes.
+  void* AllocateBytes(int size);
+
+  // Create a FlatAllocation for the corresponding sizes.
+  // All objects within it will be default constructed.
+  // The whole allocation, including the non-trivial objects within, will be
+  // destroyed with the pool.
+  template <typename... T>
+  internal::FlatAllocator::Allocation* CreateFlatAlloc(
+      const TypeMap<IntT, T...>& sizes);
+
+
+ private:
+  // All memory allocated in the pool.  Must be first as other objects can
+  // point into these.
+  struct MiscDeleter {
+    void operator()(int* p) const { internal::SizedDelete(p, *p + 8); }
+  };
+  // Miscellaneous allocations are length prefixed. The paylaod is 8 bytes after
+  // the `int` that contains the size. This keeps the payload aligned.
+  std::vector<std::unique_ptr<int, MiscDeleter>> misc_allocs_;
+  struct FlatAllocDeleter {
+    void operator()(internal::FlatAllocator::Allocation* p) const {
+      p->Destroy();
+    }
+  };
+  std::vector<
+      std::unique_ptr<internal::FlatAllocator::Allocation, FlatAllocDeleter>>
+      flat_allocs_;
+
+  SymbolsByNameSet symbols_by_name_;
+  FilesByNameMap files_by_name_;
+  ExtensionsGroupedByDescriptorMap extensions_;
+
+  struct CheckPoint {
+    explicit CheckPoint(const Tables* tables)
+        : flat_allocations_before_checkpoint(
+              static_cast<int>(tables->flat_allocs_.size())),
+          misc_allocations_before_checkpoint(
+              static_cast<int>(tables->misc_allocs_.size())),
+          pending_symbols_before_checkpoint(
+              tables->symbols_after_checkpoint_.size()),
+          pending_files_before_checkpoint(
+              tables->files_after_checkpoint_.size()),
+          pending_extensions_before_checkpoint(
+              tables->extensions_after_checkpoint_.size()) {}
+    int flat_allocations_before_checkpoint;
+    int misc_allocations_before_checkpoint;
+    int pending_symbols_before_checkpoint;
+    int pending_files_before_checkpoint;
+    int pending_extensions_before_checkpoint;
+  };
+  std::vector<CheckPoint> checkpoints_;
+  std::vector<Symbol> symbols_after_checkpoint_;
+  std::vector<const FileDescriptor*> files_after_checkpoint_;
+  std::vector<DescriptorIntPair> extensions_after_checkpoint_;
+};
+
+DescriptorPool::Tables::Tables() {
+  well_known_types_.insert({
+      {"google.protobuf.DoubleValue", Descriptor::WELLKNOWNTYPE_DOUBLEVALUE},
+      {"google.protobuf.FloatValue", Descriptor::WELLKNOWNTYPE_FLOATVALUE},
+      {"google.protobuf.Int64Value", Descriptor::WELLKNOWNTYPE_INT64VALUE},
+      {"google.protobuf.UInt64Value", Descriptor::WELLKNOWNTYPE_UINT64VALUE},
+      {"google.protobuf.Int32Value", Descriptor::WELLKNOWNTYPE_INT32VALUE},
+      {"google.protobuf.UInt32Value", Descriptor::WELLKNOWNTYPE_UINT32VALUE},
+      {"google.protobuf.StringValue", Descriptor::WELLKNOWNTYPE_STRINGVALUE},
+      {"google.protobuf.BytesValue", Descriptor::WELLKNOWNTYPE_BYTESVALUE},
+      {"google.protobuf.BoolValue", Descriptor::WELLKNOWNTYPE_BOOLVALUE},
+      {"google.protobuf.Any", Descriptor::WELLKNOWNTYPE_ANY},
+      {"google.protobuf.FieldMask", Descriptor::WELLKNOWNTYPE_FIELDMASK},
+      {"google.protobuf.Duration", Descriptor::WELLKNOWNTYPE_DURATION},
+      {"google.protobuf.Timestamp", Descriptor::WELLKNOWNTYPE_TIMESTAMP},
+      {"google.protobuf.Value", Descriptor::WELLKNOWNTYPE_VALUE},
+      {"google.protobuf.ListValue", Descriptor::WELLKNOWNTYPE_LISTVALUE},
+      {"google.protobuf.Struct", Descriptor::WELLKNOWNTYPE_STRUCT},
+  });
+}
+
+DescriptorPool::Tables::~Tables() { GOOGLE_DCHECK(checkpoints_.empty()); }
+
+FileDescriptorTables::FileDescriptorTables() {}
+
+FileDescriptorTables::~FileDescriptorTables() {
+  delete fields_by_lowercase_name_.load(std::memory_order_acquire);
+  delete fields_by_camelcase_name_.load(std::memory_order_acquire);
+}
+
+inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() {
+  static auto file_descriptor_tables =
+      internal::OnShutdownDelete(new FileDescriptorTables());
+  return *file_descriptor_tables;
+}
+
+void DescriptorPool::Tables::AddCheckpoint() {
+  checkpoints_.push_back(CheckPoint(this));
+}
+
+void DescriptorPool::Tables::ClearLastCheckpoint() {
+  GOOGLE_DCHECK(!checkpoints_.empty());
+  checkpoints_.pop_back();
+  if (checkpoints_.empty()) {
+    // All checkpoints have been cleared: we can now commit all of the pending
+    // data.
+    symbols_after_checkpoint_.clear();
+    files_after_checkpoint_.clear();
+    extensions_after_checkpoint_.clear();
+  }
+}
+
+void DescriptorPool::Tables::RollbackToLastCheckpoint() {
+  GOOGLE_DCHECK(!checkpoints_.empty());
+  const CheckPoint& checkpoint = checkpoints_.back();
+
+  for (size_t i = checkpoint.pending_symbols_before_checkpoint;
+       i < symbols_after_checkpoint_.size(); i++) {
+    symbols_by_name_.erase(symbols_after_checkpoint_[i]);
+  }
+  for (size_t i = checkpoint.pending_files_before_checkpoint;
+       i < files_after_checkpoint_.size(); i++) {
+    files_by_name_.erase(files_after_checkpoint_[i]->name());
+  }
+  for (size_t i = checkpoint.pending_extensions_before_checkpoint;
+       i < extensions_after_checkpoint_.size(); i++) {
+    extensions_.erase(extensions_after_checkpoint_[i]);
+  }
+
+  symbols_after_checkpoint_.resize(
+      checkpoint.pending_symbols_before_checkpoint);
+  files_after_checkpoint_.resize(checkpoint.pending_files_before_checkpoint);
+  extensions_after_checkpoint_.resize(
+      checkpoint.pending_extensions_before_checkpoint);
+
+  flat_allocs_.resize(checkpoint.flat_allocations_before_checkpoint);
+  misc_allocs_.resize(checkpoint.misc_allocations_before_checkpoint);
+  checkpoints_.pop_back();
+}
+
+// -------------------------------------------------------------------
+
+inline Symbol DescriptorPool::Tables::FindSymbol(StringPiece key) const {
+  Symbol::QueryKey name;
+  name.name = key;
+  auto it = symbols_by_name_.find(name);
+  return it == symbols_by_name_.end() ? Symbol() : *it;
+}
+
+inline Symbol FileDescriptorTables::FindNestedSymbol(
+    const void* parent, StringPiece name) const {
+  Symbol::QueryKey query;
+  query.name = name;
+  query.parent = parent;
+  auto it = symbols_by_parent_.find(query);
+  return it == symbols_by_parent_.end() ? Symbol() : *it;
+}
+
+Symbol DescriptorPool::Tables::FindByNameHelper(const DescriptorPool* pool,
+                                                StringPiece name) {
+  if (pool->mutex_ != nullptr) {
+    // Fast path: the Symbol is already cached.  This is just a hash lookup.
+    ReaderMutexLock lock(pool->mutex_);
+    if (known_bad_symbols_.empty() && known_bad_files_.empty()) {
+      Symbol result = FindSymbol(name);
+      if (!result.IsNull()) return result;
+    }
+  }
+  MutexLockMaybe lock(pool->mutex_);
+  if (pool->fallback_database_ != nullptr) {
+    known_bad_symbols_.clear();
+    known_bad_files_.clear();
+  }
+  Symbol result = FindSymbol(name);
+
+  if (result.IsNull() && pool->underlay_ != nullptr) {
+    // Symbol not found; check the underlay.
+    result = pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name);
+  }
+
+  if (result.IsNull()) {
+    // Symbol still not found, so check fallback database.
+    if (pool->TryFindSymbolInFallbackDatabase(name)) {
+      result = FindSymbol(name);
+    }
+  }
+
+  return result;
+}
+
+inline const FileDescriptor* DescriptorPool::Tables::FindFile(
+    StringPiece key) const {
+  return FindPtrOrNull(files_by_name_, key);
+}
+
+inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
+    const Descriptor* parent, int number) const {
+  // If `number` is within the sequential range, just index into the parent
+  // without doing a table lookup.
+  if (parent != nullptr &&  //
+      1 <= number && number <= parent->sequential_field_limit_) {
+    return parent->field(number - 1);
+  }
+
+  Symbol::QueryKey query;
+  query.parent = parent;
+  query.field_number = number;
+
+  auto it = fields_by_number_.find(query);
+  return it == fields_by_number_.end() ? nullptr : it->field_descriptor();
+}
+
+const void* FileDescriptorTables::FindParentForFieldsByMap(
+    const FieldDescriptor* field) const {
+  if (field->is_extension()) {
+    if (field->extension_scope() == nullptr) {
+      return field->file();
+    } else {
+      return field->extension_scope();
+    }
+  } else {
+    return field->containing_type();
+  }
+}
+
+void FileDescriptorTables::FieldsByLowercaseNamesLazyInitStatic(
+    const FileDescriptorTables* tables) {
+  tables->FieldsByLowercaseNamesLazyInitInternal();
+}
+
+void FileDescriptorTables::FieldsByLowercaseNamesLazyInitInternal() const {
+  auto* map = new FieldsByNameMap;
+  for (Symbol symbol : symbols_by_parent_) {
+    const FieldDescriptor* field = symbol.field_descriptor();
+    if (!field) continue;
+    (*map)[{FindParentForFieldsByMap(field), field->lowercase_name().c_str()}] =
+        field;
+  }
+  fields_by_lowercase_name_.store(map, std::memory_order_release);
+}
+
+inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
+    const void* parent, StringPiece lowercase_name) const {
+  internal::call_once(
+      fields_by_lowercase_name_once_,
+      &FileDescriptorTables::FieldsByLowercaseNamesLazyInitStatic, this);
+  return FindPtrOrNull(
+      *fields_by_lowercase_name_.load(std::memory_order_acquire),
+      PointerStringPair(parent, lowercase_name));
+}
+
+void FileDescriptorTables::FieldsByCamelcaseNamesLazyInitStatic(
+    const FileDescriptorTables* tables) {
+  tables->FieldsByCamelcaseNamesLazyInitInternal();
+}
+
+void FileDescriptorTables::FieldsByCamelcaseNamesLazyInitInternal() const {
+  auto* map = new FieldsByNameMap;
+  for (Symbol symbol : symbols_by_parent_) {
+    const FieldDescriptor* field = symbol.field_descriptor();
+    if (!field) continue;
+    (*map)[{FindParentForFieldsByMap(field), field->camelcase_name().c_str()}] =
+        field;
+  }
+  fields_by_camelcase_name_.store(map, std::memory_order_release);
+}
+
+inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName(
+    const void* parent, StringPiece camelcase_name) const {
+  internal::call_once(
+      fields_by_camelcase_name_once_,
+      FileDescriptorTables::FieldsByCamelcaseNamesLazyInitStatic, this);
+  return FindPtrOrNull(
+      *fields_by_camelcase_name_.load(std::memory_order_acquire),
+      PointerStringPair(parent, camelcase_name));
+}
+
+inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
+    const EnumDescriptor* parent, int number) const {
+  // If `number` is within the sequential range, just index into the parent
+  // without doing a table lookup.
+  const int base = parent->value(0)->number();
+  if (base <= number &&
+      number <= static_cast<int64_t>(base) + parent->sequential_value_limit_) {
+    return parent->value(number - base);
+  }
+
+  Symbol::QueryKey query;
+  query.parent = parent;
+  query.field_number = number;
+
+  auto it = enum_values_by_number_.find(query);
+  return it == enum_values_by_number_.end() ? nullptr
+                                            : it->enum_value_descriptor();
+}
+
+inline const EnumValueDescriptor*
+FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
+    const EnumDescriptor* parent, int number) const {
+  // First try, with map of compiled-in values.
+  {
+    const auto* value = FindEnumValueByNumber(parent, number);
+    if (value != nullptr) {
+      return value;
+    }
+  }
+
+  Symbol::QueryKey query;
+  query.parent = parent;
+  query.field_number = number;
+
+  // Second try, with reader lock held on unknown enum values: common case.
+  {
+    ReaderMutexLock l(&unknown_enum_values_mu_);
+    auto it = unknown_enum_values_by_number_.find(query);
+    if (it != unknown_enum_values_by_number_.end() &&
+        it->enum_value_descriptor() != nullptr) {
+      return it->enum_value_descriptor();
+    }
+  }
+  // If not found, try again with writer lock held, and create new descriptor if
+  // necessary.
+  {
+    WriterMutexLock l(&unknown_enum_values_mu_);
+    auto it = unknown_enum_values_by_number_.find(query);
+    if (it != unknown_enum_values_by_number_.end() &&
+        it->enum_value_descriptor() != nullptr) {
+      return it->enum_value_descriptor();
+    }
+
+    // Create an EnumValueDescriptor dynamically. We don't insert it into the
+    // EnumDescriptor (it's not a part of the enum as originally defined), but
+    // we do insert it into the table so that we can return the same pointer
+    // later.
+    std::string enum_value_name = StringPrintf(
+        "UNKNOWN_ENUM_VALUE_%s_%d", parent->name().c_str(), number);
+    auto* pool = DescriptorPool::generated_pool();
+    auto* tables = const_cast<DescriptorPool::Tables*>(pool->tables_.get());
+    internal::FlatAllocator alloc;
+    alloc.PlanArray<EnumValueDescriptor>(1);
+    alloc.PlanArray<std::string>(2);
+
+    {
+      // Must lock the pool because we will do allocations in the shared arena.
+      MutexLockMaybe l2(pool->mutex_);
+      alloc.FinalizePlanning(tables);
+    }
+    EnumValueDescriptor* result = alloc.AllocateArray<EnumValueDescriptor>(1);
+    result->all_names_ = alloc.AllocateStrings(
+        enum_value_name,
+        StrCat(parent->full_name(), ".", enum_value_name));
+    result->number_ = number;
+    result->type_ = parent;
+    result->options_ = &EnumValueOptions::default_instance();
+    unknown_enum_values_by_number_.insert(Symbol::EnumValue(result, 0));
+    return result;
+  }
+}
+
+inline const FieldDescriptor* DescriptorPool::Tables::FindExtension(
+    const Descriptor* extendee, int number) const {
+  return FindPtrOrNull(extensions_, std::make_pair(extendee, number));
+}
+
+inline void DescriptorPool::Tables::FindAllExtensions(
+    const Descriptor* extendee,
+    std::vector<const FieldDescriptor*>* out) const {
+  ExtensionsGroupedByDescriptorMap::const_iterator it =
+      extensions_.lower_bound(std::make_pair(extendee, 0));
+  for (; it != extensions_.end() && it->first.first == extendee; ++it) {
+    out->push_back(it->second);
+  }
+}
+
+// -------------------------------------------------------------------
+
+bool DescriptorPool::Tables::AddSymbol(const std::string& full_name,
+                                       Symbol symbol) {
+  GOOGLE_DCHECK_EQ(full_name, symbol.full_name());
+  if (symbols_by_name_.insert(symbol).second) {
+    symbols_after_checkpoint_.push_back(symbol);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool FileDescriptorTables::AddAliasUnderParent(const void* parent,
+                                               const std::string& name,
+                                               Symbol symbol) {
+  GOOGLE_DCHECK_EQ(name, symbol.parent_name_key().second);
+  GOOGLE_DCHECK_EQ(parent, symbol.parent_name_key().first);
+  return symbols_by_parent_.insert(symbol).second;
+}
+
+bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
+  if (InsertIfNotPresent(&files_by_name_, file->name(), file)) {
+    files_after_checkpoint_.push_back(file);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void FileDescriptorTables::FinalizeTables() {}
+
+bool FileDescriptorTables::AddFieldByNumber(FieldDescriptor* field) {
+  // Skip fields that are at the start of the sequence.
+  if (field->containing_type() != nullptr && field->number() >= 1 &&
+      field->number() <= field->containing_type()->sequential_field_limit_) {
+    if (field->is_extension()) {
+      // Conflicts with the field that already exists in the sequential range.
+      return false;
+    }
+    // Only return true if the field at that index matches. Otherwise it
+    // conflicts with the existing field in the sequential range.
+    return field->containing_type()->field(field->number() - 1) == field;
+  }
+
+  return fields_by_number_.insert(Symbol(field)).second;
+}
+
+bool FileDescriptorTables::AddEnumValueByNumber(EnumValueDescriptor* value) {
+  // Skip values that are at the start of the sequence.
+  const int base = value->type()->value(0)->number();
+  if (base <= value->number() &&
+      value->number() <=
+          static_cast<int64_t>(base) + value->type()->sequential_value_limit_)
+    return true;
+  return enum_values_by_number_.insert(Symbol::EnumValue(value, 0)).second;
+}
+
+bool DescriptorPool::Tables::AddExtension(const FieldDescriptor* field) {
+  DescriptorIntPair key(field->containing_type(), field->number());
+  if (InsertIfNotPresent(&extensions_, key, field)) {
+    extensions_after_checkpoint_.push_back(key);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+// -------------------------------------------------------------------
+
+template <typename Type>
+Type* DescriptorPool::Tables::Allocate() {
+  static_assert(std::is_trivially_destructible<Type>::value, "");
+  static_assert(alignof(Type) <= 8, "");
+  return ::new (AllocateBytes(sizeof(Type))) Type{};
+}
+
+void* DescriptorPool::Tables::AllocateBytes(int size) {
+  if (size == 0) return nullptr;
+  void* p = ::operator new(size + RoundUpTo<8>(sizeof(int)));
+  int* sizep = static_cast<int*>(p);
+  misc_allocs_.emplace_back(sizep);
+  *sizep = size;
+  return static_cast<char*>(p) + RoundUpTo<8>(sizeof(int));
+}
+
+template <typename... T>
+internal::FlatAllocator::Allocation* DescriptorPool::Tables::CreateFlatAlloc(
+    const TypeMap<IntT, T...>& sizes) {
+  auto ends = CalculateEnds(sizes);
+  using FlatAlloc = internal::FlatAllocator::Allocation;
+
+  int last_end = ends.template Get<
+      typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type>();
+  size_t total_size =
+      last_end + RoundUpTo<FlatAlloc::kMaxAlign>(sizeof(FlatAlloc));
+  char* data = static_cast<char*>(::operator new(total_size));
+  auto* res = ::new (data) FlatAlloc(ends);
+  flat_allocs_.emplace_back(res);
+
+  return res;
+}
+
+void FileDescriptorTables::BuildLocationsByPath(
+    std::pair<const FileDescriptorTables*, const SourceCodeInfo*>* p) {
+  for (int i = 0, len = p->second->location_size(); i < len; ++i) {
+    const SourceCodeInfo_Location* loc = &p->second->location().Get(i);
+    p->first->locations_by_path_[Join(loc->path(), ",")] = loc;
+  }
+}
+
+const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
+    const std::vector<int>& path, const SourceCodeInfo* info) const {
+  std::pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
+      std::make_pair(this, info));
+  internal::call_once(locations_by_path_once_,
+                      FileDescriptorTables::BuildLocationsByPath, &p);
+  return FindPtrOrNull(locations_by_path_, Join(path, ","));
+}
+
+// ===================================================================
+// DescriptorPool
+
+DescriptorPool::ErrorCollector::~ErrorCollector() {}
+
+DescriptorPool::DescriptorPool()
+    : mutex_(nullptr),
+      fallback_database_(nullptr),
+      default_error_collector_(nullptr),
+      underlay_(nullptr),
+      tables_(new Tables),
+      enforce_dependencies_(true),
+      lazily_build_dependencies_(false),
+      allow_unknown_(false),
+      enforce_weak_(false),
+      disallow_enforce_utf8_(false) {}
+
+DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database,
+                               ErrorCollector* error_collector)
+    : mutex_(new internal::WrappedMutex),
+      fallback_database_(fallback_database),
+      default_error_collector_(error_collector),
+      underlay_(nullptr),
+      tables_(new Tables),
+      enforce_dependencies_(true),
+      lazily_build_dependencies_(false),
+      allow_unknown_(false),
+      enforce_weak_(false),
+      disallow_enforce_utf8_(false) {}
+
+DescriptorPool::DescriptorPool(const DescriptorPool* underlay)
+    : mutex_(nullptr),
+      fallback_database_(nullptr),
+      default_error_collector_(nullptr),
+      underlay_(underlay),
+      tables_(new Tables),
+      enforce_dependencies_(true),
+      lazily_build_dependencies_(false),
+      allow_unknown_(false),
+      enforce_weak_(false),
+      disallow_enforce_utf8_(false) {}
+
+DescriptorPool::~DescriptorPool() {
+  if (mutex_ != nullptr) delete mutex_;
+}
+
+// DescriptorPool::BuildFile() defined later.
+// DescriptorPool::BuildFileCollectingErrors() defined later.
+
+void DescriptorPool::InternalDontEnforceDependencies() {
+  enforce_dependencies_ = false;
+}
+
+void DescriptorPool::AddUnusedImportTrackFile(ConstStringParam file_name,
+                                              bool is_error) {
+  unused_import_track_files_[std::string(file_name)] = is_error;
+}
+
+void DescriptorPool::ClearUnusedImportTrackFiles() {
+  unused_import_track_files_.clear();
+}
+
+bool DescriptorPool::InternalIsFileLoaded(ConstStringParam filename) const {
+  MutexLockMaybe lock(mutex_);
+  return tables_->FindFile(filename) != nullptr;
+}
+
+// generated_pool ====================================================
+
+namespace {
+
+
+EncodedDescriptorDatabase* GeneratedDatabase() {
+  static auto generated_database =
+      internal::OnShutdownDelete(new EncodedDescriptorDatabase());
+  return generated_database;
+}
+
+DescriptorPool* NewGeneratedPool() {
+  auto generated_pool = new DescriptorPool(GeneratedDatabase());
+  generated_pool->InternalSetLazilyBuildDependencies();
+  return generated_pool;
+}
+
+}  // anonymous namespace
+
+DescriptorDatabase* DescriptorPool::internal_generated_database() {
+  return GeneratedDatabase();
+}
+
+DescriptorPool* DescriptorPool::internal_generated_pool() {
+  static DescriptorPool* generated_pool =
+      internal::OnShutdownDelete(NewGeneratedPool());
+  return generated_pool;
+}
+
+const DescriptorPool* DescriptorPool::generated_pool() {
+  const DescriptorPool* pool = internal_generated_pool();
+  // Ensure that descriptor.proto has been registered in the generated pool.
+  DescriptorProto::descriptor();
+  return pool;
+}
+
+
+void DescriptorPool::InternalAddGeneratedFile(
+    const void* encoded_file_descriptor, int size) {
+  // So, this function is called in the process of initializing the
+  // descriptors for generated proto classes.  Each generated .pb.cc file
+  // has an internal procedure called AddDescriptors() which is called at
+  // process startup, and that function calls this one in order to register
+  // the raw bytes of the FileDescriptorProto representing the file.
+  //
+  // We do not actually construct the descriptor objects right away.  We just
+  // hang on to the bytes until they are actually needed.  We actually construct
+  // the descriptor the first time one of the following things happens:
+  // * Someone calls a method like descriptor(), GetDescriptor(), or
+  //   GetReflection() on the generated types, which requires returning the
+  //   descriptor or an object based on it.
+  // * Someone looks up the descriptor in DescriptorPool::generated_pool().
+  //
+  // Once one of these happens, the DescriptorPool actually parses the
+  // FileDescriptorProto and generates a FileDescriptor (and all its children)
+  // based on it.
+  //
+  // Note that FileDescriptorProto is itself a generated protocol message.
+  // Therefore, when we parse one, we have to be very careful to avoid using
+  // any descriptor-based operations, since this might cause infinite recursion
+  // or deadlock.
+  GOOGLE_CHECK(GeneratedDatabase()->Add(encoded_file_descriptor, size));
+}
+
+
+// Find*By* methods ==================================================
+
+// TODO(kenton):  There's a lot of repeated code here, but I'm not sure if
+//   there's any good way to factor it out.  Think about this some time when
+//   there's nothing more important to do (read: never).
+
+const FileDescriptor* DescriptorPool::FindFileByName(
+    ConstStringParam name) const {
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+  const FileDescriptor* result = tables_->FindFile(name);
+  if (result != nullptr) return result;
+  if (underlay_ != nullptr) {
+    result = underlay_->FindFileByName(name);
+    if (result != nullptr) return result;
+  }
+  if (TryFindFileInFallbackDatabase(name)) {
+    result = tables_->FindFile(name);
+    if (result != nullptr) return result;
+  }
+  return nullptr;
+}
+
+const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
+    ConstStringParam symbol_name) const {
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+  Symbol result = tables_->FindSymbol(symbol_name);
+  if (!result.IsNull()) return result.GetFile();
+  if (underlay_ != nullptr) {
+    const FileDescriptor* file_result =
+        underlay_->FindFileContainingSymbol(symbol_name);
+    if (file_result != nullptr) return file_result;
+  }
+  if (TryFindSymbolInFallbackDatabase(symbol_name)) {
+    result = tables_->FindSymbol(symbol_name);
+    if (!result.IsNull()) return result.GetFile();
+  }
+  return nullptr;
+}
+
+const Descriptor* DescriptorPool::FindMessageTypeByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).descriptor();
+}
+
+const FieldDescriptor* DescriptorPool::FindFieldByName(
+    ConstStringParam name) const {
+  if (const FieldDescriptor* field =
+          tables_->FindByNameHelper(this, name).field_descriptor()) {
+    if (!field->is_extension()) {
+      return field;
+    }
+  }
+  return nullptr;
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByName(
+    ConstStringParam name) const {
+  if (const FieldDescriptor* field =
+          tables_->FindByNameHelper(this, name).field_descriptor()) {
+    if (field->is_extension()) {
+      return field;
+    }
+  }
+  return nullptr;
+}
+
+const OneofDescriptor* DescriptorPool::FindOneofByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).oneof_descriptor();
+}
+
+const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).enum_descriptor();
+}
+
+const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).enum_value_descriptor();
+}
+
+const ServiceDescriptor* DescriptorPool::FindServiceByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).service_descriptor();
+}
+
+const MethodDescriptor* DescriptorPool::FindMethodByName(
+    ConstStringParam name) const {
+  return tables_->FindByNameHelper(this, name).method_descriptor();
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
+    const Descriptor* extendee, int number) const {
+  if (extendee->extension_range_count() == 0) return nullptr;
+  // A faster path to reduce lock contention in finding extensions, assuming
+  // most extensions will be cache hit.
+  if (mutex_ != nullptr) {
+    ReaderMutexLock lock(mutex_);
+    const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+    if (result != nullptr) {
+      return result;
+    }
+  }
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+  const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+  if (result != nullptr) {
+    return result;
+  }
+  if (underlay_ != nullptr) {
+    result = underlay_->FindExtensionByNumber(extendee, number);
+    if (result != nullptr) return result;
+  }
+  if (TryFindExtensionInFallbackDatabase(extendee, number)) {
+    result = tables_->FindExtension(extendee, number);
+    if (result != nullptr) {
+      return result;
+    }
+  }
+  return nullptr;
+}
+
+const FieldDescriptor* DescriptorPool::InternalFindExtensionByNumberNoLock(
+    const Descriptor* extendee, int number) const {
+  if (extendee->extension_range_count() == 0) return nullptr;
+
+  const FieldDescriptor* result = tables_->FindExtension(extendee, number);
+  if (result != nullptr) {
+    return result;
+  }
+
+  if (underlay_ != nullptr) {
+    result = underlay_->InternalFindExtensionByNumberNoLock(extendee, number);
+    if (result != nullptr) return result;
+  }
+
+  return nullptr;
+}
+
+const FieldDescriptor* DescriptorPool::FindExtensionByPrintableName(
+    const Descriptor* extendee, ConstStringParam printable_name) const {
+  if (extendee->extension_range_count() == 0) return nullptr;
+  const FieldDescriptor* result = FindExtensionByName(printable_name);
+  if (result != nullptr && result->containing_type() == extendee) {
+    return result;
+  }
+  if (extendee->options().message_set_wire_format()) {
+    // MessageSet extensions may be identified by type name.
+    const Descriptor* type = FindMessageTypeByName(printable_name);
+    if (type != nullptr) {
+      // Look for a matching extension in the foreign type's scope.
+      const int type_extension_count = type->extension_count();
+      for (int i = 0; i < type_extension_count; i++) {
+        const FieldDescriptor* extension = type->extension(i);
+        if (extension->containing_type() == extendee &&
+            extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+            extension->is_optional() && extension->message_type() == type) {
+          // Found it.
+          return extension;
+        }
+      }
+    }
+  }
+  return nullptr;
+}
+
+void DescriptorPool::FindAllExtensions(
+    const Descriptor* extendee,
+    std::vector<const FieldDescriptor*>* out) const {
+  MutexLockMaybe lock(mutex_);
+  if (fallback_database_ != nullptr) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
+
+  // Initialize tables_->extensions_ from the fallback database first
+  // (but do this only once per descriptor).
+  if (fallback_database_ != nullptr &&
+      tables_->extensions_loaded_from_db_.count(extendee) == 0) {
+    std::vector<int> numbers;
+    if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(),
+                                                    &numbers)) {
+      for (int number : numbers) {
+        if (tables_->FindExtension(extendee, number) == nullptr) {
+          TryFindExtensionInFallbackDatabase(extendee, number);
+        }
+      }
+      tables_->extensions_loaded_from_db_.insert(extendee);
+    }
+  }
+
+  tables_->FindAllExtensions(extendee, out);
+  if (underlay_ != nullptr) {
+    underlay_->FindAllExtensions(extendee, out);
+  }
+}
+
+
+// -------------------------------------------------------------------
+
+const FieldDescriptor* Descriptor::FindFieldByNumber(int key) const {
+  const FieldDescriptor* result = file()->tables_->FindFieldByNumber(this, key);
+  if (result == nullptr || result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindFieldByLowercaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByLowercaseName(this, key);
+  if (result == nullptr || result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindFieldByCamelcaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByCamelcaseName(this, key);
+  if (result == nullptr || result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindFieldByName(ConstStringParam key) const {
+  const FieldDescriptor* field =
+      file()->tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && !field->is_extension() ? field : nullptr;
+}
+
+const OneofDescriptor* Descriptor::FindOneofByName(ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).oneof_descriptor();
+}
+
+const FieldDescriptor* Descriptor::FindExtensionByName(
+    ConstStringParam key) const {
+  const FieldDescriptor* field =
+      file()->tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && field->is_extension() ? field : nullptr;
+}
+
+const FieldDescriptor* Descriptor::FindExtensionByLowercaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByLowercaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* Descriptor::FindExtensionByCamelcaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result =
+      file()->tables_->FindFieldByCamelcaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const Descriptor* Descriptor::FindNestedTypeByName(ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).descriptor();
+}
+
+const EnumDescriptor* Descriptor::FindEnumTypeByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).enum_descriptor();
+}
+
+const EnumValueDescriptor* Descriptor::FindEnumValueByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).enum_value_descriptor();
+}
+
+const FieldDescriptor* Descriptor::map_key() const {
+  if (!options().map_entry()) return nullptr;
+  GOOGLE_DCHECK_EQ(field_count(), 2);
+  return field(0);
+}
+
+const FieldDescriptor* Descriptor::map_value() const {
+  if (!options().map_entry()) return nullptr;
+  GOOGLE_DCHECK_EQ(field_count(), 2);
+  return field(1);
+}
+
+const EnumValueDescriptor* EnumDescriptor::FindValueByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).enum_value_descriptor();
+}
+
+const EnumValueDescriptor* EnumDescriptor::FindValueByNumber(int key) const {
+  return file()->tables_->FindEnumValueByNumber(this, key);
+}
+
+const EnumValueDescriptor* EnumDescriptor::FindValueByNumberCreatingIfUnknown(
+    int key) const {
+  return file()->tables_->FindEnumValueByNumberCreatingIfUnknown(this, key);
+}
+
+const MethodDescriptor* ServiceDescriptor::FindMethodByName(
+    ConstStringParam key) const {
+  return file()->tables_->FindNestedSymbol(this, key).method_descriptor();
+}
+
+const Descriptor* FileDescriptor::FindMessageTypeByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).descriptor();
+}
+
+const EnumDescriptor* FileDescriptor::FindEnumTypeByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).enum_descriptor();
+}
+
+const EnumValueDescriptor* FileDescriptor::FindEnumValueByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).enum_value_descriptor();
+}
+
+const ServiceDescriptor* FileDescriptor::FindServiceByName(
+    ConstStringParam key) const {
+  return tables_->FindNestedSymbol(this, key).service_descriptor();
+}
+
+const FieldDescriptor* FileDescriptor::FindExtensionByName(
+    ConstStringParam key) const {
+  const FieldDescriptor* field =
+      tables_->FindNestedSymbol(this, key).field_descriptor();
+  return field != nullptr && field->is_extension() ? field : nullptr;
+}
+
+const FieldDescriptor* FileDescriptor::FindExtensionByLowercaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result = tables_->FindFieldByLowercaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+const FieldDescriptor* FileDescriptor::FindExtensionByCamelcaseName(
+    ConstStringParam key) const {
+  const FieldDescriptor* result = tables_->FindFieldByCamelcaseName(this, key);
+  if (result == nullptr || !result->is_extension()) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+void Descriptor::ExtensionRange::CopyTo(
+    DescriptorProto_ExtensionRange* proto) const {
+  proto->set_start(this->start);
+  proto->set_end(this->end);
+  if (options_ != &ExtensionRangeOptions::default_instance()) {
+    *proto->mutable_options() = *options_;
+  }
+}
+
+const Descriptor::ExtensionRange*
+Descriptor::FindExtensionRangeContainingNumber(int number) const {
+  // Linear search should be fine because we don't expect a message to have
+  // more than a couple extension ranges.
+  for (int i = 0; i < extension_range_count(); i++) {
+    if (number >= extension_range(i)->start &&
+        number < extension_range(i)->end) {
+      return extension_range(i);
+    }
+  }
+  return nullptr;
+}
+
+const Descriptor::ReservedRange* Descriptor::FindReservedRangeContainingNumber(
+    int number) const {
+  // TODO(chrisn): Consider a non-linear search.
+  for (int i = 0; i < reserved_range_count(); i++) {
+    if (number >= reserved_range(i)->start && number < reserved_range(i)->end) {
+      return reserved_range(i);
+    }
+  }
+  return nullptr;
+}
+
+const EnumDescriptor::ReservedRange*
+EnumDescriptor::FindReservedRangeContainingNumber(int number) const {
+  // TODO(chrisn): Consider a non-linear search.
+  for (int i = 0; i < reserved_range_count(); i++) {
+    if (number >= reserved_range(i)->start &&
+        number <= reserved_range(i)->end) {
+      return reserved_range(i);
+    }
+  }
+  return nullptr;
+}
+
+// -------------------------------------------------------------------
+
+bool DescriptorPool::TryFindFileInFallbackDatabase(
+    StringPiece name) const {
+  if (fallback_database_ == nullptr) return false;
+
+  auto name_string = std::string(name);
+  if (tables_->known_bad_files_.count(name_string) > 0) return false;
+
+  FileDescriptorProto file_proto;
+  if (!fallback_database_->FindFileByName(name_string, &file_proto) ||
+      BuildFileFromDatabase(file_proto) == nullptr) {
+    tables_->known_bad_files_.insert(std::move(name_string));
+    return false;
+  }
+  return true;
+}
+
+bool DescriptorPool::IsSubSymbolOfBuiltType(StringPiece name) const {
+  auto prefix = std::string(name);
+  for (;;) {
+    std::string::size_type dot_pos = prefix.find_last_of('.');
+    if (dot_pos == std::string::npos) {
+      break;
+    }
+    prefix = prefix.substr(0, dot_pos);
+    Symbol symbol = tables_->FindSymbol(prefix);
+    // If the symbol type is anything other than PACKAGE, then its complete
+    // definition is already known.
+    if (!symbol.IsNull() && !symbol.IsPackage()) {
+      return true;
+    }
+  }
+  if (underlay_ != nullptr) {
+    // Check to see if any prefix of this symbol exists in the underlay.
+    return underlay_->IsSubSymbolOfBuiltType(name);
+  }
+  return false;
+}
+
+bool DescriptorPool::TryFindSymbolInFallbackDatabase(
+    StringPiece name) const {
+  if (fallback_database_ == nullptr) return false;
+
+  auto name_string = std::string(name);
+  if (tables_->known_bad_symbols_.count(name_string) > 0) return false;
+
+  FileDescriptorProto file_proto;
+  if (  // We skip looking in the fallback database if the name is a sub-symbol
+        // of any descriptor that already exists in the descriptor pool (except
+        // for package descriptors).  This is valid because all symbols except
+        // for packages are defined in a single file, so if the symbol exists
+        // then we should already have its definition.
+        //
+        // The other reason to do this is to support "overriding" type
+        // definitions by merging two databases that define the same type. (Yes,
+        // people do this.)  The main difficulty with making this work is that
+        // FindFileContainingSymbol() is allowed to return both false positives
+        // (e.g., SimpleDescriptorDatabase, UpgradedDescriptorDatabase) and
+        // false negatives (e.g. ProtoFileParser, SourceTreeDescriptorDatabase).
+        // When two such databases are merged, looking up a non-existent
+        // sub-symbol of a type that already exists in the descriptor pool can
+        // result in an attempt to load multiple definitions of the same type.
+        // The check below avoids this.
+      IsSubSymbolOfBuiltType(name)
+
+      // Look up file containing this symbol in fallback database.
+      || !fallback_database_->FindFileContainingSymbol(name_string, &file_proto)
+
+      // Check if we've already built this file. If so, it apparently doesn't
+      // contain the symbol we're looking for.  Some DescriptorDatabases
+      // return false positives.
+      || tables_->FindFile(file_proto.name()) != nullptr
+
+      // Build the file.
+      || BuildFileFromDatabase(file_proto) == nullptr) {
+    tables_->known_bad_symbols_.insert(std::move(name_string));
+    return false;
+  }
+
+  return true;
+}
+
+bool DescriptorPool::TryFindExtensionInFallbackDatabase(
+    const Descriptor* containing_type, int field_number) const {
+  if (fallback_database_ == nullptr) return false;
+
+  FileDescriptorProto file_proto;
+  if (!fallback_database_->FindFileContainingExtension(
+          containing_type->full_name(), field_number, &file_proto)) {
+    return false;
+  }
+
+  if (tables_->FindFile(file_proto.name()) != nullptr) {
+    // We've already loaded this file, and it apparently doesn't contain the
+    // extension we're looking for.  Some DescriptorDatabases return false
+    // positives.
+    return false;
+  }
+
+  if (BuildFileFromDatabase(file_proto) == nullptr) {
+    return false;
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+bool FieldDescriptor::is_map_message_type() const {
+  return type_descriptor_.message_type->options().map_entry();
+}
+
+std::string FieldDescriptor::DefaultValueAsString(
+    bool quote_string_type) const {
+  GOOGLE_CHECK(has_default_value()) << "No default value";
+  switch (cpp_type()) {
+    case CPPTYPE_INT32:
+      return StrCat(default_value_int32_t());
+    case CPPTYPE_INT64:
+      return StrCat(default_value_int64_t());
+    case CPPTYPE_UINT32:
+      return StrCat(default_value_uint32_t());
+    case CPPTYPE_UINT64:
+      return StrCat(default_value_uint64_t());
+    case CPPTYPE_FLOAT:
+      return SimpleFtoa(default_value_float());
+    case CPPTYPE_DOUBLE:
+      return SimpleDtoa(default_value_double());
+    case CPPTYPE_BOOL:
+      return default_value_bool() ? "true" : "false";
+    case CPPTYPE_STRING:
+      if (quote_string_type) {
+        return "\"" + CEscape(default_value_string()) + "\"";
+      } else {
+        if (type() == TYPE_BYTES) {
+          return CEscape(default_value_string());
+        } else {
+          return default_value_string();
+        }
+      }
+    case CPPTYPE_ENUM:
+      return default_value_enum()->name();
+    case CPPTYPE_MESSAGE:
+      GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
+      break;
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here: failed to get default value as string";
+  return "";
+}
+
+// CopyTo methods ====================================================
+
+void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
+  proto->set_name(name());
+  if (!package().empty()) proto->set_package(package());
+  // TODO(liujisi): Also populate when syntax="proto2".
+  if (syntax() == SYNTAX_PROTO3) proto->set_syntax(SyntaxName(syntax()));
+
+  for (int i = 0; i < dependency_count(); i++) {
+    proto->add_dependency(dependency(i)->name());
+  }
+
+  for (int i = 0; i < public_dependency_count(); i++) {
+    proto->add_public_dependency(public_dependencies_[i]);
+  }
+
+  for (int i = 0; i < weak_dependency_count(); i++) {
+    proto->add_weak_dependency(weak_dependencies_[i]);
+  }
+
+  for (int i = 0; i < message_type_count(); i++) {
+    message_type(i)->CopyTo(proto->add_message_type());
+  }
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->CopyTo(proto->add_enum_type());
+  }
+  for (int i = 0; i < service_count(); i++) {
+    service(i)->CopyTo(proto->add_service());
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyTo(proto->add_extension());
+  }
+
+  if (&options() != &FileOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const {
+  if (message_type_count() != proto->message_type_size() ||
+      extension_count() != proto->extension_size()) {
+    GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
+    return;
+  }
+  for (int i = 0; i < message_type_count(); i++) {
+    message_type(i)->CopyJsonNameTo(proto->mutable_message_type(i));
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
+  }
+}
+
+void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
+  if (source_code_info_ &&
+      source_code_info_ != &SourceCodeInfo::default_instance()) {
+    proto->mutable_source_code_info()->CopyFrom(*source_code_info_);
+  }
+}
+
+void Descriptor::CopyTo(DescriptorProto* proto) const {
+  proto->set_name(name());
+
+  for (int i = 0; i < field_count(); i++) {
+    field(i)->CopyTo(proto->add_field());
+  }
+  for (int i = 0; i < oneof_decl_count(); i++) {
+    oneof_decl(i)->CopyTo(proto->add_oneof_decl());
+  }
+  for (int i = 0; i < nested_type_count(); i++) {
+    nested_type(i)->CopyTo(proto->add_nested_type());
+  }
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->CopyTo(proto->add_enum_type());
+  }
+  for (int i = 0; i < extension_range_count(); i++) {
+    extension_range(i)->CopyTo(proto->add_extension_range());
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyTo(proto->add_extension());
+  }
+  for (int i = 0; i < reserved_range_count(); i++) {
+    DescriptorProto::ReservedRange* range = proto->add_reserved_range();
+    range->set_start(reserved_range(i)->start);
+    range->set_end(reserved_range(i)->end);
+  }
+  for (int i = 0; i < reserved_name_count(); i++) {
+    proto->add_reserved_name(reserved_name(i));
+  }
+
+  if (&options() != &MessageOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void Descriptor::CopyJsonNameTo(DescriptorProto* proto) const {
+  if (field_count() != proto->field_size() ||
+      nested_type_count() != proto->nested_type_size() ||
+      extension_count() != proto->extension_size()) {
+    GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
+    return;
+  }
+  for (int i = 0; i < field_count(); i++) {
+    field(i)->CopyJsonNameTo(proto->mutable_field(i));
+  }
+  for (int i = 0; i < nested_type_count(); i++) {
+    nested_type(i)->CopyJsonNameTo(proto->mutable_nested_type(i));
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
+  }
+}
+
+void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
+  proto->set_name(name());
+  proto->set_number(number());
+  if (has_json_name_) {
+    proto->set_json_name(json_name());
+  }
+  if (proto3_optional_) {
+    proto->set_proto3_optional(true);
+  }
+  // Some compilers do not allow static_cast directly between two enum types,
+  // so we must cast to int first.
+  proto->set_label(static_cast<FieldDescriptorProto::Label>(
+      implicit_cast<int>(label())));
+  proto->set_type(static_cast<FieldDescriptorProto::Type>(
+      implicit_cast<int>(type())));
+
+  if (is_extension()) {
+    if (!containing_type()->is_unqualified_placeholder_) {
+      proto->set_extendee(".");
+    }
+    proto->mutable_extendee()->append(containing_type()->full_name());
+  }
+
+  if (cpp_type() == CPPTYPE_MESSAGE) {
+    if (message_type()->is_placeholder_) {
+      // We don't actually know if the type is a message type.  It could be
+      // an enum.
+      proto->clear_type();
+    }
+
+    if (!message_type()->is_unqualified_placeholder_) {
+      proto->set_type_name(".");
+    }
+    proto->mutable_type_name()->append(message_type()->full_name());
+  } else if (cpp_type() == CPPTYPE_ENUM) {
+    if (!enum_type()->is_unqualified_placeholder_) {
+      proto->set_type_name(".");
+    }
+    proto->mutable_type_name()->append(enum_type()->full_name());
+  }
+
+  if (has_default_value()) {
+    proto->set_default_value(DefaultValueAsString(false));
+  }
+
+  if (containing_oneof() != nullptr && !is_extension()) {
+    proto->set_oneof_index(containing_oneof()->index());
+  }
+
+  if (&options() != &FieldOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
+  proto->set_json_name(json_name());
+}
+
+void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
+  proto->set_name(name());
+  if (&options() != &OneofOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const {
+  proto->set_name(name());
+
+  for (int i = 0; i < value_count(); i++) {
+    value(i)->CopyTo(proto->add_value());
+  }
+  for (int i = 0; i < reserved_range_count(); i++) {
+    EnumDescriptorProto::EnumReservedRange* range = proto->add_reserved_range();
+    range->set_start(reserved_range(i)->start);
+    range->set_end(reserved_range(i)->end);
+  }
+  for (int i = 0; i < reserved_name_count(); i++) {
+    proto->add_reserved_name(reserved_name(i));
+  }
+
+  if (&options() != &EnumOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void EnumValueDescriptor::CopyTo(EnumValueDescriptorProto* proto) const {
+  proto->set_name(name());
+  proto->set_number(number());
+
+  if (&options() != &EnumValueOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void ServiceDescriptor::CopyTo(ServiceDescriptorProto* proto) const {
+  proto->set_name(name());
+
+  for (int i = 0; i < method_count(); i++) {
+    method(i)->CopyTo(proto->add_method());
+  }
+
+  if (&options() != &ServiceOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+}
+
+void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const {
+  proto->set_name(name());
+
+  if (!input_type()->is_unqualified_placeholder_) {
+    proto->set_input_type(".");
+  }
+  proto->mutable_input_type()->append(input_type()->full_name());
+
+  if (!output_type()->is_unqualified_placeholder_) {
+    proto->set_output_type(".");
+  }
+  proto->mutable_output_type()->append(output_type()->full_name());
+
+  if (&options() != &MethodOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
+
+  if (client_streaming_) {
+    proto->set_client_streaming(true);
+  }
+  if (server_streaming_) {
+    proto->set_server_streaming(true);
+  }
+}
+
+// DebugString methods ===============================================
+
+namespace {
+
+bool RetrieveOptionsAssumingRightPool(
+    int depth, const Message& options,
+    std::vector<std::string>* option_entries) {
+  option_entries->clear();
+  const Reflection* reflection = options.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(options, &fields);
+  for (const FieldDescriptor* field : fields) {
+    int count = 1;
+    bool repeated = false;
+    if (field->is_repeated()) {
+      count = reflection->FieldSize(options, field);
+      repeated = true;
+    }
+    for (int j = 0; j < count; j++) {
+      std::string fieldval;
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        std::string tmp;
+        TextFormat::Printer printer;
+        printer.SetExpandAny(true);
+        printer.SetInitialIndentLevel(depth + 1);
+        printer.PrintFieldValueToString(options, field, repeated ? j : -1,
+                                        &tmp);
+        fieldval.append("{\n");
+        fieldval.append(tmp);
+        fieldval.append(depth * 2, ' ');
+        fieldval.append("}");
+      } else {
+        TextFormat::PrintFieldValueToString(options, field, repeated ? j : -1,
+                                            &fieldval);
+      }
+      std::string name;
+      if (field->is_extension()) {
+        name = "(." + field->full_name() + ")";
+      } else {
+        name = field->name();
+      }
+      option_entries->push_back(name + " = " + fieldval);
+    }
+  }
+  return !option_entries->empty();
+}
+
+// Used by each of the option formatters.
+bool RetrieveOptions(int depth, const Message& options,
+                     const DescriptorPool* pool,
+                     std::vector<std::string>* option_entries) {
+  // When printing custom options for a descriptor, we must use an options
+  // message built on top of the same DescriptorPool where the descriptor
+  // is coming from. This is to ensure we are interpreting custom options
+  // against the right pool.
+  if (options.GetDescriptor()->file()->pool() == pool) {
+    return RetrieveOptionsAssumingRightPool(depth, options, option_entries);
+  } else {
+    const Descriptor* option_descriptor =
+        pool->FindMessageTypeByName(options.GetDescriptor()->full_name());
+    if (option_descriptor == nullptr) {
+      // descriptor.proto is not in the pool. This means no custom options are
+      // used so we are safe to proceed with the compiled options message type.
+      return RetrieveOptionsAssumingRightPool(depth, options, option_entries);
+    }
+    DynamicMessageFactory factory;
+    std::unique_ptr<Message> dynamic_options(
+        factory.GetPrototype(option_descriptor)->New());
+    std::string serialized = options.SerializeAsString();
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8_t*>(serialized.c_str()),
+        serialized.size());
+    input.SetExtensionRegistry(pool, &factory);
+    if (dynamic_options->ParseFromCodedStream(&input)) {
+      return RetrieveOptionsAssumingRightPool(depth, *dynamic_options,
+                                              option_entries);
+    } else {
+      GOOGLE_LOG(ERROR) << "Found invalid proto option data for: "
+                 << options.GetDescriptor()->full_name();
+      return RetrieveOptionsAssumingRightPool(depth, options, option_entries);
+    }
+  }
+}
+
+// Formats options that all appear together in brackets. Does not include
+// brackets.
+bool FormatBracketedOptions(int depth, const Message& options,
+                            const DescriptorPool* pool, std::string* output) {
+  std::vector<std::string> all_options;
+  if (RetrieveOptions(depth, options, pool, &all_options)) {
+    output->append(Join(all_options, ", "));
+  }
+  return !all_options.empty();
+}
+
+// Formats options one per line
+bool FormatLineOptions(int depth, const Message& options,
+                       const DescriptorPool* pool, std::string* output) {
+  std::string prefix(depth * 2, ' ');
+  std::vector<std::string> all_options;
+  if (RetrieveOptions(depth, options, pool, &all_options)) {
+    for (const std::string& option : all_options) {
+      strings::SubstituteAndAppend(output, "$0option $1;\n", prefix, option);
+    }
+  }
+  return !all_options.empty();
+}
+
+class SourceLocationCommentPrinter {
+ public:
+  template <typename DescType>
+  SourceLocationCommentPrinter(const DescType* desc, const std::string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ =
+        options.include_comments && desc->GetSourceLocation(&source_loc_);
+  }
+  SourceLocationCommentPrinter(const FileDescriptor* file,
+                               const std::vector<int>& path,
+                               const std::string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ =
+        options.include_comments && file->GetSourceLocation(path, &source_loc_);
+  }
+  void AddPreComment(std::string* output) {
+    if (have_source_loc_) {
+      // Detached leading comments.
+      for (const std::string& leading_detached_comment :
+           source_loc_.leading_detached_comments) {
+        *output += FormatComment(leading_detached_comment);
+        *output += "\n";
+      }
+      // Attached leading comments.
+      if (!source_loc_.leading_comments.empty()) {
+        *output += FormatComment(source_loc_.leading_comments);
+      }
+    }
+  }
+  void AddPostComment(std::string* output) {
+    if (have_source_loc_ && source_loc_.trailing_comments.size() > 0) {
+      *output += FormatComment(source_loc_.trailing_comments);
+    }
+  }
+
+  // Format comment such that each line becomes a full-line C++-style comment in
+  // the DebugString() output.
+  std::string FormatComment(const std::string& comment_text) {
+    std::string stripped_comment = comment_text;
+    StripWhitespace(&stripped_comment);
+    std::vector<std::string> lines = Split(stripped_comment, "\n");
+    std::string output;
+    for (const std::string& line : lines) {
+      strings::SubstituteAndAppend(&output, "$0// $1\n", prefix_, line);
+    }
+    return output;
+  }
+
+ private:
+
+  bool have_source_loc_;
+  SourceLocation source_loc_;
+  DebugStringOptions options_;
+  std::string prefix_;
+};
+
+}  // anonymous namespace
+
+std::string FileDescriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+std::string FileDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& debug_string_options) const {
+  std::string contents;
+  {
+    std::vector<int> path;
+    path.push_back(FileDescriptorProto::kSyntaxFieldNumber);
+    SourceLocationCommentPrinter syntax_comment(this, path, "",
+                                                debug_string_options);
+    syntax_comment.AddPreComment(&contents);
+    strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
+                              SyntaxName(syntax()));
+    syntax_comment.AddPostComment(&contents);
+  }
+
+  SourceLocationCommentPrinter comment_printer(this, "", debug_string_options);
+  comment_printer.AddPreComment(&contents);
+
+  std::set<int> public_dependencies;
+  std::set<int> weak_dependencies;
+  public_dependencies.insert(public_dependencies_,
+                             public_dependencies_ + public_dependency_count_);
+  weak_dependencies.insert(weak_dependencies_,
+                           weak_dependencies_ + weak_dependency_count_);
+
+  for (int i = 0; i < dependency_count(); i++) {
+    if (public_dependencies.count(i) > 0) {
+      strings::SubstituteAndAppend(&contents, "import public \"$0\";\n",
+                                dependency(i)->name());
+    } else if (weak_dependencies.count(i) > 0) {
+      strings::SubstituteAndAppend(&contents, "import weak \"$0\";\n",
+                                dependency(i)->name());
+    } else {
+      strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
+                                dependency(i)->name());
+    }
+  }
+
+  if (!package().empty()) {
+    std::vector<int> path;
+    path.push_back(FileDescriptorProto::kPackageFieldNumber);
+    SourceLocationCommentPrinter package_comment(this, path, "",
+                                                 debug_string_options);
+    package_comment.AddPreComment(&contents);
+    strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
+    package_comment.AddPostComment(&contents);
+  }
+
+  if (FormatLineOptions(0, options(), pool(), &contents)) {
+    contents.append("\n");  // add some space if we had options
+  }
+
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->DebugString(0, &contents, debug_string_options);
+    contents.append("\n");
+  }
+
+  // Find all the 'group' type extensions; we will not output their nested
+  // definitions (those will be done with their group field descriptor).
+  std::set<const Descriptor*> groups;
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(extension(i)->message_type());
+    }
+  }
+
+  for (int i = 0; i < message_type_count(); i++) {
+    if (groups.count(message_type(i)) == 0) {
+      message_type(i)->DebugString(0, &contents, debug_string_options,
+                                   /* include_opening_clause */ true);
+      contents.append("\n");
+    }
+  }
+
+  for (int i = 0; i < service_count(); i++) {
+    service(i)->DebugString(&contents, debug_string_options);
+    contents.append("\n");
+  }
+
+  const Descriptor* containing_type = nullptr;
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->containing_type() != containing_type) {
+      if (i > 0) contents.append("}\n\n");
+      containing_type = extension(i)->containing_type();
+      strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
+                                containing_type->full_name());
+    }
+    extension(i)->DebugString(1, &contents, debug_string_options);
+  }
+  if (extension_count() > 0) contents.append("}\n\n");
+
+  comment_printer.AddPostComment(&contents);
+
+  return contents;
+}
+
+std::string Descriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+std::string Descriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options, /* include_opening_clause */ true);
+  return contents;
+}
+
+void Descriptor::DebugString(int depth, std::string* contents,
+                             const DebugStringOptions& debug_string_options,
+                             bool include_opening_clause) const {
+  if (options().map_entry()) {
+    // Do not generate debug string for auto-generated map-entry type.
+    return;
+  }
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  if (include_opening_clause) {
+    strings::SubstituteAndAppend(contents, "$0message $1", prefix, name());
+  }
+  contents->append(" {\n");
+
+  FormatLineOptions(depth, options(), file()->pool(), contents);
+
+  // Find all the 'group' types for fields and extensions; we will not output
+  // their nested definitions (those will be done with their group field
+  // descriptor).
+  std::set<const Descriptor*> groups;
+  for (int i = 0; i < field_count(); i++) {
+    if (field(i)->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(field(i)->message_type());
+    }
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) {
+      groups.insert(extension(i)->message_type());
+    }
+  }
+
+  for (int i = 0; i < nested_type_count(); i++) {
+    if (groups.count(nested_type(i)) == 0) {
+      nested_type(i)->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ true);
+    }
+  }
+  for (int i = 0; i < enum_type_count(); i++) {
+    enum_type(i)->DebugString(depth, contents, debug_string_options);
+  }
+  for (int i = 0; i < field_count(); i++) {
+    if (field(i)->real_containing_oneof() == nullptr) {
+      field(i)->DebugString(depth, contents, debug_string_options);
+    } else if (field(i)->containing_oneof()->field(0) == field(i)) {
+      // This is the first field in this oneof, so print the whole oneof.
+      field(i)->containing_oneof()->DebugString(depth, contents,
+                                                debug_string_options);
+    }
+  }
+
+  for (int i = 0; i < extension_range_count(); i++) {
+    strings::SubstituteAndAppend(contents, "$0  extensions $1 to $2;\n", prefix,
+                              extension_range(i)->start,
+                              extension_range(i)->end - 1);
+  }
+
+  // Group extensions by what they extend, so they can be printed out together.
+  const Descriptor* containing_type = nullptr;
+  for (int i = 0; i < extension_count(); i++) {
+    if (extension(i)->containing_type() != containing_type) {
+      if (i > 0) strings::SubstituteAndAppend(contents, "$0  }\n", prefix);
+      containing_type = extension(i)->containing_type();
+      strings::SubstituteAndAppend(contents, "$0  extend .$1 {\n", prefix,
+                                containing_type->full_name());
+    }
+    extension(i)->DebugString(depth + 1, contents, debug_string_options);
+  }
+  if (extension_count() > 0)
+    strings::SubstituteAndAppend(contents, "$0  }\n", prefix);
+
+  if (reserved_range_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_range_count(); i++) {
+      const Descriptor::ReservedRange* range = reserved_range(i);
+      if (range->end == range->start + 1) {
+        strings::SubstituteAndAppend(contents, "$0, ", range->start);
+      } else if (range->end > FieldDescriptor::kMaxNumber) {
+        strings::SubstituteAndAppend(contents, "$0 to max, ", range->start);
+      } else {
+        strings::SubstituteAndAppend(contents, "$0 to $1, ", range->start,
+                                  range->end - 1);
+      }
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
+  if (reserved_name_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_name_count(); i++) {
+      strings::SubstituteAndAppend(contents, "\"$0\", ",
+                                CEscape(reserved_name(i)));
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
+  strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+  comment_printer.AddPostComment(contents);
+}
+
+std::string FieldDescriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+std::string FieldDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& debug_string_options) const {
+  std::string contents;
+  int depth = 0;
+  if (is_extension()) {
+    strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
+                              containing_type()->full_name());
+    depth = 1;
+  }
+  DebugString(depth, &contents, debug_string_options);
+  if (is_extension()) {
+    contents.append("}\n");
+  }
+  return contents;
+}
+
+// The field type string used in FieldDescriptor::DebugString()
+std::string FieldDescriptor::FieldTypeNameDebugString() const {
+  switch (type()) {
+    case TYPE_MESSAGE:
+      return "." + message_type()->full_name();
+    case TYPE_ENUM:
+      return "." + enum_type()->full_name();
+    default:
+      return kTypeToName[type()];
+  }
+}
+
+void FieldDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  std::string field_type;
+
+  // Special case map fields.
+  if (is_map()) {
+    strings::SubstituteAndAppend(
+        &field_type, "map<$0, $1>",
+        message_type()->field(0)->FieldTypeNameDebugString(),
+        message_type()->field(1)->FieldTypeNameDebugString());
+  } else {
+    field_type = FieldTypeNameDebugString();
+  }
+
+  std::string label = StrCat(kLabelToName[this->label()], " ");
+
+  // Label is omitted for maps, oneof, and plain proto3 fields.
+  if (is_map() || real_containing_oneof() ||
+      (is_optional() && !has_optional_keyword())) {
+    label.clear();
+  }
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(
+      contents, "$0$1$2 $3 = $4", prefix, label, field_type,
+      type() == TYPE_GROUP ? message_type()->name() : name(), number());
+
+  bool bracketed = false;
+  if (has_default_value()) {
+    bracketed = true;
+    strings::SubstituteAndAppend(contents, " [default = $0",
+                              DefaultValueAsString(true));
+  }
+  if (has_json_name_) {
+    if (!bracketed) {
+      bracketed = true;
+      contents->append(" [");
+    } else {
+      contents->append(", ");
+    }
+    contents->append("json_name = \"");
+    contents->append(CEscape(json_name()));
+    contents->append("\"");
+  }
+
+  std::string formatted_options;
+  if (FormatBracketedOptions(depth, options(), file()->pool(),
+                             &formatted_options)) {
+    contents->append(bracketed ? ", " : " [");
+    bracketed = true;
+    contents->append(formatted_options);
+  }
+
+  if (bracketed) {
+    contents->append("]");
+  }
+
+  if (type() == TYPE_GROUP) {
+    if (debug_string_options.elide_group_body) {
+      contents->append(" { ... };\n");
+    } else {
+      message_type()->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ false);
+    }
+  } else {
+    contents->append(";\n");
+  }
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string OneofDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string OneofDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void OneofDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+  strings::SubstituteAndAppend(contents, "$0oneof $1 {", prefix, name());
+
+  FormatLineOptions(depth, options(), containing_type()->file()->pool(),
+                    contents);
+
+  if (debug_string_options.elide_oneof_body) {
+    contents->append(" ... }\n");
+  } else {
+    contents->append("\n");
+    for (int i = 0; i < field_count(); i++) {
+      field(i)->DebugString(depth, contents, debug_string_options);
+    }
+    strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+  }
+  comment_printer.AddPostComment(contents);
+}
+
+std::string EnumDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string EnumDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void EnumDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "$0enum $1 {\n", prefix, name());
+
+  FormatLineOptions(depth, options(), file()->pool(), contents);
+
+  for (int i = 0; i < value_count(); i++) {
+    value(i)->DebugString(depth, contents, debug_string_options);
+  }
+
+  if (reserved_range_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_range_count(); i++) {
+      const EnumDescriptor::ReservedRange* range = reserved_range(i);
+      if (range->end == range->start) {
+        strings::SubstituteAndAppend(contents, "$0, ", range->start);
+      } else if (range->end == INT_MAX) {
+        strings::SubstituteAndAppend(contents, "$0 to max, ", range->start);
+      } else {
+        strings::SubstituteAndAppend(contents, "$0 to $1, ", range->start,
+                                  range->end);
+      }
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
+  if (reserved_name_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_name_count(); i++) {
+      strings::SubstituteAndAppend(contents, "\"$0\", ",
+                                CEscape(reserved_name(i)));
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
+  strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string EnumValueDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string EnumValueDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void EnumValueDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "$0$1 = $2", prefix, name(), number());
+
+  std::string formatted_options;
+  if (FormatBracketedOptions(depth, options(), type()->file()->pool(),
+                             &formatted_options)) {
+    strings::SubstituteAndAppend(contents, " [$0]", formatted_options);
+  }
+  contents->append(";\n");
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string ServiceDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string ServiceDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(&contents, options);
+  return contents;
+}
+
+void ServiceDescriptor::DebugString(
+    std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  SourceLocationCommentPrinter comment_printer(this, /* prefix */ "",
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "service $0 {\n", name());
+
+  FormatLineOptions(1, options(), file()->pool(), contents);
+
+  for (int i = 0; i < method_count(); i++) {
+    method(i)->DebugString(1, contents, debug_string_options);
+  }
+
+  contents->append("}\n");
+
+  comment_printer.AddPostComment(contents);
+}
+
+std::string MethodDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+std::string MethodDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
+  std::string contents;
+  DebugString(0, &contents, options);
+  return contents;
+}
+
+void MethodDescriptor::DebugString(
+    int depth, std::string* contents,
+    const DebugStringOptions& debug_string_options) const {
+  std::string prefix(depth * 2, ' ');
+  ++depth;
+
+  SourceLocationCommentPrinter comment_printer(this, prefix,
+                                               debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(
+      contents, "$0rpc $1($4.$2) returns ($5.$3)", prefix, name(),
+      input_type()->full_name(), output_type()->full_name(),
+      client_streaming() ? "stream " : "", server_streaming() ? "stream " : "");
+
+  std::string formatted_options;
+  if (FormatLineOptions(depth, options(), service()->file()->pool(),
+                        &formatted_options)) {
+    strings::SubstituteAndAppend(contents, " {\n$0$1}\n", formatted_options,
+                              prefix);
+  } else {
+    contents->append(";\n");
+  }
+
+  comment_printer.AddPostComment(contents);
+}
+
+// Location methods ===============================================
+
+bool FileDescriptor::GetSourceLocation(const std::vector<int>& path,
+                                       SourceLocation* out_location) const {
+  GOOGLE_CHECK(out_location != nullptr);
+  if (source_code_info_) {
+    if (const SourceCodeInfo_Location* loc =
+            tables_->GetSourceLocation(path, source_code_info_)) {
+      const RepeatedField<int32_t>& span = loc->span();
+      if (span.size() == 3 || span.size() == 4) {
+        out_location->start_line = span.Get(0);
+        out_location->start_column = span.Get(1);
+        out_location->end_line = span.Get(span.size() == 3 ? 0 : 2);
+        out_location->end_column = span.Get(span.size() - 1);
+
+        out_location->leading_comments = loc->leading_comments();
+        out_location->trailing_comments = loc->trailing_comments();
+        out_location->leading_detached_comments.assign(
+            loc->leading_detached_comments().begin(),
+            loc->leading_detached_comments().end());
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;  // empty path for root FileDescriptor
+  return GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::is_packed() const {
+  if (!is_packable()) return false;
+  if (file_->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+    return (options_ != nullptr) && options_->packed();
+  } else {
+    return options_ == nullptr || !options_->has_packed() || options_->packed();
+  }
+}
+
+bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool FieldDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool OneofDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return containing_type()->file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool MethodDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return service()->file()->GetSourceLocation(path, out_location);
+}
+
+bool ServiceDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return file()->GetSourceLocation(path, out_location);
+}
+
+bool EnumValueDescriptor::GetSourceLocation(
+    SourceLocation* out_location) const {
+  std::vector<int> path;
+  GetLocationPath(&path);
+  return type()->file()->GetSourceLocation(path, out_location);
+}
+
+void Descriptor::GetLocationPath(std::vector<int>* output) const {
+  if (containing_type()) {
+    containing_type()->GetLocationPath(output);
+    output->push_back(DescriptorProto::kNestedTypeFieldNumber);
+    output->push_back(index());
+  } else {
+    output->push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+    output->push_back(index());
+  }
+}
+
+void FieldDescriptor::GetLocationPath(std::vector<int>* output) const {
+  if (is_extension()) {
+    if (extension_scope() == nullptr) {
+      output->push_back(FileDescriptorProto::kExtensionFieldNumber);
+      output->push_back(index());
+    } else {
+      extension_scope()->GetLocationPath(output);
+      output->push_back(DescriptorProto::kExtensionFieldNumber);
+      output->push_back(index());
+    }
+  } else {
+    containing_type()->GetLocationPath(output);
+    output->push_back(DescriptorProto::kFieldFieldNumber);
+    output->push_back(index());
+  }
+}
+
+void OneofDescriptor::GetLocationPath(std::vector<int>* output) const {
+  containing_type()->GetLocationPath(output);
+  output->push_back(DescriptorProto::kOneofDeclFieldNumber);
+  output->push_back(index());
+}
+
+void EnumDescriptor::GetLocationPath(std::vector<int>* output) const {
+  if (containing_type()) {
+    containing_type()->GetLocationPath(output);
+    output->push_back(DescriptorProto::kEnumTypeFieldNumber);
+    output->push_back(index());
+  } else {
+    output->push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+    output->push_back(index());
+  }
+}
+
+void EnumValueDescriptor::GetLocationPath(std::vector<int>* output) const {
+  type()->GetLocationPath(output);
+  output->push_back(EnumDescriptorProto::kValueFieldNumber);
+  output->push_back(index());
+}
+
+void ServiceDescriptor::GetLocationPath(std::vector<int>* output) const {
+  output->push_back(FileDescriptorProto::kServiceFieldNumber);
+  output->push_back(index());
+}
+
+void MethodDescriptor::GetLocationPath(std::vector<int>* output) const {
+  service()->GetLocationPath(output);
+  output->push_back(ServiceDescriptorProto::kMethodFieldNumber);
+  output->push_back(index());
+}
+
+// ===================================================================
+
+namespace {
+
+// Represents an options message to interpret. Extension names in the option
+// name are resolved relative to name_scope. element_name and orig_opt are
+// used only for error reporting (since the parser records locations against
+// pointers in the original options, not the mutable copy). The Message must be
+// one of the Options messages in descriptor.proto.
+struct OptionsToInterpret {
+  OptionsToInterpret(const std::string& ns, const std::string& el,
+                     const std::vector<int>& path, const Message* orig_opt,
+                     Message* opt)
+      : name_scope(ns),
+        element_name(el),
+        element_path(path),
+        original_options(orig_opt),
+        options(opt) {}
+  std::string name_scope;
+  std::string element_name;
+  std::vector<int> element_path;
+  const Message* original_options;
+  Message* options;
+};
+
+}  // namespace
+
+class DescriptorBuilder {
+ public:
+  DescriptorBuilder(const DescriptorPool* pool, DescriptorPool::Tables* tables,
+                    DescriptorPool::ErrorCollector* error_collector);
+  ~DescriptorBuilder();
+
+  const FileDescriptor* BuildFile(const FileDescriptorProto& proto);
+
+ private:
+  friend class OptionInterpreter;
+
+  // Non-recursive part of BuildFile functionality.
+  FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto,
+                                internal::FlatAllocator& alloc);
+
+  const DescriptorPool* pool_;
+  DescriptorPool::Tables* tables_;  // for convenience
+  DescriptorPool::ErrorCollector* error_collector_;
+
+  // As we build descriptors we store copies of the options messages in
+  // them. We put pointers to those copies in this vector, as we build, so we
+  // can later (after cross-linking) interpret those options.
+  std::vector<OptionsToInterpret> options_to_interpret_;
+
+  bool had_errors_;
+  std::string filename_;
+  FileDescriptor* file_;
+  FileDescriptorTables* file_tables_;
+  std::set<const FileDescriptor*> dependencies_;
+
+  struct MessageHints {
+    int fields_to_suggest = 0;
+    const Message* first_reason = nullptr;
+    DescriptorPool::ErrorCollector::ErrorLocation first_reason_location =
+        DescriptorPool::ErrorCollector::ErrorLocation::OTHER;
+
+    void RequestHintOnFieldNumbers(
+        const Message& reason,
+        DescriptorPool::ErrorCollector::ErrorLocation reason_location,
+        int range_start = 0, int range_end = 1) {
+      auto fit = [](int value) {
+        return std::min(std::max(value, 0), FieldDescriptor::kMaxNumber);
+      };
+      fields_to_suggest =
+          fit(fields_to_suggest + fit(fit(range_end) - fit(range_start)));
+      if (first_reason) return;
+      first_reason = &reason;
+      first_reason_location = reason_location;
+    }
+  };
+
+  std::unordered_map<const Descriptor*, MessageHints> message_hints_;
+
+  // unused_dependency_ is used to record the unused imported files.
+  // Note: public import is not considered.
+  std::set<const FileDescriptor*> unused_dependency_;
+
+  // If LookupSymbol() finds a symbol that is in a file which is not a declared
+  // dependency of this file, it will fail, but will set
+  // possible_undeclared_dependency_ to point at that file.  This is only used
+  // by AddNotDefinedError() to report a more useful error message.
+  // possible_undeclared_dependency_name_ is the name of the symbol that was
+  // actually found in possible_undeclared_dependency_, which may be a parent
+  // of the symbol actually looked for.
+  const FileDescriptor* possible_undeclared_dependency_;
+  std::string possible_undeclared_dependency_name_;
+
+  // If LookupSymbol() could resolve a symbol which is not defined,
+  // record the resolved name.  This is only used by AddNotDefinedError()
+  // to report a more useful error message.
+  std::string undefine_resolved_name_;
+
+  // Tracker for current recursion depth to implement recursion protection.
+  //
+  // Counts down to 0 when there is no depth remaining.
+  //
+  // Maximum recursion depth corresponds to 32 nested message declarations.
+  int recursion_depth_ = 32;
+
+  void AddError(const std::string& element_name, const Message& descriptor,
+                DescriptorPool::ErrorCollector::ErrorLocation location,
+                const std::string& error);
+  void AddError(const std::string& element_name, const Message& descriptor,
+                DescriptorPool::ErrorCollector::ErrorLocation location,
+                const char* error);
+  void AddRecursiveImportError(const FileDescriptorProto& proto, int from_here);
+  void AddTwiceListedError(const FileDescriptorProto& proto, int index);
+  void AddImportError(const FileDescriptorProto& proto, int index);
+
+  // Adds an error indicating that undefined_symbol was not defined.  Must
+  // only be called after LookupSymbol() fails.
+  void AddNotDefinedError(
+      const std::string& element_name, const Message& descriptor,
+      DescriptorPool::ErrorCollector::ErrorLocation location,
+      const std::string& undefined_symbol);
+
+  void AddWarning(const std::string& element_name, const Message& descriptor,
+                  DescriptorPool::ErrorCollector::ErrorLocation location,
+                  const std::string& error);
+
+  // Silly helper which determines if the given file is in the given package.
+  // I.e., either file->package() == package_name or file->package() is a
+  // nested package within package_name.
+  bool IsInPackage(const FileDescriptor* file, const std::string& package_name);
+
+  // Helper function which finds all public dependencies of the given file, and
+  // stores the them in the dependencies_ set in the builder.
+  void RecordPublicDependencies(const FileDescriptor* file);
+
+  // Like tables_->FindSymbol(), but additionally:
+  // - Search the pool's underlay if not found in tables_.
+  // - Insure that the resulting Symbol is from one of the file's declared
+  //   dependencies.
+  Symbol FindSymbol(const std::string& name, bool build_it = true);
+
+  // Like FindSymbol() but does not require that the symbol is in one of the
+  // file's declared dependencies.
+  Symbol FindSymbolNotEnforcingDeps(const std::string& name,
+                                    bool build_it = true);
+
+  // This implements the body of FindSymbolNotEnforcingDeps().
+  Symbol FindSymbolNotEnforcingDepsHelper(const DescriptorPool* pool,
+                                          const std::string& name,
+                                          bool build_it = true);
+
+  // Like FindSymbol(), but looks up the name relative to some other symbol
+  // name.  This first searches siblings of relative_to, then siblings of its
+  // parents, etc.  For example, LookupSymbol("foo.bar", "baz.moo.corge") makes
+  // the following calls, returning the first non-null result:
+  // FindSymbol("baz.moo.foo.bar"), FindSymbol("baz.foo.bar"),
+  // FindSymbol("foo.bar").  If AllowUnknownDependencies() has been called
+  // on the DescriptorPool, this will generate a placeholder type if
+  // the name is not found (unless the name itself is malformed).  The
+  // placeholder_type parameter indicates what kind of placeholder should be
+  // constructed in this case.  The resolve_mode parameter determines whether
+  // any symbol is returned, or only symbols that are types.  Note, however,
+  // that LookupSymbol may still return a non-type symbol in LOOKUP_TYPES mode,
+  // if it believes that's all it could refer to.  The caller should always
+  // check that it receives the type of symbol it was expecting.
+  enum ResolveMode { LOOKUP_ALL, LOOKUP_TYPES };
+  Symbol LookupSymbol(const std::string& name, const std::string& relative_to,
+                      DescriptorPool::PlaceholderType placeholder_type =
+                          DescriptorPool::PLACEHOLDER_MESSAGE,
+                      ResolveMode resolve_mode = LOOKUP_ALL,
+                      bool build_it = true);
+
+  // Like LookupSymbol() but will not return a placeholder even if
+  // AllowUnknownDependencies() has been used.
+  Symbol LookupSymbolNoPlaceholder(const std::string& name,
+                                   const std::string& relative_to,
+                                   ResolveMode resolve_mode = LOOKUP_ALL,
+                                   bool build_it = true);
+
+  // Calls tables_->AddSymbol() and records an error if it fails.  Returns
+  // true if successful or false if failed, though most callers can ignore
+  // the return value since an error has already been recorded.
+  bool AddSymbol(const std::string& full_name, const void* parent,
+                 const std::string& name, const Message& proto, Symbol symbol);
+
+  // Like AddSymbol(), but succeeds if the symbol is already defined as long
+  // as the existing definition is also a package (because it's OK to define
+  // the same package in two different files).  Also adds all parents of the
+  // package to the symbol table (e.g. AddPackage("foo.bar", ...) will add
+  // "foo.bar" and "foo" to the table).
+  void AddPackage(const std::string& name, const Message& proto,
+                  FileDescriptor* file);
+
+  // Checks that the symbol name contains only alphanumeric characters and
+  // underscores.  Records an error otherwise.
+  void ValidateSymbolName(const std::string& name, const std::string& full_name,
+                          const Message& proto);
+
+  // Allocates a copy of orig_options in tables_ and stores it in the
+  // descriptor. Remembers its uninterpreted options, to be interpreted
+  // later. DescriptorT must be one of the Descriptor messages from
+  // descriptor.proto.
+  template <class DescriptorT>
+  void AllocateOptions(const typename DescriptorT::OptionsType& orig_options,
+                       DescriptorT* descriptor, int options_field_tag,
+                       const std::string& option_name,
+                       internal::FlatAllocator& alloc);
+  // Specialization for FileOptions.
+  void AllocateOptions(const FileOptions& orig_options,
+                       FileDescriptor* descriptor,
+                       internal::FlatAllocator& alloc);
+
+  // Implementation for AllocateOptions(). Don't call this directly.
+  template <class DescriptorT>
+  void AllocateOptionsImpl(
+      const std::string& name_scope, const std::string& element_name,
+      const typename DescriptorT::OptionsType& orig_options,
+      DescriptorT* descriptor, const std::vector<int>& options_path,
+      const std::string& option_name, internal::FlatAllocator& alloc);
+
+  // Allocates an array of two strings, the first one is a copy of `proto_name`,
+  // and the second one is the full name.
+  // Full proto name is "scope.proto_name" if scope is non-empty and
+  // "proto_name" otherwise.
+  const std::string* AllocateNameStrings(const std::string& scope,
+                                         const std::string& proto_name,
+                                         internal::FlatAllocator& alloc);
+
+  // These methods all have the same signature for the sake of the BUILD_ARRAY
+  // macro, below.
+  void BuildMessage(const DescriptorProto& proto, const Descriptor* parent,
+                    Descriptor* result, internal::FlatAllocator& alloc);
+  void BuildFieldOrExtension(const FieldDescriptorProto& proto,
+                             Descriptor* parent, FieldDescriptor* result,
+                             bool is_extension, internal::FlatAllocator& alloc);
+  void BuildField(const FieldDescriptorProto& proto, Descriptor* parent,
+                  FieldDescriptor* result, internal::FlatAllocator& alloc) {
+    BuildFieldOrExtension(proto, parent, result, false, alloc);
+  }
+  void BuildExtension(const FieldDescriptorProto& proto, Descriptor* parent,
+                      FieldDescriptor* result, internal::FlatAllocator& alloc) {
+    BuildFieldOrExtension(proto, parent, result, true, alloc);
+  }
+  void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
+                           const Descriptor* parent,
+                           Descriptor::ExtensionRange* result,
+                           internal::FlatAllocator& alloc);
+  void BuildReservedRange(const DescriptorProto::ReservedRange& proto,
+                          const Descriptor* parent,
+                          Descriptor::ReservedRange* result,
+                          internal::FlatAllocator& alloc);
+  void BuildReservedRange(const EnumDescriptorProto::EnumReservedRange& proto,
+                          const EnumDescriptor* parent,
+                          EnumDescriptor::ReservedRange* result,
+                          internal::FlatAllocator& alloc);
+  void BuildOneof(const OneofDescriptorProto& proto, Descriptor* parent,
+                  OneofDescriptor* result, internal::FlatAllocator& alloc);
+  void CheckEnumValueUniqueness(const EnumDescriptorProto& proto,
+                                const EnumDescriptor* result);
+  void BuildEnum(const EnumDescriptorProto& proto, const Descriptor* parent,
+                 EnumDescriptor* result, internal::FlatAllocator& alloc);
+  void BuildEnumValue(const EnumValueDescriptorProto& proto,
+                      const EnumDescriptor* parent, EnumValueDescriptor* result,
+                      internal::FlatAllocator& alloc);
+  void BuildService(const ServiceDescriptorProto& proto, const void* dummy,
+                    ServiceDescriptor* result, internal::FlatAllocator& alloc);
+  void BuildMethod(const MethodDescriptorProto& proto,
+                   const ServiceDescriptor* parent, MethodDescriptor* result,
+                   internal::FlatAllocator& alloc);
+
+  void LogUnusedDependency(const FileDescriptorProto& proto,
+                           const FileDescriptor* result);
+
+  // Must be run only after building.
+  //
+  // NOTE: Options will not be available during cross-linking, as they
+  // have not yet been interpreted. Defer any handling of options to the
+  // Validate*Options methods.
+  void CrossLinkFile(FileDescriptor* file, const FileDescriptorProto& proto);
+  void CrossLinkMessage(Descriptor* message, const DescriptorProto& proto);
+  void CrossLinkField(FieldDescriptor* field,
+                      const FieldDescriptorProto& proto);
+  void CrossLinkExtensionRange(Descriptor::ExtensionRange* range,
+                               const DescriptorProto::ExtensionRange& proto);
+  void CrossLinkEnum(EnumDescriptor* enum_type,
+                     const EnumDescriptorProto& proto);
+  void CrossLinkEnumValue(EnumValueDescriptor* enum_value,
+                          const EnumValueDescriptorProto& proto);
+  void CrossLinkService(ServiceDescriptor* service,
+                        const ServiceDescriptorProto& proto);
+  void CrossLinkMethod(MethodDescriptor* method,
+                       const MethodDescriptorProto& proto);
+  void SuggestFieldNumbers(FileDescriptor* file,
+                           const FileDescriptorProto& proto);
+
+  // Must be run only after cross-linking.
+  void InterpretOptions();
+
+  // A helper class for interpreting options.
+  class OptionInterpreter {
+   public:
+    // Creates an interpreter that operates in the context of the pool of the
+    // specified builder, which must not be nullptr. We don't take ownership of
+    // the builder.
+    explicit OptionInterpreter(DescriptorBuilder* builder);
+
+    ~OptionInterpreter();
+
+    // Interprets the uninterpreted options in the specified Options message.
+    // On error, calls AddError() on the underlying builder and returns false.
+    // Otherwise returns true.
+    bool InterpretOptions(OptionsToInterpret* options_to_interpret);
+
+    // Updates the given source code info by re-writing uninterpreted option
+    // locations to refer to the corresponding interpreted option.
+    void UpdateSourceCodeInfo(SourceCodeInfo* info);
+
+    class AggregateOptionFinder;
+
+   private:
+    // Interprets uninterpreted_option_ on the specified message, which
+    // must be the mutable copy of the original options message to which
+    // uninterpreted_option_ belongs. The given src_path is the source
+    // location path to the uninterpreted option, and options_path is the
+    // source location path to the options message. The location paths are
+    // recorded and then used in UpdateSourceCodeInfo.
+    bool InterpretSingleOption(Message* options,
+                               const std::vector<int>& src_path,
+                               const std::vector<int>& options_path);
+
+    // Adds the uninterpreted_option to the given options message verbatim.
+    // Used when AllowUnknownDependencies() is in effect and we can't find
+    // the option's definition.
+    void AddWithoutInterpreting(const UninterpretedOption& uninterpreted_option,
+                                Message* options);
+
+    // A recursive helper function that drills into the intermediate fields
+    // in unknown_fields to check if field innermost_field is set on the
+    // innermost message. Returns false and sets an error if so.
+    bool ExamineIfOptionIsSet(
+        std::vector<const FieldDescriptor*>::const_iterator
+            intermediate_fields_iter,
+        std::vector<const FieldDescriptor*>::const_iterator
+            intermediate_fields_end,
+        const FieldDescriptor* innermost_field,
+        const std::string& debug_msg_name,
+        const UnknownFieldSet& unknown_fields);
+
+    // Validates the value for the option field of the currently interpreted
+    // option and then sets it on the unknown_field.
+    bool SetOptionValue(const FieldDescriptor* option_field,
+                        UnknownFieldSet* unknown_fields);
+
+    // Parses an aggregate value for a CPPTYPE_MESSAGE option and
+    // saves it into *unknown_fields.
+    bool SetAggregateOption(const FieldDescriptor* option_field,
+                            UnknownFieldSet* unknown_fields);
+
+    // Convenience functions to set an int field the right way, depending on
+    // its wire type (a single int CppType can represent multiple wire types).
+    void SetInt32(int number, int32_t value, FieldDescriptor::Type type,
+                  UnknownFieldSet* unknown_fields);
+    void SetInt64(int number, int64_t value, FieldDescriptor::Type type,
+                  UnknownFieldSet* unknown_fields);
+    void SetUInt32(int number, uint32_t value, FieldDescriptor::Type type,
+                   UnknownFieldSet* unknown_fields);
+    void SetUInt64(int number, uint64_t value, FieldDescriptor::Type type,
+                   UnknownFieldSet* unknown_fields);
+
+    // A helper function that adds an error at the specified location of the
+    // option we're currently interpreting, and returns false.
+    bool AddOptionError(DescriptorPool::ErrorCollector::ErrorLocation location,
+                        const std::string& msg) {
+      builder_->AddError(options_to_interpret_->element_name,
+                         *uninterpreted_option_, location, msg);
+      return false;
+    }
+
+    // A helper function that adds an error at the location of the option name
+    // and returns false.
+    bool AddNameError(const std::string& msg) {
+#ifdef PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+      return true;
+#else   // PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+      return AddOptionError(DescriptorPool::ErrorCollector::OPTION_NAME, msg);
+#endif  // PROTOBUF_INTERNAL_IGNORE_FIELD_NAME_ERRORS_
+    }
+
+    // A helper function that adds an error at the location of the option name
+    // and returns false.
+    bool AddValueError(const std::string& msg) {
+      return AddOptionError(DescriptorPool::ErrorCollector::OPTION_VALUE, msg);
+    }
+
+    // We interpret against this builder's pool. Is never nullptr. We don't own
+    // this pointer.
+    DescriptorBuilder* builder_;
+
+    // The options we're currently interpreting, or nullptr if we're not in a
+    // call to InterpretOptions.
+    const OptionsToInterpret* options_to_interpret_;
+
+    // The option we're currently interpreting within options_to_interpret_, or
+    // nullptr if we're not in a call to InterpretOptions(). This points to a
+    // submessage of the original option, not the mutable copy. Therefore we
+    // can use it to find locations recorded by the parser.
+    const UninterpretedOption* uninterpreted_option_;
+
+    // This maps the element path of uninterpreted options to the element path
+    // of the resulting interpreted option. This is used to modify a file's
+    // source code info to account for option interpretation.
+    std::map<std::vector<int>, std::vector<int>> interpreted_paths_;
+
+    // This maps the path to a repeated option field to the known number of
+    // elements the field contains. This is used to track the compute the
+    // index portion of the element path when interpreting a single option.
+    std::map<std::vector<int>, int> repeated_option_counts_;
+
+    // Factory used to create the dynamic messages we need to parse
+    // any aggregate option values we encounter.
+    DynamicMessageFactory dynamic_factory_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OptionInterpreter);
+  };
+
+  // Work-around for broken compilers:  According to the C++ standard,
+  // OptionInterpreter should have access to the private members of any class
+  // which has declared DescriptorBuilder as a friend.  Unfortunately some old
+  // versions of GCC and other compilers do not implement this correctly.  So,
+  // we have to have these intermediate methods to provide access.  We also
+  // redundantly declare OptionInterpreter a friend just to make things extra
+  // clear for these bad compilers.
+  friend class OptionInterpreter;
+  friend class OptionInterpreter::AggregateOptionFinder;
+
+  static inline bool get_allow_unknown(const DescriptorPool* pool) {
+    return pool->allow_unknown_;
+  }
+  static inline bool get_enforce_weak(const DescriptorPool* pool) {
+    return pool->enforce_weak_;
+  }
+  static inline bool get_is_placeholder(const Descriptor* descriptor) {
+    return descriptor != nullptr && descriptor->is_placeholder_;
+  }
+  static inline void assert_mutex_held(const DescriptorPool* pool) {
+    if (pool->mutex_ != nullptr) {
+      pool->mutex_->AssertHeld();
+    }
+  }
+
+  // Must be run only after options have been interpreted.
+  //
+  // NOTE: Validation code must only reference the options in the mutable
+  // descriptors, which are the ones that have been interpreted. The const
+  // proto references are passed in only so they can be provided to calls to
+  // AddError(). Do not look at their options, which have not been interpreted.
+  void ValidateFileOptions(FileDescriptor* file,
+                           const FileDescriptorProto& proto);
+  void ValidateMessageOptions(Descriptor* message,
+                              const DescriptorProto& proto);
+  void ValidateFieldOptions(FieldDescriptor* field,
+                            const FieldDescriptorProto& proto);
+  void ValidateEnumOptions(EnumDescriptor* enm,
+                           const EnumDescriptorProto& proto);
+  void ValidateEnumValueOptions(EnumValueDescriptor* enum_value,
+                                const EnumValueDescriptorProto& proto);
+  void ValidateExtensionRangeOptions(
+      const std::string& full_name, Descriptor::ExtensionRange* extension_range,
+      const DescriptorProto_ExtensionRange& proto);
+  void ValidateServiceOptions(ServiceDescriptor* service,
+                              const ServiceDescriptorProto& proto);
+  void ValidateMethodOptions(MethodDescriptor* method,
+                             const MethodDescriptorProto& proto);
+  void ValidateProto3(FileDescriptor* file, const FileDescriptorProto& proto);
+  void ValidateProto3Message(Descriptor* message, const DescriptorProto& proto);
+  void ValidateProto3Field(FieldDescriptor* field,
+                           const FieldDescriptorProto& proto);
+  void ValidateProto3Enum(EnumDescriptor* enm,
+                          const EnumDescriptorProto& proto);
+
+  // Returns true if the map entry message is compatible with the
+  // auto-generated entry message from map fields syntax.
+  bool ValidateMapEntry(FieldDescriptor* field,
+                        const FieldDescriptorProto& proto);
+
+  // Recursively detects naming conflicts with map entry types for a
+  // better error message.
+  void DetectMapConflicts(const Descriptor* message,
+                          const DescriptorProto& proto);
+
+  void ValidateJSType(FieldDescriptor* field,
+                      const FieldDescriptorProto& proto);
+};
+
+const FileDescriptor* DescriptorPool::BuildFile(
+    const FileDescriptorProto& proto) {
+  GOOGLE_CHECK(fallback_database_ == nullptr)
+      << "Cannot call BuildFile on a DescriptorPool that uses a "
+         "DescriptorDatabase.  You must instead find a way to get your file "
+         "into the underlying database.";
+  GOOGLE_CHECK(mutex_ == nullptr);  // Implied by the above GOOGLE_CHECK.
+  tables_->known_bad_symbols_.clear();
+  tables_->known_bad_files_.clear();
+  return DescriptorBuilder(this, tables_.get(), nullptr).BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::BuildFileCollectingErrors(
+    const FileDescriptorProto& proto, ErrorCollector* error_collector) {
+  GOOGLE_CHECK(fallback_database_ == nullptr)
+      << "Cannot call BuildFile on a DescriptorPool that uses a "
+         "DescriptorDatabase.  You must instead find a way to get your file "
+         "into the underlying database.";
+  GOOGLE_CHECK(mutex_ == nullptr);  // Implied by the above GOOGLE_CHECK.
+  tables_->known_bad_symbols_.clear();
+  tables_->known_bad_files_.clear();
+  return DescriptorBuilder(this, tables_.get(), error_collector)
+      .BuildFile(proto);
+}
+
+const FileDescriptor* DescriptorPool::BuildFileFromDatabase(
+    const FileDescriptorProto& proto) const {
+  mutex_->AssertHeld();
+  if (tables_->known_bad_files_.count(proto.name()) > 0) {
+    return nullptr;
+  }
+  const FileDescriptor* result =
+      DescriptorBuilder(this, tables_.get(), default_error_collector_)
+          .BuildFile(proto);
+  if (result == nullptr) {
+    tables_->known_bad_files_.insert(proto.name());
+  }
+  return result;
+}
+
+DescriptorBuilder::DescriptorBuilder(
+    const DescriptorPool* pool, DescriptorPool::Tables* tables,
+    DescriptorPool::ErrorCollector* error_collector)
+    : pool_(pool),
+      tables_(tables),
+      error_collector_(error_collector),
+      had_errors_(false),
+      possible_undeclared_dependency_(nullptr),
+      undefine_resolved_name_("") {}
+
+DescriptorBuilder::~DescriptorBuilder() {}
+
+void DescriptorBuilder::AddError(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location,
+    const std::string& error) {
+  if (error_collector_ == nullptr) {
+    if (!had_errors_) {
+      GOOGLE_LOG(ERROR) << "Invalid proto descriptor for file \"" << filename_
+                 << "\":";
+    }
+    GOOGLE_LOG(ERROR) << "  " << element_name << ": " << error;
+  } else {
+    error_collector_->AddError(filename_, element_name, &descriptor, location,
+                               error);
+  }
+  had_errors_ = true;
+}
+
+void DescriptorBuilder::AddError(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location, const char* error) {
+  AddError(element_name, descriptor, location, std::string(error));
+}
+
+void DescriptorBuilder::AddNotDefinedError(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location,
+    const std::string& undefined_symbol) {
+  if (possible_undeclared_dependency_ == nullptr &&
+      undefine_resolved_name_.empty()) {
+    AddError(element_name, descriptor, location,
+             "\"" + undefined_symbol + "\" is not defined.");
+  } else {
+    if (possible_undeclared_dependency_ != nullptr) {
+      AddError(element_name, descriptor, location,
+               "\"" + possible_undeclared_dependency_name_ +
+                   "\" seems to be defined in \"" +
+                   possible_undeclared_dependency_->name() +
+                   "\", which is not "
+                   "imported by \"" +
+                   filename_ +
+                   "\".  To use it here, please "
+                   "add the necessary import.");
+    }
+    if (!undefine_resolved_name_.empty()) {
+      AddError(element_name, descriptor, location,
+               "\"" + undefined_symbol + "\" is resolved to \"" +
+                   undefine_resolved_name_ +
+                   "\", which is not defined. "
+                   "The innermost scope is searched first in name resolution. "
+                   "Consider using a leading '.'(i.e., \"." +
+                   undefined_symbol + "\") to start from the outermost scope.");
+    }
+  }
+}
+
+void DescriptorBuilder::AddWarning(
+    const std::string& element_name, const Message& descriptor,
+    DescriptorPool::ErrorCollector::ErrorLocation location,
+    const std::string& error) {
+  if (error_collector_ == nullptr) {
+    GOOGLE_LOG(WARNING) << filename_ << " " << element_name << ": " << error;
+  } else {
+    error_collector_->AddWarning(filename_, element_name, &descriptor, location,
+                                 error);
+  }
+}
+
+bool DescriptorBuilder::IsInPackage(const FileDescriptor* file,
+                                    const std::string& package_name) {
+  return HasPrefixString(file->package(), package_name) &&
+         (file->package().size() == package_name.size() ||
+          file->package()[package_name.size()] == '.');
+}
+
+void DescriptorBuilder::RecordPublicDependencies(const FileDescriptor* file) {
+  if (file == nullptr || !dependencies_.insert(file).second) return;
+  for (int i = 0; file != nullptr && i < file->public_dependency_count(); i++) {
+    RecordPublicDependencies(file->public_dependency(i));
+  }
+}
+
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDepsHelper(
+    const DescriptorPool* pool, const std::string& name, bool build_it) {
+  // If we are looking at an underlay, we must lock its mutex_, since we are
+  // accessing the underlay's tables_ directly.
+  MutexLockMaybe lock((pool == pool_) ? nullptr : pool->mutex_);
+
+  Symbol result = pool->tables_->FindSymbol(name);
+  if (result.IsNull() && pool->underlay_ != nullptr) {
+    // Symbol not found; check the underlay.
+    result = FindSymbolNotEnforcingDepsHelper(pool->underlay_, name);
+  }
+
+  if (result.IsNull()) {
+    // With lazily_build_dependencies_, a symbol lookup at cross link time is
+    // not guaranteed to be successful. In most cases, build_it will be false,
+    // which intentionally prevents us from building an import until it's
+    // actually needed. In some cases, like registering an extension, we want
+    // to build the file containing the symbol, and build_it will be set.
+    // Also, build_it will be true when !lazily_build_dependencies_, to provide
+    // better error reporting of missing dependencies.
+    if (build_it && pool->TryFindSymbolInFallbackDatabase(name)) {
+      result = pool->tables_->FindSymbol(name);
+    }
+  }
+
+  return result;
+}
+
+Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const std::string& name,
+                                                     bool build_it) {
+  Symbol result = FindSymbolNotEnforcingDepsHelper(pool_, name, build_it);
+  // Only find symbols which were defined in this file or one of its
+  // dependencies.
+  const FileDescriptor* file = result.GetFile();
+  if (file == file_ || dependencies_.count(file) > 0) {
+    unused_dependency_.erase(file);
+  }
+  return result;
+}
+
+Symbol DescriptorBuilder::FindSymbol(const std::string& name, bool build_it) {
+  Symbol result = FindSymbolNotEnforcingDeps(name, build_it);
+
+  if (result.IsNull()) return result;
+
+  if (!pool_->enforce_dependencies_) {
+    // Hack for CompilerUpgrader, and also used for lazily_build_dependencies_
+    return result;
+  }
+
+  // Only find symbols which were defined in this file or one of its
+  // dependencies.
+  const FileDescriptor* file = result.GetFile();
+  if (file == file_ || dependencies_.count(file) > 0) {
+    return result;
+  }
+
+  if (result.IsPackage()) {
+    // Arg, this is overcomplicated.  The symbol is a package name.  It could
+    // be that the package was defined in multiple files.  result.GetFile()
+    // returns the first file we saw that used this package.  We've determined
+    // that that file is not a direct dependency of the file we are currently
+    // building, but it could be that some other file which *is* a direct
+    // dependency also defines the same package.  We can't really rule out this
+    // symbol unless none of the dependencies define it.
+    if (IsInPackage(file_, name)) return result;
+    for (std::set<const FileDescriptor*>::const_iterator it =
+             dependencies_.begin();
+         it != dependencies_.end(); ++it) {
+      // Note:  A dependency may be nullptr if it was not found or had errors.
+      if (*it != nullptr && IsInPackage(*it, name)) return result;
+    }
+  }
+
+  possible_undeclared_dependency_ = file;
+  possible_undeclared_dependency_name_ = name;
+  return Symbol();
+}
+
+Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
+    const std::string& name, const std::string& relative_to,
+    ResolveMode resolve_mode, bool build_it) {
+  possible_undeclared_dependency_ = nullptr;
+  undefine_resolved_name_.clear();
+
+  if (!name.empty() && name[0] == '.') {
+    // Fully-qualified name.
+    return FindSymbol(name.substr(1), build_it);
+  }
+
+  // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
+  // defined in multiple parent scopes, we only want to find "Bar.baz" in the
+  // innermost one.  E.g., the following should produce an error:
+  //   message Bar { message Baz {} }
+  //   message Foo {
+  //     message Bar {
+  //     }
+  //     optional Bar.Baz baz = 1;
+  //   }
+  // So, we look for just "Foo" first, then look for "Bar.baz" within it if
+  // found.
+  std::string::size_type name_dot_pos = name.find_first_of('.');
+  std::string first_part_of_name;
+  if (name_dot_pos == std::string::npos) {
+    first_part_of_name = name;
+  } else {
+    first_part_of_name = name.substr(0, name_dot_pos);
+  }
+
+  std::string scope_to_try(relative_to);
+
+  while (true) {
+    // Chop off the last component of the scope.
+    std::string::size_type dot_pos = scope_to_try.find_last_of('.');
+    if (dot_pos == std::string::npos) {
+      return FindSymbol(name, build_it);
+    } else {
+      scope_to_try.erase(dot_pos);
+    }
+
+    // Append ".first_part_of_name" and try to find.
+    std::string::size_type old_size = scope_to_try.size();
+    scope_to_try.append(1, '.');
+    scope_to_try.append(first_part_of_name);
+    Symbol result = FindSymbol(scope_to_try, build_it);
+    if (!result.IsNull()) {
+      if (first_part_of_name.size() < name.size()) {
+        // name is a compound symbol, of which we only found the first part.
+        // Now try to look up the rest of it.
+        if (result.IsAggregate()) {
+          scope_to_try.append(name, first_part_of_name.size(),
+                              name.size() - first_part_of_name.size());
+          result = FindSymbol(scope_to_try, build_it);
+          if (result.IsNull()) {
+            undefine_resolved_name_ = scope_to_try;
+          }
+          return result;
+        } else {
+          // We found a symbol but it's not an aggregate.  Continue the loop.
+        }
+      } else {
+        if (resolve_mode == LOOKUP_TYPES && !result.IsType()) {
+          // We found a symbol but it's not a type.  Continue the loop.
+        } else {
+          return result;
+        }
+      }
+    }
+
+    // Not found.  Remove the name so we can try again.
+    scope_to_try.erase(old_size);
+  }
+}
+
+Symbol DescriptorBuilder::LookupSymbol(
+    const std::string& name, const std::string& relative_to,
+    DescriptorPool::PlaceholderType placeholder_type, ResolveMode resolve_mode,
+    bool build_it) {
+  Symbol result =
+      LookupSymbolNoPlaceholder(name, relative_to, resolve_mode, build_it);
+  if (result.IsNull() && pool_->allow_unknown_) {
+    // Not found, but AllowUnknownDependencies() is enabled.  Return a
+    // placeholder instead.
+    result = pool_->NewPlaceholderWithMutexHeld(name, placeholder_type);
+  }
+  return result;
+}
+
+static bool ValidateQualifiedName(StringPiece name) {
+  bool last_was_period = false;
+
+  for (char character : name) {
+    // I don't trust isalnum() due to locales.  :(
+    if (('a' <= character && character <= 'z') ||
+        ('A' <= character && character <= 'Z') ||
+        ('0' <= character && character <= '9') || (character == '_')) {
+      last_was_period = false;
+    } else if (character == '.') {
+      if (last_was_period) return false;
+      last_was_period = true;
+    } else {
+      return false;
+    }
+  }
+
+  return !name.empty() && !last_was_period;
+}
+
+Symbol DescriptorPool::NewPlaceholder(StringPiece name,
+                                      PlaceholderType placeholder_type) const {
+  MutexLockMaybe lock(mutex_);
+  return NewPlaceholderWithMutexHeld(name, placeholder_type);
+}
+
+Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
+    StringPiece name, PlaceholderType placeholder_type) const {
+  if (mutex_) {
+    mutex_->AssertHeld();
+  }
+  // Compute names.
+  StringPiece placeholder_full_name;
+  StringPiece placeholder_name;
+  const std::string* placeholder_package;
+
+  if (!ValidateQualifiedName(name)) return Symbol();
+  if (name[0] == '.') {
+    // Fully-qualified.
+    placeholder_full_name = name.substr(1);
+  } else {
+    placeholder_full_name = name;
+  }
+
+  // Create the placeholders.
+  internal::FlatAllocator alloc;
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<std::string>(2);
+  if (placeholder_type == PLACEHOLDER_ENUM) {
+    alloc.PlanArray<EnumDescriptor>(1);
+    alloc.PlanArray<EnumValueDescriptor>(1);
+    alloc.PlanArray<std::string>(2);  // names for the descriptor.
+    alloc.PlanArray<std::string>(2);  // names for the value.
+  } else {
+    alloc.PlanArray<Descriptor>(1);
+    alloc.PlanArray<std::string>(2);  // names for the descriptor.
+    if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
+      alloc.PlanArray<Descriptor::ExtensionRange>(1);
+    }
+  }
+  alloc.FinalizePlanning(tables_);
+
+  const std::string::size_type dotpos = placeholder_full_name.find_last_of('.');
+  if (dotpos != std::string::npos) {
+    placeholder_package =
+        alloc.AllocateStrings(placeholder_full_name.substr(0, dotpos));
+    placeholder_name = placeholder_full_name.substr(dotpos + 1);
+  } else {
+    placeholder_package = alloc.AllocateStrings("");
+    placeholder_name = placeholder_full_name;
+  }
+
+  FileDescriptor* placeholder_file = NewPlaceholderFileWithMutexHeld(
+      StrCat(placeholder_full_name, ".placeholder.proto"), alloc);
+  placeholder_file->package_ = placeholder_package;
+
+  if (placeholder_type == PLACEHOLDER_ENUM) {
+    placeholder_file->enum_type_count_ = 1;
+    placeholder_file->enum_types_ = alloc.AllocateArray<EnumDescriptor>(1);
+
+    EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
+    memset(static_cast<void*>(placeholder_enum), 0, sizeof(*placeholder_enum));
+
+    placeholder_enum->all_names_ =
+        alloc.AllocateStrings(placeholder_name, placeholder_full_name);
+    placeholder_enum->file_ = placeholder_file;
+    placeholder_enum->options_ = &EnumOptions::default_instance();
+    placeholder_enum->is_placeholder_ = true;
+    placeholder_enum->is_unqualified_placeholder_ = (name[0] != '.');
+
+    // Enums must have at least one value.
+    placeholder_enum->value_count_ = 1;
+    placeholder_enum->values_ = alloc.AllocateArray<EnumValueDescriptor>(1);
+    // Disable fast-path lookup for this enum.
+    placeholder_enum->sequential_value_limit_ = -1;
+
+    EnumValueDescriptor* placeholder_value = &placeholder_enum->values_[0];
+    memset(static_cast<void*>(placeholder_value), 0,
+           sizeof(*placeholder_value));
+
+    // Note that enum value names are siblings of their type, not children.
+    placeholder_value->all_names_ = alloc.AllocateStrings(
+        "PLACEHOLDER_VALUE", placeholder_package->empty()
+                                 ? "PLACEHOLDER_VALUE"
+                                 : *placeholder_package + ".PLACEHOLDER_VALUE");
+
+    placeholder_value->number_ = 0;
+    placeholder_value->type_ = placeholder_enum;
+    placeholder_value->options_ = &EnumValueOptions::default_instance();
+
+    return Symbol(placeholder_enum);
+  } else {
+    placeholder_file->message_type_count_ = 1;
+    placeholder_file->message_types_ = alloc.AllocateArray<Descriptor>(1);
+
+    Descriptor* placeholder_message = &placeholder_file->message_types_[0];
+    memset(static_cast<void*>(placeholder_message), 0,
+           sizeof(*placeholder_message));
+
+    placeholder_message->all_names_ =
+        alloc.AllocateStrings(placeholder_name, placeholder_full_name);
+    placeholder_message->file_ = placeholder_file;
+    placeholder_message->options_ = &MessageOptions::default_instance();
+    placeholder_message->is_placeholder_ = true;
+    placeholder_message->is_unqualified_placeholder_ = (name[0] != '.');
+
+    if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
+      placeholder_message->extension_range_count_ = 1;
+      placeholder_message->extension_ranges_ =
+          alloc.AllocateArray<Descriptor::ExtensionRange>(1);
+      placeholder_message->extension_ranges_[0].start = 1;
+      // kMaxNumber + 1 because ExtensionRange::end is exclusive.
+      placeholder_message->extension_ranges_[0].end =
+          FieldDescriptor::kMaxNumber + 1;
+      placeholder_message->extension_ranges_[0].options_ = nullptr;
+    }
+
+    return Symbol(placeholder_message);
+  }
+}
+
+FileDescriptor* DescriptorPool::NewPlaceholderFile(
+    StringPiece name) const {
+  MutexLockMaybe lock(mutex_);
+  internal::FlatAllocator alloc;
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<std::string>(1);
+  alloc.FinalizePlanning(tables_);
+
+  return NewPlaceholderFileWithMutexHeld(name, alloc);
+}
+
+FileDescriptor* DescriptorPool::NewPlaceholderFileWithMutexHeld(
+    StringPiece name, internal::FlatAllocator& alloc) const {
+  if (mutex_) {
+    mutex_->AssertHeld();
+  }
+  FileDescriptor* placeholder = alloc.AllocateArray<FileDescriptor>(1);
+  memset(static_cast<void*>(placeholder), 0, sizeof(*placeholder));
+
+  placeholder->name_ = alloc.AllocateStrings(name);
+  placeholder->package_ = &internal::GetEmptyString();
+  placeholder->pool_ = this;
+  placeholder->options_ = &FileOptions::default_instance();
+  placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
+  placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
+  placeholder->is_placeholder_ = true;
+  placeholder->syntax_ = FileDescriptor::SYNTAX_UNKNOWN;
+  placeholder->finished_building_ = true;
+  // All other fields are zero or nullptr.
+
+  return placeholder;
+}
+
+bool DescriptorBuilder::AddSymbol(const std::string& full_name,
+                                  const void* parent, const std::string& name,
+                                  const Message& proto, Symbol symbol) {
+  // If the caller passed nullptr for the parent, the symbol is at file scope.
+  // Use its file as the parent instead.
+  if (parent == nullptr) parent = file_;
+
+  if (full_name.find('\0') != std::string::npos) {
+    AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + full_name + "\" contains null character.");
+    return false;
+  }
+  if (tables_->AddSymbol(full_name, symbol)) {
+    if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) {
+      // This is only possible if there was already an error adding something of
+      // the same name.
+      if (!had_errors_) {
+        GOOGLE_LOG(DFATAL) << "\"" << full_name
+                    << "\" not previously defined in "
+                       "symbols_by_name_, but was defined in "
+                       "symbols_by_parent_; this shouldn't be possible.";
+      }
+      return false;
+    }
+    return true;
+  } else {
+    const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile();
+    if (other_file == file_) {
+      std::string::size_type dot_pos = full_name.find_last_of('.');
+      if (dot_pos == std::string::npos) {
+        AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+                 "\"" + full_name + "\" is already defined.");
+      } else {
+        AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+                 "\"" + full_name.substr(dot_pos + 1) +
+                     "\" is already defined in \"" +
+                     full_name.substr(0, dot_pos) + "\".");
+      }
+    } else {
+      // Symbol seems to have been defined in a different file.
+      AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+               "\"" + full_name + "\" is already defined in file \"" +
+                   (other_file == nullptr ? "null" : other_file->name()) +
+                   "\".");
+    }
+    return false;
+  }
+}
+
+void DescriptorBuilder::AddPackage(const std::string& name,
+                                   const Message& proto, FileDescriptor* file) {
+  if (name.find('\0') != std::string::npos) {
+    AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + name + "\" contains null character.");
+    return;
+  }
+
+  Symbol existing_symbol = tables_->FindSymbol(name);
+  // It's OK to redefine a package.
+  if (existing_symbol.IsNull()) {
+    if (&name == &file->package()) {
+      // It is the toplevel package name, so insert the descriptor directly.
+      tables_->AddSymbol(file->package(), Symbol(file));
+    } else {
+      auto* package = tables_->Allocate<Symbol::Subpackage>();
+      // If the name is the package name, then it is already in the arena.
+      // If not, copy it there. It came from the call to AddPackage below.
+      package->name_size = static_cast<int>(name.size());
+      package->file = file;
+      tables_->AddSymbol(name, Symbol(package));
+    }
+    // Also add parent package, if any.
+    std::string::size_type dot_pos = name.find_last_of('.');
+    if (dot_pos == std::string::npos) {
+      // No parents.
+      ValidateSymbolName(name, name, proto);
+    } else {
+      // Has parent.
+      AddPackage(name.substr(0, dot_pos), proto, file);
+      ValidateSymbolName(name.substr(dot_pos + 1), name, proto);
+    }
+  } else if (!existing_symbol.IsPackage()) {
+    // Symbol seems to have been defined in a different file.
+    const FileDescriptor* other_file = existing_symbol.GetFile();
+    AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + name +
+                 "\" is already defined (as something other than "
+                 "a package) in file \"" +
+                 (other_file == nullptr ? "null" : other_file->name()) + "\".");
+  }
+}
+
+void DescriptorBuilder::ValidateSymbolName(const std::string& name,
+                                           const std::string& full_name,
+                                           const Message& proto) {
+  if (name.empty()) {
+    AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+             "Missing name.");
+  } else {
+    for (char character : name) {
+      // I don't trust isalnum() due to locales.  :(
+      if ((character < 'a' || 'z' < character) &&
+          (character < 'A' || 'Z' < character) &&
+          (character < '0' || '9' < character) && (character != '_')) {
+        AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
+                 "\"" + name + "\" is not a valid identifier.");
+        return;
+      }
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+
+// This generic implementation is good for all descriptors except
+// FileDescriptor.
+template <class DescriptorT>
+void DescriptorBuilder::AllocateOptions(
+    const typename DescriptorT::OptionsType& orig_options,
+    DescriptorT* descriptor, int options_field_tag,
+    const std::string& option_name, internal::FlatAllocator& alloc) {
+  std::vector<int> options_path;
+  descriptor->GetLocationPath(&options_path);
+  options_path.push_back(options_field_tag);
+  AllocateOptionsImpl(descriptor->full_name(), descriptor->full_name(),
+                      orig_options, descriptor, options_path, option_name,
+                      alloc);
+}
+
+// We specialize for FileDescriptor.
+void DescriptorBuilder::AllocateOptions(const FileOptions& orig_options,
+                                        FileDescriptor* descriptor,
+                                        internal::FlatAllocator& alloc) {
+  std::vector<int> options_path;
+  options_path.push_back(FileDescriptorProto::kOptionsFieldNumber);
+  // We add the dummy token so that LookupSymbol does the right thing.
+  AllocateOptionsImpl(descriptor->package() + ".dummy", descriptor->name(),
+                      orig_options, descriptor, options_path,
+                      "google.protobuf.FileOptions", alloc);
+}
+
+template <class DescriptorT>
+void DescriptorBuilder::AllocateOptionsImpl(
+    const std::string& name_scope, const std::string& element_name,
+    const typename DescriptorT::OptionsType& orig_options,
+    DescriptorT* descriptor, const std::vector<int>& options_path,
+    const std::string& option_name, internal::FlatAllocator& alloc) {
+  auto* options = alloc.AllocateArray<typename DescriptorT::OptionsType>(1);
+
+  if (!orig_options.IsInitialized()) {
+    AddError(name_scope + "." + element_name, orig_options,
+             DescriptorPool::ErrorCollector::OPTION_NAME,
+             "Uninterpreted option is missing name or value.");
+    return;
+  }
+
+  // Avoid using MergeFrom()/CopyFrom() in this class to make it -fno-rtti
+  // friendly. Without RTTI, MergeFrom() and CopyFrom() will fallback to the
+  // reflection based method, which requires the Descriptor. However, we are in
+  // the middle of building the descriptors, thus the deadlock.
+  options->ParseFromString(orig_options.SerializeAsString());
+  descriptor->options_ = options;
+
+  // Don't add to options_to_interpret_ unless there were uninterpreted
+  // options.  This not only avoids unnecessary work, but prevents a
+  // bootstrapping problem when building descriptors for descriptor.proto.
+  // descriptor.proto does not contain any uninterpreted options, but
+  // attempting to interpret options anyway will cause
+  // OptionsType::GetDescriptor() to be called which may then deadlock since
+  // we're still trying to build it.
+  if (options->uninterpreted_option_size() > 0) {
+    options_to_interpret_.push_back(OptionsToInterpret(
+        name_scope, element_name, options_path, &orig_options, options));
+  }
+
+  // If the custom option is in unknown fields, no need to interpret it.
+  // Remove the dependency file from unused_dependency.
+  const UnknownFieldSet& unknown_fields = orig_options.unknown_fields();
+  if (!unknown_fields.empty()) {
+    // Can not use options->GetDescriptor() which may case deadlock.
+    Symbol msg_symbol = tables_->FindSymbol(option_name);
+    if (msg_symbol.type() == Symbol::MESSAGE) {
+      for (int i = 0; i < unknown_fields.field_count(); ++i) {
+        assert_mutex_held(pool_);
+        const FieldDescriptor* field =
+            pool_->InternalFindExtensionByNumberNoLock(
+                msg_symbol.descriptor(), unknown_fields.field(i).number());
+        if (field) {
+          unused_dependency_.erase(field->file());
+        }
+      }
+    }
+  }
+}
+
+// A common pattern:  We want to convert a repeated field in the descriptor
+// to an array of values, calling some method to build each value.
+#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT)               \
+  OUTPUT->NAME##_count_ = INPUT.NAME##_size();                         \
+  OUTPUT->NAME##s_ = alloc.AllocateArray<                              \
+      typename std::remove_pointer<decltype(OUTPUT->NAME##s_)>::type>( \
+      INPUT.NAME##_size());                                            \
+  for (int i = 0; i < INPUT.NAME##_size(); i++) {                      \
+    METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc);        \
+  }
+
+void DescriptorBuilder::AddRecursiveImportError(
+    const FileDescriptorProto& proto, int from_here) {
+  std::string error_message("File recursively imports itself: ");
+  for (size_t i = from_here; i < tables_->pending_files_.size(); i++) {
+    error_message.append(tables_->pending_files_[i]);
+    error_message.append(" -> ");
+  }
+  error_message.append(proto.name());
+
+  if (static_cast<size_t>(from_here) < tables_->pending_files_.size() - 1) {
+    AddError(tables_->pending_files_[from_here + 1], proto,
+             DescriptorPool::ErrorCollector::IMPORT, error_message);
+  } else {
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::IMPORT,
+             error_message);
+  }
+}
+
+void DescriptorBuilder::AddTwiceListedError(const FileDescriptorProto& proto,
+                                            int index) {
+  AddError(proto.dependency(index), proto,
+           DescriptorPool::ErrorCollector::IMPORT,
+           "Import \"" + proto.dependency(index) + "\" was listed twice.");
+}
+
+void DescriptorBuilder::AddImportError(const FileDescriptorProto& proto,
+                                       int index) {
+  std::string message;
+  if (pool_->fallback_database_ == nullptr) {
+    message = "Import \"" + proto.dependency(index) + "\" has not been loaded.";
+  } else {
+    message = "Import \"" + proto.dependency(index) +
+              "\" was not found or had errors.";
+  }
+  AddError(proto.dependency(index), proto,
+           DescriptorPool::ErrorCollector::IMPORT, message);
+}
+
+static bool ExistingFileMatchesProto(const FileDescriptor* existing_file,
+                                     const FileDescriptorProto& proto) {
+  FileDescriptorProto existing_proto;
+  existing_file->CopyTo(&existing_proto);
+  // TODO(liujisi): Remove it when CopyTo supports copying syntax params when
+  // syntax="proto2".
+  if (existing_file->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
+      proto.has_syntax()) {
+    existing_proto.set_syntax(
+        existing_file->SyntaxName(existing_file->syntax()));
+  }
+
+  return existing_proto.SerializeAsString() == proto.SerializeAsString();
+}
+
+// These PlanAllocationSize functions will gather into the FlatAllocator all the
+// necessary memory allocations that BuildXXX functions below will do on the
+// Tables object.
+// They *must* be kept in sync. If we miss some PlanArray call we won't have
+// enough memory and will GOOGLE_CHECK-fail.
+static void PlanAllocationSize(
+    const RepeatedPtrField<EnumValueDescriptorProto>& values,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<EnumValueDescriptor>(values.size());
+  alloc.PlanArray<std::string>(2 * values.size());  // name + full_name
+  for (const auto& v : values) {
+    if (v.has_options()) alloc.PlanArray<EnumValueOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<EnumDescriptorProto>& enums,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<EnumDescriptor>(enums.size());
+  alloc.PlanArray<std::string>(2 * enums.size());  // name + full_name
+  for (const auto& e : enums) {
+    if (e.has_options()) alloc.PlanArray<EnumOptions>(1);
+    PlanAllocationSize(e.value(), alloc);
+    alloc.PlanArray<EnumDescriptor::ReservedRange>(e.reserved_range_size());
+    alloc.PlanArray<const std::string*>(e.reserved_name_size());
+    alloc.PlanArray<std::string>(e.reserved_name_size());
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<OneofDescriptorProto>& oneofs,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<OneofDescriptor>(oneofs.size());
+  alloc.PlanArray<std::string>(2 * oneofs.size());  // name + full_name
+  for (const auto& oneof : oneofs) {
+    if (oneof.has_options()) alloc.PlanArray<OneofOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<FieldDescriptorProto>& fields,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<FieldDescriptor>(fields.size());
+  for (const auto& field : fields) {
+    if (field.has_options()) alloc.PlanArray<FieldOptions>(1);
+    alloc.PlanFieldNames(field.name(),
+                         field.has_json_name() ? &field.json_name() : nullptr);
+    if (field.has_default_value() && field.has_type() &&
+        (field.type() == FieldDescriptorProto::TYPE_STRING ||
+         field.type() == FieldDescriptorProto::TYPE_BYTES)) {
+      // For the default string value.
+      alloc.PlanArray<std::string>(1);
+    }
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<DescriptorProto::ExtensionRange>& ranges,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<Descriptor::ExtensionRange>(ranges.size());
+  for (const auto& r : ranges) {
+    if (r.has_options()) alloc.PlanArray<ExtensionRangeOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<DescriptorProto>& messages,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<Descriptor>(messages.size());
+  alloc.PlanArray<std::string>(2 * messages.size());  // name + full_name
+
+  for (const auto& message : messages) {
+    if (message.has_options()) alloc.PlanArray<MessageOptions>(1);
+    PlanAllocationSize(message.nested_type(), alloc);
+    PlanAllocationSize(message.field(), alloc);
+    PlanAllocationSize(message.extension(), alloc);
+    PlanAllocationSize(message.extension_range(), alloc);
+    alloc.PlanArray<Descriptor::ReservedRange>(message.reserved_range_size());
+    alloc.PlanArray<const std::string*>(message.reserved_name_size());
+    alloc.PlanArray<std::string>(message.reserved_name_size());
+    PlanAllocationSize(message.enum_type(), alloc);
+    PlanAllocationSize(message.oneof_decl(), alloc);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<MethodDescriptorProto>& methods,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<MethodDescriptor>(methods.size());
+  alloc.PlanArray<std::string>(2 * methods.size());  // name + full_name
+  for (const auto& m : methods) {
+    if (m.has_options()) alloc.PlanArray<MethodOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<ServiceDescriptorProto>& services,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<ServiceDescriptor>(services.size());
+  alloc.PlanArray<std::string>(2 * services.size());  // name + full_name
+  for (const auto& service : services) {
+    if (service.has_options()) alloc.PlanArray<ServiceOptions>(1);
+    PlanAllocationSize(service.method(), alloc);
+  }
+}
+
+static void PlanAllocationSize(const FileDescriptorProto& proto,
+                               internal::FlatAllocator& alloc) {
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<FileDescriptorTables>(1);
+  alloc.PlanArray<std::string>(2);  // name + package
+  if (proto.has_options()) alloc.PlanArray<FileOptions>(1);
+  if (proto.has_source_code_info()) alloc.PlanArray<SourceCodeInfo>(1);
+
+  PlanAllocationSize(proto.service(), alloc);
+  PlanAllocationSize(proto.message_type(), alloc);
+  PlanAllocationSize(proto.enum_type(), alloc);
+  PlanAllocationSize(proto.extension(), alloc);
+
+  alloc.PlanArray<int>(proto.weak_dependency_size());
+  alloc.PlanArray<int>(proto.public_dependency_size());
+  alloc.PlanArray<const FileDescriptor*>(proto.dependency_size());
+}
+
+const FileDescriptor* DescriptorBuilder::BuildFile(
+    const FileDescriptorProto& proto) {
+  filename_ = proto.name();
+
+  // Check if the file already exists and is identical to the one being built.
+  // Note:  This only works if the input is canonical -- that is, it
+  //   fully-qualifies all type names, has no UninterpretedOptions, etc.
+  //   This is fine, because this idempotency "feature" really only exists to
+  //   accommodate one hack in the proto1->proto2 migration layer.
+  const FileDescriptor* existing_file = tables_->FindFile(filename_);
+  if (existing_file != nullptr) {
+    // File already in pool.  Compare the existing one to the input.
+    if (ExistingFileMatchesProto(existing_file, proto)) {
+      // They're identical.  Return the existing descriptor.
+      return existing_file;
+    }
+
+    // Not a match.  The error will be detected and handled later.
+  }
+
+  // Check to see if this file is already on the pending files list.
+  // TODO(kenton):  Allow recursive imports?  It may not work with some
+  //   (most?) programming languages.  E.g., in C++, a forward declaration
+  //   of a type is not sufficient to allow it to be used even in a
+  //   generated header file due to inlining.  This could perhaps be
+  //   worked around using tricks involving inserting #include statements
+  //   mid-file, but that's pretty ugly, and I'm pretty sure there are
+  //   some languages out there that do not allow recursive dependencies
+  //   at all.
+  for (size_t i = 0; i < tables_->pending_files_.size(); i++) {
+    if (tables_->pending_files_[i] == proto.name()) {
+      AddRecursiveImportError(proto, i);
+      return nullptr;
+    }
+  }
+
+  static const int kMaximumPackageLength = 511;
+  if (proto.package().size() > kMaximumPackageLength) {
+    AddError(proto.package(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Package name is too long");
+    return nullptr;
+  }
+
+  // If we have a fallback_database_, and we aren't doing lazy import building,
+  // attempt to load all dependencies now, before checkpointing tables_.  This
+  // avoids confusion with recursive checkpoints.
+  if (!pool_->lazily_build_dependencies_) {
+    if (pool_->fallback_database_ != nullptr) {
+      tables_->pending_files_.push_back(proto.name());
+      for (int i = 0; i < proto.dependency_size(); i++) {
+        if (tables_->FindFile(proto.dependency(i)) == nullptr &&
+            (pool_->underlay_ == nullptr ||
+             pool_->underlay_->FindFileByName(proto.dependency(i)) ==
+                 nullptr)) {
+          // We don't care what this returns since we'll find out below anyway.
+          pool_->TryFindFileInFallbackDatabase(proto.dependency(i));
+        }
+      }
+      tables_->pending_files_.pop_back();
+    }
+  }
+
+  // Checkpoint the tables so that we can roll back if something goes wrong.
+  tables_->AddCheckpoint();
+
+  internal::FlatAllocator alloc;
+  PlanAllocationSize(proto, alloc);
+  alloc.FinalizePlanning(tables_);
+  FileDescriptor* result = BuildFileImpl(proto, alloc);
+
+  file_tables_->FinalizeTables();
+  if (result) {
+    tables_->ClearLastCheckpoint();
+    result->finished_building_ = true;
+    alloc.ExpectConsumed();
+  } else {
+    tables_->RollbackToLastCheckpoint();
+  }
+
+  return result;
+}
+
+FileDescriptor* DescriptorBuilder::BuildFileImpl(
+    const FileDescriptorProto& proto, internal::FlatAllocator& alloc) {
+  FileDescriptor* result = alloc.AllocateArray<FileDescriptor>(1);
+  file_ = result;
+
+  result->is_placeholder_ = false;
+  result->finished_building_ = false;
+  SourceCodeInfo* info = nullptr;
+  if (proto.has_source_code_info()) {
+    info = alloc.AllocateArray<SourceCodeInfo>(1);
+    info->CopyFrom(proto.source_code_info());
+    result->source_code_info_ = info;
+  } else {
+    result->source_code_info_ = &SourceCodeInfo::default_instance();
+  }
+
+  file_tables_ = alloc.AllocateArray<FileDescriptorTables>(1);
+  file_->tables_ = file_tables_;
+
+  if (!proto.has_name()) {
+    AddError("", proto, DescriptorPool::ErrorCollector::OTHER,
+             "Missing field: FileDescriptorProto.name.");
+  }
+
+  // TODO(liujisi): Report error when the syntax is empty after all the protos
+  // have added the syntax statement.
+  if (proto.syntax().empty() || proto.syntax() == "proto2") {
+    file_->syntax_ = FileDescriptor::SYNTAX_PROTO2;
+  } else if (proto.syntax() == "proto3") {
+    file_->syntax_ = FileDescriptor::SYNTAX_PROTO3;
+  } else {
+    file_->syntax_ = FileDescriptor::SYNTAX_UNKNOWN;
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "Unrecognized syntax: " + proto.syntax());
+  }
+
+  result->name_ = alloc.AllocateStrings(proto.name());
+  if (proto.has_package()) {
+    result->package_ = alloc.AllocateStrings(proto.package());
+  } else {
+    // We cannot rely on proto.package() returning a valid string if
+    // proto.has_package() is false, because we might be running at static
+    // initialization time, in which case default values have not yet been
+    // initialized.
+    result->package_ = alloc.AllocateStrings("");
+  }
+  result->pool_ = pool_;
+
+  if (result->name().find('\0') != std::string::npos) {
+    AddError(result->name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "\"" + result->name() + "\" contains null character.");
+    return nullptr;
+  }
+
+  // Add to tables.
+  if (!tables_->AddFile(result)) {
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "A file with this name is already in the pool.");
+    // Bail out early so that if this is actually the exact same file, we
+    // don't end up reporting that every single symbol is already defined.
+    return nullptr;
+  }
+  if (!result->package().empty()) {
+    if (std::count(result->package().begin(), result->package().end(), '.') >
+        kPackageLimit) {
+      AddError(result->package(), proto, DescriptorPool::ErrorCollector::NAME,
+               "Exceeds Maximum Package Depth");
+      return nullptr;
+    }
+    AddPackage(result->package(), proto, result);
+  }
+
+  // Make sure all dependencies are loaded.
+  std::set<std::string> seen_dependencies;
+  result->dependency_count_ = proto.dependency_size();
+  result->dependencies_ =
+      alloc.AllocateArray<const FileDescriptor*>(proto.dependency_size());
+  result->dependencies_once_ = nullptr;
+  unused_dependency_.clear();
+  std::set<int> weak_deps;
+  for (int i = 0; i < proto.weak_dependency_size(); ++i) {
+    weak_deps.insert(proto.weak_dependency(i));
+  }
+
+  bool need_lazy_deps = false;
+  for (int i = 0; i < proto.dependency_size(); i++) {
+    if (!seen_dependencies.insert(proto.dependency(i)).second) {
+      AddTwiceListedError(proto, i);
+    }
+
+    const FileDescriptor* dependency = tables_->FindFile(proto.dependency(i));
+    if (dependency == nullptr && pool_->underlay_ != nullptr) {
+      dependency = pool_->underlay_->FindFileByName(proto.dependency(i));
+    }
+
+    if (dependency == result) {
+      // Recursive import.  dependency/result is not fully initialized, and it's
+      // dangerous to try to do anything with it.  The recursive import error
+      // will be detected and reported in DescriptorBuilder::BuildFile().
+      return nullptr;
+    }
+
+    if (dependency == nullptr) {
+      if (!pool_->lazily_build_dependencies_) {
+        if (pool_->allow_unknown_ ||
+            (!pool_->enforce_weak_ && weak_deps.find(i) != weak_deps.end())) {
+          internal::FlatAllocator lazy_dep_alloc;
+          lazy_dep_alloc.PlanArray<FileDescriptor>(1);
+          lazy_dep_alloc.PlanArray<std::string>(1);
+          lazy_dep_alloc.FinalizePlanning(tables_);
+          dependency = pool_->NewPlaceholderFileWithMutexHeld(
+              proto.dependency(i), lazy_dep_alloc);
+        } else {
+          AddImportError(proto, i);
+        }
+      }
+    } else {
+      // Add to unused_dependency_ to track unused imported files.
+      // Note: do not track unused imported files for public import.
+      if (pool_->enforce_dependencies_ &&
+          (pool_->unused_import_track_files_.find(proto.name()) !=
+           pool_->unused_import_track_files_.end()) &&
+          (dependency->public_dependency_count() == 0)) {
+        unused_dependency_.insert(dependency);
+      }
+    }
+
+    result->dependencies_[i] = dependency;
+    if (pool_->lazily_build_dependencies_ && !dependency) {
+      need_lazy_deps = true;
+    }
+  }
+  if (need_lazy_deps) {
+    int total_char_size = 0;
+    for (int i = 0; i < proto.dependency_size(); i++) {
+      if (result->dependencies_[i] == nullptr) {
+        total_char_size += static_cast<int>(proto.dependency(i).size());
+      }
+      ++total_char_size;  // For NUL char
+    }
+
+    void* data = tables_->AllocateBytes(
+        static_cast<int>(sizeof(internal::once_flag) + total_char_size));
+    result->dependencies_once_ = ::new (data) internal::once_flag{};
+    char* name_data = reinterpret_cast<char*>(result->dependencies_once_ + 1);
+
+    for (int i = 0; i < proto.dependency_size(); i++) {
+      if (result->dependencies_[i] == nullptr) {
+        memcpy(name_data, proto.dependency(i).c_str(),
+               proto.dependency(i).size());
+        name_data += proto.dependency(i).size();
+      }
+      *name_data++ = '\0';
+    }
+  }
+
+  // Check public dependencies.
+  int public_dependency_count = 0;
+  result->public_dependencies_ =
+      alloc.AllocateArray<int>(proto.public_dependency_size());
+  for (int i = 0; i < proto.public_dependency_size(); i++) {
+    // Only put valid public dependency indexes.
+    int index = proto.public_dependency(i);
+    if (index >= 0 && index < proto.dependency_size()) {
+      result->public_dependencies_[public_dependency_count++] = index;
+      // Do not track unused imported files for public import.
+      // Calling dependency(i) builds that file when doing lazy imports,
+      // need to avoid doing this. Unused dependency detection isn't done
+      // when building lazily, anyways.
+      if (!pool_->lazily_build_dependencies_) {
+        unused_dependency_.erase(result->dependency(index));
+      }
+    } else {
+      AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+               "Invalid public dependency index.");
+    }
+  }
+  result->public_dependency_count_ = public_dependency_count;
+
+  // Build dependency set
+  dependencies_.clear();
+  // We don't/can't do proper dependency error checking when
+  // lazily_build_dependencies_, and calling dependency(i) will force
+  // a dependency to be built, which we don't want.
+  if (!pool_->lazily_build_dependencies_) {
+    for (int i = 0; i < result->dependency_count(); i++) {
+      RecordPublicDependencies(result->dependency(i));
+    }
+  }
+
+  // Check weak dependencies.
+  int weak_dependency_count = 0;
+  result->weak_dependencies_ =
+      alloc.AllocateArray<int>(proto.weak_dependency_size());
+  for (int i = 0; i < proto.weak_dependency_size(); i++) {
+    int index = proto.weak_dependency(i);
+    if (index >= 0 && index < proto.dependency_size()) {
+      result->weak_dependencies_[weak_dependency_count++] = index;
+    } else {
+      AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+               "Invalid weak dependency index.");
+    }
+  }
+  result->weak_dependency_count_ = weak_dependency_count;
+
+  // Convert children.
+  BUILD_ARRAY(proto, result, message_type, BuildMessage, nullptr);
+  BUILD_ARRAY(proto, result, enum_type, BuildEnum, nullptr);
+  BUILD_ARRAY(proto, result, service, BuildService, nullptr);
+  BUILD_ARRAY(proto, result, extension, BuildExtension, nullptr);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result, alloc);
+  }
+
+  // Note that the following steps must occur in exactly the specified order.
+
+  // Cross-link.
+  CrossLinkFile(result, proto);
+
+  if (!message_hints_.empty()) {
+    SuggestFieldNumbers(result, proto);
+  }
+
+  // Interpret any remaining uninterpreted options gathered into
+  // options_to_interpret_ during descriptor building.  Cross-linking has made
+  // extension options known, so all interpretations should now succeed.
+  if (!had_errors_) {
+    OptionInterpreter option_interpreter(this);
+    for (std::vector<OptionsToInterpret>::iterator iter =
+             options_to_interpret_.begin();
+         iter != options_to_interpret_.end(); ++iter) {
+      option_interpreter.InterpretOptions(&(*iter));
+    }
+    options_to_interpret_.clear();
+    if (info != nullptr) {
+      option_interpreter.UpdateSourceCodeInfo(info);
+    }
+  }
+
+  // Validate options. See comments at InternalSetLazilyBuildDependencies about
+  // error checking and lazy import building.
+  if (!had_errors_ && !pool_->lazily_build_dependencies_) {
+    ValidateFileOptions(result, proto);
+  }
+
+  // Additional naming conflict check for map entry types. Only need to check
+  // this if there are already errors.
+  if (had_errors_) {
+    for (int i = 0; i < proto.message_type_size(); ++i) {
+      DetectMapConflicts(result->message_type(i), proto.message_type(i));
+    }
+  }
+
+
+  // Again, see comments at InternalSetLazilyBuildDependencies about error
+  // checking. Also, don't log unused dependencies if there were previous
+  // errors, since the results might be inaccurate.
+  if (!had_errors_ && !unused_dependency_.empty() &&
+      !pool_->lazily_build_dependencies_) {
+    LogUnusedDependency(proto, result);
+  }
+
+  if (had_errors_) {
+    return nullptr;
+  } else {
+    return result;
+  }
+}
+
+
+const std::string* DescriptorBuilder::AllocateNameStrings(
+    const std::string& scope, const std::string& proto_name,
+    internal::FlatAllocator& alloc) {
+  if (scope.empty()) {
+    return alloc.AllocateStrings(proto_name, proto_name);
+  } else {
+    return alloc.AllocateStrings(proto_name,
+                                 StrCat(scope, ".", proto_name));
+  }
+}
+
+namespace {
+
+// Helper for BuildMessage below.
+struct IncrementWhenDestroyed {
+  ~IncrementWhenDestroyed() { ++to_increment; }
+  int& to_increment;
+};
+
+}  // namespace
+
+void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
+                                     const Descriptor* parent,
+                                     Descriptor* result,
+                                     internal::FlatAllocator& alloc) {
+  const std::string& scope =
+      (parent == nullptr) ? file_->package() : parent->full_name();
+  result->all_names_ = AllocateNameStrings(scope, proto.name(), alloc);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  result->file_ = file_;
+  result->containing_type_ = parent;
+  result->is_placeholder_ = false;
+  result->is_unqualified_placeholder_ = false;
+  result->well_known_type_ = Descriptor::WELLKNOWNTYPE_UNSPECIFIED;
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+
+  auto it = pool_->tables_->well_known_types_.find(result->full_name());
+  if (it != pool_->tables_->well_known_types_.end()) {
+    result->well_known_type_ = it->second;
+  }
+
+  // Calculate the continuous sequence of fields.
+  // These can be fast-path'd during lookup and don't need to be added to the
+  // tables.
+  // We use uint16_t to save space for sequential_field_limit_, so stop before
+  // overflowing it. Worst case, we are not taking full advantage on huge
+  // messages, but it is unlikely.
+  result->sequential_field_limit_ = 0;
+  for (int i = 0; i < std::numeric_limits<uint16_t>::max() &&
+                  i < proto.field_size() && proto.field(i).number() == i + 1;
+       ++i) {
+    result->sequential_field_limit_ = i + 1;
+  }
+
+  // Build oneofs first so that fields and extension ranges can refer to them.
+  BUILD_ARRAY(proto, result, oneof_decl, BuildOneof, result);
+  BUILD_ARRAY(proto, result, field, BuildField, result);
+  BUILD_ARRAY(proto, result, enum_type, BuildEnum, result);
+  BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result);
+  BUILD_ARRAY(proto, result, extension, BuildExtension, result);
+  BUILD_ARRAY(proto, result, reserved_range, BuildReservedRange, result);
+
+  // Before building submessages, check recursion limit.
+  --recursion_depth_;
+  IncrementWhenDestroyed revert{recursion_depth_};
+  if (recursion_depth_ <= 0) {
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "Reached maximum recursion limit for nested messages.");
+    result->nested_types_ = nullptr;
+    result->nested_type_count_ = 0;
+    return;
+  }
+  BUILD_ARRAY(proto, result, nested_type, BuildMessage, result);
+
+  // Copy reserved names.
+  int reserved_name_count = proto.reserved_name_size();
+  result->reserved_name_count_ = reserved_name_count;
+  result->reserved_names_ =
+      alloc.AllocateArray<const std::string*>(reserved_name_count);
+  for (int i = 0; i < reserved_name_count; ++i) {
+    result->reserved_names_[i] =
+        alloc.AllocateStrings(proto.reserved_name(i));
+  }
+
+  // Copy options.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    DescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.MessageOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+
+  for (int i = 0; i < proto.reserved_range_size(); i++) {
+    const DescriptorProto_ReservedRange& range1 = proto.reserved_range(i);
+    for (int j = i + 1; j < proto.reserved_range_size(); j++) {
+      const DescriptorProto_ReservedRange& range2 = proto.reserved_range(j);
+      if (range1.end() > range2.start() && range2.end() > range1.start()) {
+        AddError(result->full_name(), proto.reserved_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Reserved range $0 to $1 overlaps with "
+                                  "already-defined range $2 to $3.",
+                                  range2.start(), range2.end() - 1,
+                                  range1.start(), range1.end() - 1));
+      }
+    }
+  }
+
+  HASH_SET<std::string> reserved_name_set;
+  for (int i = 0; i < proto.reserved_name_size(); i++) {
+    const std::string& name = proto.reserved_name(i);
+    if (reserved_name_set.find(name) == reserved_name_set.end()) {
+      reserved_name_set.insert(name);
+    } else {
+      AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+               strings::Substitute("Field name \"$0\" is reserved multiple times.",
+                                name));
+    }
+  }
+
+
+  for (int i = 0; i < result->field_count(); i++) {
+    const FieldDescriptor* field = result->field(i);
+    for (int j = 0; j < result->extension_range_count(); j++) {
+      const Descriptor::ExtensionRange* range = result->extension_range(j);
+      if (range->start <= field->number() && field->number() < range->end) {
+        message_hints_[result].RequestHintOnFieldNumbers(
+            proto.extension_range(j), DescriptorPool::ErrorCollector::NUMBER);
+        AddError(
+            field->full_name(), proto.extension_range(j),
+            DescriptorPool::ErrorCollector::NUMBER,
+            strings::Substitute(
+                "Extension range $0 to $1 includes field \"$2\" ($3).",
+                range->start, range->end - 1, field->name(), field->number()));
+      }
+    }
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const Descriptor::ReservedRange* range = result->reserved_range(j);
+      if (range->start <= field->number() && field->number() < range->end) {
+        message_hints_[result].RequestHintOnFieldNumbers(
+            proto.reserved_range(j), DescriptorPool::ErrorCollector::NUMBER);
+        AddError(field->full_name(), proto.reserved_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Field \"$0\" uses reserved number $1.",
+                                  field->name(), field->number()));
+      }
+    }
+    if (reserved_name_set.find(field->name()) != reserved_name_set.end()) {
+      AddError(
+          field->full_name(), proto.field(i),
+          DescriptorPool::ErrorCollector::NAME,
+          strings::Substitute("Field name \"$0\" is reserved.", field->name()));
+    }
+
+  }
+
+  // Check that extension ranges don't overlap and don't include
+  // reserved field numbers or names.
+  for (int i = 0; i < result->extension_range_count(); i++) {
+    const Descriptor::ExtensionRange* range1 = result->extension_range(i);
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const Descriptor::ReservedRange* range2 = result->reserved_range(j);
+      if (range1->end > range2->start && range2->end > range1->start) {
+        AddError(result->full_name(), proto.extension_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Extension range $0 to $1 overlaps with "
+                                  "reserved range $2 to $3.",
+                                  range1->start, range1->end - 1, range2->start,
+                                  range2->end - 1));
+      }
+    }
+    for (int j = i + 1; j < result->extension_range_count(); j++) {
+      const Descriptor::ExtensionRange* range2 = result->extension_range(j);
+      if (range1->end > range2->start && range2->end > range1->start) {
+        AddError(result->full_name(), proto.extension_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Extension range $0 to $1 overlaps with "
+                                  "already-defined range $2 to $3.",
+                                  range2->start, range2->end - 1, range1->start,
+                                  range1->end - 1));
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
+                                              Descriptor* parent,
+                                              FieldDescriptor* result,
+                                              bool is_extension,
+                                              internal::FlatAllocator& alloc) {
+  const std::string& scope =
+      (parent == nullptr) ? file_->package() : parent->full_name();
+
+  // We allocate all names in a single array, and dedup them.
+  // We remember the indices for the potentially deduped values.
+  auto all_names = alloc.AllocateFieldNames(
+      proto.name(), scope,
+      proto.has_json_name() ? &proto.json_name() : nullptr);
+  result->all_names_ = all_names.array;
+  result->lowercase_name_index_ = all_names.lowercase_index;
+  result->camelcase_name_index_ = all_names.camelcase_index;
+  result->json_name_index_ = all_names.json_index;
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  result->file_ = file_;
+  result->number_ = proto.number();
+  result->is_extension_ = is_extension;
+  result->is_oneof_ = false;
+  result->proto3_optional_ = proto.proto3_optional();
+
+  if (proto.proto3_optional() &&
+      file_->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "The [proto3_optional=true] option may only be set on proto3"
+             "fields, not " +
+                 result->full_name());
+  }
+
+  result->has_json_name_ = proto.has_json_name();
+
+  // Some compilers do not allow static_cast directly between two enum types,
+  // so we must cast to int first.
+  result->type_ = static_cast<FieldDescriptor::Type>(
+      implicit_cast<int>(proto.type()));
+  result->label_ = static_cast<FieldDescriptor::Label>(
+      implicit_cast<int>(proto.label()));
+
+  if (result->label_ == FieldDescriptor::LABEL_REQUIRED) {
+    // An extension cannot have a required field (b/13365836).
+    if (result->is_extension_) {
+      AddError(result->full_name(), proto,
+               // Error location `TYPE`: we would really like to indicate
+               // `LABEL`, but the `ErrorLocation` enum has no entry for this,
+               // and we don't necessarily know about all implementations of the
+               // `ErrorCollector` interface to extend them to handle the new
+               // error location type properly.
+               DescriptorPool::ErrorCollector::TYPE,
+               "The extension " + result->full_name() + " cannot be required.");
+    }
+  }
+
+  // Some of these may be filled in when cross-linking.
+  result->containing_type_ = nullptr;
+  result->type_once_ = nullptr;
+  result->default_value_enum_ = nullptr;
+
+  result->has_default_value_ = proto.has_default_value();
+  if (proto.has_default_value() && result->is_repeated()) {
+    AddError(result->full_name(), proto,
+             DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+             "Repeated fields can't have default values.");
+  }
+
+  if (proto.has_type()) {
+    if (proto.has_default_value()) {
+      char* end_pos = nullptr;
+      switch (result->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+          result->default_value_int32_t_ =
+              strtol(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_INT64:
+          result->default_value_int64_t_ =
+              strto64(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_UINT32:
+          result->default_value_uint32_t_ =
+              strtoul(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_UINT64:
+          result->default_value_uint64_t_ =
+              strtou64(proto.default_value().c_str(), &end_pos, 0);
+          break;
+        case FieldDescriptor::CPPTYPE_FLOAT:
+          if (proto.default_value() == "inf") {
+            result->default_value_float_ =
+                std::numeric_limits<float>::infinity();
+          } else if (proto.default_value() == "-inf") {
+            result->default_value_float_ =
+                -std::numeric_limits<float>::infinity();
+          } else if (proto.default_value() == "nan") {
+            result->default_value_float_ =
+                std::numeric_limits<float>::quiet_NaN();
+          } else {
+            result->default_value_float_ = io::SafeDoubleToFloat(
+                io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos));
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          if (proto.default_value() == "inf") {
+            result->default_value_double_ =
+                std::numeric_limits<double>::infinity();
+          } else if (proto.default_value() == "-inf") {
+            result->default_value_double_ =
+                -std::numeric_limits<double>::infinity();
+          } else if (proto.default_value() == "nan") {
+            result->default_value_double_ =
+                std::numeric_limits<double>::quiet_NaN();
+          } else {
+            result->default_value_double_ =
+                io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          if (proto.default_value() == "true") {
+            result->default_value_bool_ = true;
+          } else if (proto.default_value() == "false") {
+            result->default_value_bool_ = false;
+          } else {
+            AddError(result->full_name(), proto,
+                     DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                     "Boolean default must be true or false.");
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_ENUM:
+          // This will be filled in when cross-linking.
+          result->default_value_enum_ = nullptr;
+          break;
+        case FieldDescriptor::CPPTYPE_STRING:
+          if (result->type() == FieldDescriptor::TYPE_BYTES) {
+            result->default_value_string_ = alloc.AllocateStrings(
+                UnescapeCEscapeString(proto.default_value()));
+          } else {
+            result->default_value_string_ =
+                alloc.AllocateStrings(proto.default_value());
+          }
+          break;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          AddError(result->full_name(), proto,
+                   DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                   "Messages can't have default values.");
+          result->has_default_value_ = false;
+          result->default_generated_instance_ = nullptr;
+          break;
+      }
+
+      if (end_pos != nullptr) {
+        // end_pos is only set non-null by the parsers for numeric types,
+        // above. This checks that the default was non-empty and had no extra
+        // junk after the end of the number.
+        if (proto.default_value().empty() || *end_pos != '\0') {
+          AddError(result->full_name(), proto,
+                   DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                   "Couldn't parse default value \"" + proto.default_value() +
+                       "\".");
+        }
+      }
+    } else {
+      // No explicit default value
+      switch (result->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+          result->default_value_int32_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_INT64:
+          result->default_value_int64_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_UINT32:
+          result->default_value_uint32_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_UINT64:
+          result->default_value_uint64_t_ = 0;
+          break;
+        case FieldDescriptor::CPPTYPE_FLOAT:
+          result->default_value_float_ = 0.0f;
+          break;
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          result->default_value_double_ = 0.0;
+          break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          result->default_value_bool_ = false;
+          break;
+        case FieldDescriptor::CPPTYPE_ENUM:
+          // This will be filled in when cross-linking.
+          result->default_value_enum_ = nullptr;
+          break;
+        case FieldDescriptor::CPPTYPE_STRING:
+          result->default_value_string_ = &internal::GetEmptyString();
+          break;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          result->default_generated_instance_ = nullptr;
+          break;
+      }
+    }
+  }
+
+  if (result->number() <= 0) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER);
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Field numbers must be positive integers.");
+  } else if (!is_extension && result->number() > FieldDescriptor::kMaxNumber) {
+    // Only validate that the number is within the valid field range if it is
+    // not an extension. Since extension numbers are validated with the
+    // extendee's valid set of extension numbers, and those are in turn
+    // validated against the max allowed number, the check is unnecessary for
+    // extension fields.
+    // This avoids cross-linking issues that arise when attempting to check if
+    // the extendee is a message_set_wire_format message, which has a higher max
+    // on extension numbers.
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER);
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             strings::Substitute("Field numbers cannot be greater than $0.",
+                              FieldDescriptor::kMaxNumber));
+  } else if (result->number() >= FieldDescriptor::kFirstReservedNumber &&
+             result->number() <= FieldDescriptor::kLastReservedNumber) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER);
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             strings::Substitute(
+                 "Field numbers $0 through $1 are reserved for the protocol "
+                 "buffer library implementation.",
+                 FieldDescriptor::kFirstReservedNumber,
+                 FieldDescriptor::kLastReservedNumber));
+  }
+
+  if (is_extension) {
+    if (!proto.has_extendee()) {
+      AddError(result->full_name(), proto,
+               DescriptorPool::ErrorCollector::EXTENDEE,
+               "FieldDescriptorProto.extendee not set for extension field.");
+    }
+
+    result->scope_.extension_scope = parent;
+
+    if (proto.has_oneof_index()) {
+      AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "FieldDescriptorProto.oneof_index should not be set for "
+               "extensions.");
+    }
+  } else {
+    if (proto.has_extendee()) {
+      AddError(result->full_name(), proto,
+               DescriptorPool::ErrorCollector::EXTENDEE,
+               "FieldDescriptorProto.extendee set for non-extension field.");
+    }
+
+    result->containing_type_ = parent;
+
+    if (proto.has_oneof_index()) {
+      if (proto.oneof_index() < 0 ||
+          proto.oneof_index() >= parent->oneof_decl_count()) {
+        AddError(result->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 strings::Substitute("FieldDescriptorProto.oneof_index $0 is "
+                                  "out of range for type \"$1\".",
+                                  proto.oneof_index(), parent->name()));
+      } else {
+        result->is_oneof_ = true;
+        result->scope_.containing_oneof =
+            parent->oneof_decl(proto.oneof_index());
+      }
+    }
+  }
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    FieldDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.FieldOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+}
+
+void DescriptorBuilder::BuildExtensionRange(
+    const DescriptorProto::ExtensionRange& proto, const Descriptor* parent,
+    Descriptor::ExtensionRange* result, internal::FlatAllocator& alloc) {
+  result->start = proto.start();
+  result->end = proto.end();
+  if (result->start <= 0) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER, result->start,
+        result->end);
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Extension numbers must be positive integers.");
+  }
+
+  // Checking of the upper bound of the extension range is deferred until after
+  // options interpreting. This allows messages with message_set_wire_format to
+  // have extensions beyond FieldDescriptor::kMaxNumber, since the extension
+  // numbers are actually used as int32s in the message_set_wire_format.
+
+  if (result->start >= result->end) {
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Extension range end number must be greater than start number.");
+  }
+
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    std::vector<int> options_path;
+    parent->GetLocationPath(&options_path);
+    options_path.push_back(DescriptorProto::kExtensionRangeFieldNumber);
+    // find index of this extension range in order to compute path
+    int index;
+    for (index = 0; parent->extension_ranges_ + index != result; index++) {
+    }
+    options_path.push_back(index);
+    options_path.push_back(DescriptorProto_ExtensionRange::kOptionsFieldNumber);
+    AllocateOptionsImpl(parent->full_name(), parent->full_name(),
+                        proto.options(), result, options_path,
+                        "google.protobuf.ExtensionRangeOptions", alloc);
+  }
+}
+
+void DescriptorBuilder::BuildReservedRange(
+    const DescriptorProto::ReservedRange& proto, const Descriptor* parent,
+    Descriptor::ReservedRange* result, internal::FlatAllocator&) {
+  result->start = proto.start();
+  result->end = proto.end();
+  if (result->start <= 0) {
+    message_hints_[parent].RequestHintOnFieldNumbers(
+        proto, DescriptorPool::ErrorCollector::NUMBER, result->start,
+        result->end);
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Reserved numbers must be positive integers.");
+  }
+}
+
+void DescriptorBuilder::BuildReservedRange(
+    const EnumDescriptorProto::EnumReservedRange& proto,
+    const EnumDescriptor* parent, EnumDescriptor::ReservedRange* result,
+    internal::FlatAllocator&) {
+  result->start = proto.start();
+  result->end = proto.end();
+
+  if (result->start > result->end) {
+    AddError(parent->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
+             "Reserved range end number must be greater than start number.");
+  }
+}
+
+void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
+                                   Descriptor* parent, OneofDescriptor* result,
+                                   internal::FlatAllocator& alloc) {
+  result->all_names_ =
+      AllocateNameStrings(parent->full_name(), proto.name(), alloc);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  result->containing_type_ = parent;
+
+  // We need to fill these in later.
+  result->field_count_ = 0;
+  result->fields_ = nullptr;
+  result->options_ = nullptr;
+
+  // Copy options.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    OneofDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.OneofOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+}
+
+void DescriptorBuilder::CheckEnumValueUniqueness(
+    const EnumDescriptorProto& proto, const EnumDescriptor* result) {
+
+  // Check that enum labels are still unique when we remove the enum prefix from
+  // values that have it.
+  //
+  // This will fail for something like:
+  //
+  //   enum MyEnum {
+  //     MY_ENUM_FOO = 0;
+  //     FOO = 1;
+  //   }
+  //
+  // By enforcing this reasonable constraint, we allow code generators to strip
+  // the prefix and/or PascalCase it without creating conflicts.  This can lead
+  // to much nicer language-specific enums like:
+  //
+  //   enum NameType {
+  //     FirstName = 1,
+  //     LastName = 2,
+  //   }
+  //
+  // Instead of:
+  //
+  //   enum NameType {
+  //     NAME_TYPE_FIRST_NAME = 1,
+  //     NAME_TYPE_LAST_NAME = 2,
+  //   }
+  PrefixRemover remover(result->name());
+  std::map<std::string, const EnumValueDescriptor*> values;
+  for (int i = 0; i < result->value_count(); i++) {
+    const EnumValueDescriptor* value = result->value(i);
+    std::string stripped =
+        EnumValueToPascalCase(remover.MaybeRemove(value->name()));
+    std::pair<std::map<std::string, const EnumValueDescriptor*>::iterator, bool>
+        insert_result = values.insert(std::make_pair(stripped, value));
+    bool inserted = insert_result.second;
+
+    // We don't throw the error if the two conflicting symbols are identical, or
+    // if they map to the same number.  In the former case, the normal symbol
+    // duplication error will fire so we don't need to (and its error message
+    // will make more sense). We allow the latter case so users can create
+    // aliases which add or remove the prefix (code generators that do prefix
+    // stripping should de-dup the labels in this case).
+    if (!inserted && insert_result.first->second->name() != value->name() &&
+        insert_result.first->second->number() != value->number()) {
+      std::string error_message =
+          "Enum name " + value->name() + " has the same name as " +
+          values[stripped]->name() +
+          " if you ignore case and strip out the enum name prefix (if any). "
+          "This is error-prone and can lead to undefined behavior. "
+          "Please avoid doing this. If you are using allow_alias, please "
+          "assign the same numeric value to both enums.";
+      // There are proto2 enums out there with conflicting names, so to preserve
+      // compatibility we issue only a warning for proto2.
+      if (result->file()->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+        AddWarning(value->full_name(), proto.value(i),
+                   DescriptorPool::ErrorCollector::NAME, error_message);
+      } else {
+        AddError(value->full_name(), proto.value(i),
+                 DescriptorPool::ErrorCollector::NAME, error_message);
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
+                                  const Descriptor* parent,
+                                  EnumDescriptor* result,
+                                  internal::FlatAllocator& alloc) {
+  const std::string& scope =
+      (parent == nullptr) ? file_->package() : parent->full_name();
+
+  result->all_names_ = AllocateNameStrings(scope, proto.name(), alloc);
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+  result->file_ = file_;
+  result->containing_type_ = parent;
+  result->is_placeholder_ = false;
+  result->is_unqualified_placeholder_ = false;
+
+  if (proto.value_size() == 0) {
+    // We cannot allow enums with no values because this would mean there
+    // would be no valid default value for fields of this type.
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Enums must contain at least one value.");
+  }
+
+  // Calculate the continuous sequence of the labels.
+  // These can be fast-path'd during lookup and don't need to be added to the
+  // tables.
+  // We use uint16_t to save space for sequential_value_limit_, so stop before
+  // overflowing it. Worst case, we are not taking full advantage on huge
+  // enums, but it is unlikely.
+  for (int i = 0;
+       i < std::numeric_limits<uint16_t>::max() && i < proto.value_size() &&
+       // We do the math in int64_t to avoid overflows.
+       proto.value(i).number() ==
+           static_cast<int64_t>(i) + proto.value(0).number();
+       ++i) {
+    result->sequential_value_limit_ = i;
+  }
+
+  BUILD_ARRAY(proto, result, value, BuildEnumValue, result);
+  BUILD_ARRAY(proto, result, reserved_range, BuildReservedRange, result);
+
+  // Copy reserved names.
+  int reserved_name_count = proto.reserved_name_size();
+  result->reserved_name_count_ = reserved_name_count;
+  result->reserved_names_ =
+      alloc.AllocateArray<const std::string*>(reserved_name_count);
+  for (int i = 0; i < reserved_name_count; ++i) {
+    result->reserved_names_[i] =
+        alloc.AllocateStrings(proto.reserved_name(i));
+  }
+
+  CheckEnumValueUniqueness(proto, result);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    EnumDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.EnumOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+
+  for (int i = 0; i < proto.reserved_range_size(); i++) {
+    const EnumDescriptorProto_EnumReservedRange& range1 =
+        proto.reserved_range(i);
+    for (int j = i + 1; j < proto.reserved_range_size(); j++) {
+      const EnumDescriptorProto_EnumReservedRange& range2 =
+          proto.reserved_range(j);
+      if (range1.end() >= range2.start() && range2.end() >= range1.start()) {
+        AddError(result->full_name(), proto.reserved_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Reserved range $0 to $1 overlaps with "
+                                  "already-defined range $2 to $3.",
+                                  range2.start(), range2.end(), range1.start(),
+                                  range1.end()));
+      }
+    }
+  }
+
+  HASH_SET<std::string> reserved_name_set;
+  for (int i = 0; i < proto.reserved_name_size(); i++) {
+    const std::string& name = proto.reserved_name(i);
+    if (reserved_name_set.find(name) == reserved_name_set.end()) {
+      reserved_name_set.insert(name);
+    } else {
+      AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+               strings::Substitute("Enum value \"$0\" is reserved multiple times.",
+                                name));
+    }
+  }
+
+  for (int i = 0; i < result->value_count(); i++) {
+    const EnumValueDescriptor* value = result->value(i);
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const EnumDescriptor::ReservedRange* range = result->reserved_range(j);
+      if (range->start <= value->number() && value->number() <= range->end) {
+        AddError(value->full_name(), proto.reserved_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Enum value \"$0\" uses reserved number $1.",
+                                  value->name(), value->number()));
+      }
+    }
+    if (reserved_name_set.find(value->name()) != reserved_name_set.end()) {
+      AddError(
+          value->full_name(), proto.value(i),
+          DescriptorPool::ErrorCollector::NAME,
+          strings::Substitute("Enum value \"$0\" is reserved.", value->name()));
+    }
+  }
+}
+
+void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
+                                       const EnumDescriptor* parent,
+                                       EnumValueDescriptor* result,
+                                       internal::FlatAllocator& alloc) {
+  // Note:  full_name for enum values is a sibling to the parent's name, not a
+  //   child of it.
+  std::string full_name;
+  size_t scope_len = parent->full_name().size() - parent->name().size();
+  full_name.reserve(scope_len + proto.name().size());
+  full_name.append(parent->full_name().data(), scope_len);
+  full_name.append(proto.name());
+
+  result->all_names_ =
+      alloc.AllocateStrings(proto.name(), std::move(full_name));
+  result->number_ = proto.number();
+  result->type_ = parent;
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    EnumValueDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.EnumValueOptions", alloc);
+  }
+
+  // Again, enum values are weird because we makes them appear as siblings
+  // of the enum type instead of children of it.  So, we use
+  // parent->containing_type() as the value's parent.
+  bool added_to_outer_scope =
+      AddSymbol(result->full_name(), parent->containing_type(), result->name(),
+                proto, Symbol::EnumValue(result, 0));
+
+  // However, we also want to be able to search for values within a single
+  // enum type, so we add it as a child of the enum type itself, too.
+  // Note:  This could fail, but if it does, the error has already been
+  //   reported by the above AddSymbol() call, so we ignore the return code.
+  bool added_to_inner_scope = file_tables_->AddAliasUnderParent(
+      parent, result->name(), Symbol::EnumValue(result, 1));
+
+  if (added_to_inner_scope && !added_to_outer_scope) {
+    // This value did not conflict with any values defined in the same enum,
+    // but it did conflict with some other symbol defined in the enum type's
+    // scope.  Let's print an additional error to explain this.
+    std::string outer_scope;
+    if (parent->containing_type() == nullptr) {
+      outer_scope = file_->package();
+    } else {
+      outer_scope = parent->containing_type()->full_name();
+    }
+
+    if (outer_scope.empty()) {
+      outer_scope = "the global scope";
+    } else {
+      outer_scope = "\"" + outer_scope + "\"";
+    }
+
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Note that enum values use C++ scoping rules, meaning that "
+             "enum values are siblings of their type, not children of it.  "
+             "Therefore, \"" +
+                 result->name() + "\" must be unique within " + outer_scope +
+                 ", not just within \"" + parent->name() + "\".");
+  }
+
+  // An enum is allowed to define two numbers that refer to the same value.
+  // FindValueByNumber() should return the first such value, so we simply
+  // ignore AddEnumValueByNumber()'s return code.
+  file_tables_->AddEnumValueByNumber(result);
+}
+
+void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
+                                     const void* /* dummy */,
+                                     ServiceDescriptor* result,
+                                     internal::FlatAllocator& alloc) {
+  result->all_names_ =
+      AllocateNameStrings(file_->package(), proto.name(), alloc);
+  result->file_ = file_;
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  BUILD_ARRAY(proto, result, method, BuildMethod, result);
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    ServiceDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.ServiceOptions", alloc);
+  }
+
+  AddSymbol(result->full_name(), nullptr, result->name(), proto,
+            Symbol(result));
+}
+
+void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
+                                    const ServiceDescriptor* parent,
+                                    MethodDescriptor* result,
+                                    internal::FlatAllocator& alloc) {
+  result->service_ = parent;
+  result->all_names_ =
+      AllocateNameStrings(parent->full_name(), proto.name(), alloc);
+
+  ValidateSymbolName(proto.name(), result->full_name(), proto);
+
+  // These will be filled in when cross-linking.
+  result->input_type_.Init();
+  result->output_type_.Init();
+
+  // Copy options.
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
+  if (proto.has_options()) {
+    AllocateOptions(proto.options(), result,
+                    MethodDescriptorProto::kOptionsFieldNumber,
+                    "google.protobuf.MethodOptions", alloc);
+  }
+
+  result->client_streaming_ = proto.client_streaming();
+  result->server_streaming_ = proto.server_streaming();
+
+  AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
+}
+
+#undef BUILD_ARRAY
+
+// -------------------------------------------------------------------
+
+void DescriptorBuilder::CrossLinkFile(FileDescriptor* file,
+                                      const FileDescriptorProto& proto) {
+  if (file->options_ == nullptr) {
+    file->options_ = &FileOptions::default_instance();
+  }
+
+  for (int i = 0; i < file->message_type_count(); i++) {
+    CrossLinkMessage(&file->message_types_[i], proto.message_type(i));
+  }
+
+  for (int i = 0; i < file->extension_count(); i++) {
+    CrossLinkField(&file->extensions_[i], proto.extension(i));
+  }
+
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    CrossLinkEnum(&file->enum_types_[i], proto.enum_type(i));
+  }
+
+  for (int i = 0; i < file->service_count(); i++) {
+    CrossLinkService(&file->services_[i], proto.service(i));
+  }
+}
+
+void DescriptorBuilder::CrossLinkMessage(Descriptor* message,
+                                         const DescriptorProto& proto) {
+  if (message->options_ == nullptr) {
+    message->options_ = &MessageOptions::default_instance();
+  }
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    CrossLinkMessage(&message->nested_types_[i], proto.nested_type(i));
+  }
+
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    CrossLinkEnum(&message->enum_types_[i], proto.enum_type(i));
+  }
+
+  for (int i = 0; i < message->field_count(); i++) {
+    CrossLinkField(&message->fields_[i], proto.field(i));
+  }
+
+  for (int i = 0; i < message->extension_count(); i++) {
+    CrossLinkField(&message->extensions_[i], proto.extension(i));
+  }
+
+  for (int i = 0; i < message->extension_range_count(); i++) {
+    CrossLinkExtensionRange(&message->extension_ranges_[i],
+                            proto.extension_range(i));
+  }
+
+  // Set up field array for each oneof.
+
+  // First count the number of fields per oneof.
+  for (int i = 0; i < message->field_count(); i++) {
+    const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
+    if (oneof_decl != nullptr) {
+      // Make sure fields belonging to the same oneof are defined consecutively.
+      // This enables optimizations in codegens and reflection libraries to
+      // skip fields in the oneof group, as only one of the field can be set.
+      // Note that field_count() returns how many fields in this oneof we have
+      // seen so far. field_count() > 0 guarantees that i > 0, so field(i-1) is
+      // safe.
+      if (oneof_decl->field_count() > 0 &&
+          message->field(i - 1)->containing_oneof() != oneof_decl) {
+        AddError(message->full_name() + "." + message->field(i - 1)->name(),
+                 proto.field(i - 1), DescriptorPool::ErrorCollector::TYPE,
+                 strings::Substitute(
+                     "Fields in the same oneof must be defined consecutively. "
+                     "\"$0\" cannot be defined before the completion of the "
+                     "\"$1\" oneof definition.",
+                     message->field(i - 1)->name(), oneof_decl->name()));
+      }
+      // Must go through oneof_decls_ array to get a non-const version of the
+      // OneofDescriptor.
+      auto& out_oneof_decl = message->oneof_decls_[oneof_decl->index()];
+      if (out_oneof_decl.field_count_ == 0) {
+        out_oneof_decl.fields_ = message->field(i);
+      }
+
+      if (!had_errors_) {
+        // Verify that they are contiguous.
+        // This is assumed by OneofDescriptor::field(i).
+        // But only if there are no errors.
+        GOOGLE_CHECK_EQ(out_oneof_decl.fields_ + out_oneof_decl.field_count_,
+                 message->field(i));
+      }
+      ++out_oneof_decl.field_count_;
+    }
+  }
+
+  // Then verify the sizes.
+  for (int i = 0; i < message->oneof_decl_count(); i++) {
+    OneofDescriptor* oneof_decl = &message->oneof_decls_[i];
+
+    if (oneof_decl->field_count() == 0) {
+      AddError(message->full_name() + "." + oneof_decl->name(),
+               proto.oneof_decl(i), DescriptorPool::ErrorCollector::NAME,
+               "Oneof must have at least one field.");
+    }
+
+    if (oneof_decl->options_ == nullptr) {
+      oneof_decl->options_ = &OneofOptions::default_instance();
+    }
+  }
+
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    if (field->proto3_optional_) {
+      if (!field->containing_oneof() ||
+          !field->containing_oneof()->is_synthetic()) {
+        AddError(message->full_name(), proto.field(i),
+                 DescriptorPool::ErrorCollector::OTHER,
+                 "Fields with proto3_optional set must be "
+                 "a member of a one-field oneof");
+      }
+    }
+  }
+
+  // Synthetic oneofs must be last.
+  int first_synthetic = -1;
+  for (int i = 0; i < message->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    if (oneof->is_synthetic()) {
+      if (first_synthetic == -1) {
+        first_synthetic = i;
+      }
+    } else {
+      if (first_synthetic != -1) {
+        AddError(message->full_name(), proto.oneof_decl(i),
+                 DescriptorPool::ErrorCollector::OTHER,
+                 "Synthetic oneofs must be after all other oneofs");
+      }
+    }
+  }
+
+  if (first_synthetic == -1) {
+    message->real_oneof_decl_count_ = message->oneof_decl_count_;
+  } else {
+    message->real_oneof_decl_count_ = first_synthetic;
+  }
+}
+
+void DescriptorBuilder::CrossLinkExtensionRange(
+    Descriptor::ExtensionRange* range,
+    const DescriptorProto::ExtensionRange& /*proto*/) {
+  if (range->options_ == nullptr) {
+    range->options_ = &ExtensionRangeOptions::default_instance();
+  }
+}
+
+void DescriptorBuilder::CrossLinkField(FieldDescriptor* field,
+                                       const FieldDescriptorProto& proto) {
+  if (field->options_ == nullptr) {
+    field->options_ = &FieldOptions::default_instance();
+  }
+
+  if (proto.has_extendee()) {
+    Symbol extendee =
+        LookupSymbol(proto.extendee(), field->full_name(),
+                     DescriptorPool::PLACEHOLDER_EXTENDABLE_MESSAGE);
+    if (extendee.IsNull()) {
+      AddNotDefinedError(field->full_name(), proto,
+                         DescriptorPool::ErrorCollector::EXTENDEE,
+                         proto.extendee());
+      return;
+    } else if (extendee.type() != Symbol::MESSAGE) {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::EXTENDEE,
+               "\"" + proto.extendee() + "\" is not a message type.");
+      return;
+    }
+    field->containing_type_ = extendee.descriptor();
+
+    const Descriptor::ExtensionRange* extension_range =
+        field->containing_type()->FindExtensionRangeContainingNumber(
+            field->number());
+
+    if (extension_range == nullptr) {
+      // Set of valid extension numbers for MessageSet is different (< 2^32)
+      // from other extendees (< 2^29). If unknown deps are allowed, we may not
+      // have that information, and wrongly deem the extension as invalid.
+      auto skip_check = get_allow_unknown(pool_) &&
+                        proto.extendee() == "google.protobuf.bridge.MessageSet";
+      if (!skip_check) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("\"$0\" does not declare $1 as an "
+                                  "extension number.",
+                                  field->containing_type()->full_name(),
+                                  field->number()));
+      }
+    }
+  }
+
+  if (field->containing_oneof() != nullptr) {
+    if (field->label() != FieldDescriptor::LABEL_OPTIONAL) {
+      // Note that this error will never happen when parsing .proto files.
+      // It can only happen if you manually construct a FileDescriptorProto
+      // that is incorrect.
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+               "Fields of oneofs must themselves have label LABEL_OPTIONAL.");
+    }
+  }
+
+  if (proto.has_type_name()) {
+    // Assume we are expecting a message type unless the proto contains some
+    // evidence that it expects an enum type.  This only makes a difference if
+    // we end up creating a placeholder.
+    bool expecting_enum = (proto.type() == FieldDescriptorProto::TYPE_ENUM) ||
+                          proto.has_default_value();
+
+    // In case of weak fields we force building the dependency. We need to know
+    // if the type exist or not. If it doesn't exist we substitute Empty which
+    // should only be done if the type can't be found in the generated pool.
+    // TODO(gerbens) Ideally we should query the database directly to check
+    // if weak fields exist or not so that we don't need to force building
+    // weak dependencies. However the name lookup rules for symbols are
+    // somewhat complicated, so I defer it too another CL.
+    bool is_weak = !pool_->enforce_weak_ && proto.options().weak();
+    bool is_lazy = pool_->lazily_build_dependencies_ && !is_weak;
+
+    Symbol type =
+        LookupSymbol(proto.type_name(), field->full_name(),
+                     expecting_enum ? DescriptorPool::PLACEHOLDER_ENUM
+                                    : DescriptorPool::PLACEHOLDER_MESSAGE,
+                     LOOKUP_TYPES, !is_lazy);
+
+    if (type.IsNull()) {
+      if (is_lazy) {
+        // Save the symbol names for later for lookup, and allocate the once
+        // object needed for the accessors.
+        const std::string& name = proto.type_name();
+
+        int name_sizes = static_cast<int>(name.size() + 1 +
+                                          proto.default_value().size() + 1);
+
+        field->type_once_ = ::new (tables_->AllocateBytes(static_cast<int>(
+            sizeof(internal::once_flag) + name_sizes))) internal::once_flag{};
+        char* names = reinterpret_cast<char*>(field->type_once_ + 1);
+
+        memcpy(names, name.c_str(), name.size() + 1);
+        memcpy(names + name.size() + 1, proto.default_value().c_str(),
+               proto.default_value().size() + 1);
+
+        // AddFieldByNumber and AddExtension are done later in this function,
+        // and can/must be done if the field type was not found. The related
+        // error checking is not necessary when in lazily_build_dependencies_
+        // mode, and can't be done without building the type's descriptor,
+        // which we don't want to do.
+        file_tables_->AddFieldByNumber(field);
+        if (field->is_extension()) {
+          tables_->AddExtension(field);
+        }
+        return;
+      } else {
+        // If the type is a weak type, we change the type to a google.protobuf.Empty
+        // field.
+        if (is_weak) {
+          type = FindSymbol(kNonLinkedWeakMessageReplacementName);
+        }
+        if (type.IsNull()) {
+          AddNotDefinedError(field->full_name(), proto,
+                             DescriptorPool::ErrorCollector::TYPE,
+                             proto.type_name());
+          return;
+        }
+      }
+    }
+
+    if (!proto.has_type()) {
+      // Choose field type based on symbol.
+      if (type.type() == Symbol::MESSAGE) {
+        field->type_ = FieldDescriptor::TYPE_MESSAGE;
+      } else if (type.type() == Symbol::ENUM) {
+        field->type_ = FieldDescriptor::TYPE_ENUM;
+      } else {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "\"" + proto.type_name() + "\" is not a type.");
+        return;
+      }
+    }
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      field->type_descriptor_.message_type = type.descriptor();
+      if (field->type_descriptor_.message_type == nullptr) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "\"" + proto.type_name() + "\" is not a message type.");
+        return;
+      }
+
+      if (field->has_default_value()) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                 "Messages can't have default values.");
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      field->type_descriptor_.enum_type = type.enum_descriptor();
+      if (field->type_descriptor_.enum_type == nullptr) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "\"" + proto.type_name() + "\" is not an enum type.");
+        return;
+      }
+
+      if (field->enum_type()->is_placeholder_) {
+        // We can't look up default values for placeholder types.  We'll have
+        // to just drop them.
+        field->has_default_value_ = false;
+      }
+
+      if (field->has_default_value()) {
+        // Ensure that the default value is an identifier. Parser cannot always
+        // verify this because it does not have complete type information.
+        // N.B. that this check yields better error messages but is not
+        // necessary for correctness (an enum symbol must be a valid identifier
+        // anyway), only for better errors.
+        if (!io::Tokenizer::IsIdentifier(proto.default_value())) {
+          AddError(field->full_name(), proto,
+                   DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                   "Default value for an enum field must be an identifier.");
+        } else {
+          // We can't just use field->enum_type()->FindValueByName() here
+          // because that locks the pool's mutex, which we have already locked
+          // at this point.
+          const EnumValueDescriptor* default_value =
+              LookupSymbolNoPlaceholder(proto.default_value(),
+                                        field->enum_type()->full_name())
+                  .enum_value_descriptor();
+
+          if (default_value != nullptr &&
+              default_value->type() == field->enum_type()) {
+            field->default_value_enum_ = default_value;
+          } else {
+            AddError(field->full_name(), proto,
+                     DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+                     "Enum type \"" + field->enum_type()->full_name() +
+                         "\" has no value named \"" + proto.default_value() +
+                         "\".");
+          }
+        }
+      } else if (field->enum_type()->value_count() > 0) {
+        // All enums must have at least one value, or we would have reported
+        // an error elsewhere.  We use the first defined value as the default
+        // if a default is not explicitly defined.
+        field->default_value_enum_ = field->enum_type()->value(0);
+      }
+    } else {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Field with primitive type has type_name.");
+    }
+  } else {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+        field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Field with message or enum type missing type_name.");
+    }
+  }
+
+  // Add the field to the fields-by-number table.
+  // Note:  We have to do this *after* cross-linking because extensions do not
+  // know their containing type until now. If we're in
+  // lazily_build_dependencies_ mode, we're guaranteed there's no errors, so no
+  // risk to calling containing_type() or other accessors that will build
+  // dependencies.
+  if (!file_tables_->AddFieldByNumber(field)) {
+    const FieldDescriptor* conflicting_field = file_tables_->FindFieldByNumber(
+        field->containing_type(), field->number());
+    std::string containing_type_name =
+        field->containing_type() == nullptr
+            ? "unknown"
+            : field->containing_type()->full_name();
+    if (field->is_extension()) {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::NUMBER,
+               strings::Substitute("Extension number $0 has already been used "
+                                "in \"$1\" by extension \"$2\".",
+                                field->number(), containing_type_name,
+                                conflicting_field->full_name()));
+    } else {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::NUMBER,
+               strings::Substitute("Field number $0 has already been used in "
+                                "\"$1\" by field \"$2\".",
+                                field->number(), containing_type_name,
+                                conflicting_field->name()));
+    }
+  } else {
+    if (field->is_extension()) {
+      if (!tables_->AddExtension(field)) {
+        const FieldDescriptor* conflicting_field =
+            tables_->FindExtension(field->containing_type(), field->number());
+        std::string containing_type_name =
+            field->containing_type() == nullptr
+                ? "unknown"
+                : field->containing_type()->full_name();
+        std::string error_msg = strings::Substitute(
+            "Extension number $0 has already been used in \"$1\" by extension "
+            "\"$2\" defined in $3.",
+            field->number(), containing_type_name,
+            conflicting_field->full_name(), conflicting_field->file()->name());
+        // Conflicting extension numbers should be an error. However, before
+        // turning this into an error we need to fix all existing broken
+        // protos first.
+        // TODO(xiaofeng): Change this to an error.
+        AddWarning(field->full_name(), proto,
+                   DescriptorPool::ErrorCollector::NUMBER, error_msg);
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::CrossLinkEnum(EnumDescriptor* enum_type,
+                                      const EnumDescriptorProto& proto) {
+  if (enum_type->options_ == nullptr) {
+    enum_type->options_ = &EnumOptions::default_instance();
+  }
+
+  for (int i = 0; i < enum_type->value_count(); i++) {
+    CrossLinkEnumValue(&enum_type->values_[i], proto.value(i));
+  }
+}
+
+void DescriptorBuilder::CrossLinkEnumValue(
+    EnumValueDescriptor* enum_value,
+    const EnumValueDescriptorProto& /* proto */) {
+  if (enum_value->options_ == nullptr) {
+    enum_value->options_ = &EnumValueOptions::default_instance();
+  }
+}
+
+void DescriptorBuilder::CrossLinkService(ServiceDescriptor* service,
+                                         const ServiceDescriptorProto& proto) {
+  if (service->options_ == nullptr) {
+    service->options_ = &ServiceOptions::default_instance();
+  }
+
+  for (int i = 0; i < service->method_count(); i++) {
+    CrossLinkMethod(&service->methods_[i], proto.method(i));
+  }
+}
+
+void DescriptorBuilder::CrossLinkMethod(MethodDescriptor* method,
+                                        const MethodDescriptorProto& proto) {
+  if (method->options_ == nullptr) {
+    method->options_ = &MethodOptions::default_instance();
+  }
+
+  Symbol input_type =
+      LookupSymbol(proto.input_type(), method->full_name(),
+                   DescriptorPool::PLACEHOLDER_MESSAGE, LOOKUP_ALL,
+                   !pool_->lazily_build_dependencies_);
+  if (input_type.IsNull()) {
+    if (!pool_->lazily_build_dependencies_) {
+      AddNotDefinedError(method->full_name(), proto,
+                         DescriptorPool::ErrorCollector::INPUT_TYPE,
+                         proto.input_type());
+    } else {
+      method->input_type_.SetLazy(proto.input_type(), file_);
+    }
+  } else if (input_type.type() != Symbol::MESSAGE) {
+    AddError(method->full_name(), proto,
+             DescriptorPool::ErrorCollector::INPUT_TYPE,
+             "\"" + proto.input_type() + "\" is not a message type.");
+  } else {
+    method->input_type_.Set(input_type.descriptor());
+  }
+
+  Symbol output_type =
+      LookupSymbol(proto.output_type(), method->full_name(),
+                   DescriptorPool::PLACEHOLDER_MESSAGE, LOOKUP_ALL,
+                   !pool_->lazily_build_dependencies_);
+  if (output_type.IsNull()) {
+    if (!pool_->lazily_build_dependencies_) {
+      AddNotDefinedError(method->full_name(), proto,
+                         DescriptorPool::ErrorCollector::OUTPUT_TYPE,
+                         proto.output_type());
+    } else {
+      method->output_type_.SetLazy(proto.output_type(), file_);
+    }
+  } else if (output_type.type() != Symbol::MESSAGE) {
+    AddError(method->full_name(), proto,
+             DescriptorPool::ErrorCollector::OUTPUT_TYPE,
+             "\"" + proto.output_type() + "\" is not a message type.");
+  } else {
+    method->output_type_.Set(output_type.descriptor());
+  }
+}
+
+void DescriptorBuilder::SuggestFieldNumbers(FileDescriptor* file,
+                                            const FileDescriptorProto& proto) {
+  for (int message_index = 0; message_index < file->message_type_count();
+       message_index++) {
+    const Descriptor* message = &file->message_types_[message_index];
+    auto* hints = FindOrNull(message_hints_, message);
+    if (!hints) continue;
+    constexpr int kMaxSuggestions = 3;
+    int fields_to_suggest = std::min(kMaxSuggestions, hints->fields_to_suggest);
+    if (fields_to_suggest <= 0) continue;
+    struct Range {
+      int from;
+      int to;
+    };
+    std::vector<Range> used_ordinals;
+    auto add_ordinal = [&](int ordinal) {
+      if (ordinal <= 0 || ordinal > FieldDescriptor::kMaxNumber) return;
+      if (!used_ordinals.empty() &&
+          ordinal == used_ordinals.back().to) {
+        used_ordinals.back().to = ordinal + 1;
+      } else {
+        used_ordinals.push_back({ordinal, ordinal + 1});
+      }
+    };
+    auto add_range = [&](int from, int to) {
+      from = std::max(0, std::min(FieldDescriptor::kMaxNumber + 1, from));
+      to = std::max(0, std::min(FieldDescriptor::kMaxNumber + 1, to));
+      if (from >= to) return;
+      used_ordinals.push_back({from, to});
+    };
+    for (int i = 0; i < message->field_count(); i++) {
+      add_ordinal(message->field(i)->number());
+    }
+    for (int i = 0; i < message->extension_count(); i++) {
+      add_ordinal(message->extension(i)->number());
+    }
+    for (int i = 0; i < message->reserved_range_count(); i++) {
+      auto range = message->reserved_range(i);
+      add_range(range->start, range->end);
+    }
+    for (int i = 0; i < message->extension_range_count(); i++) {
+      auto range = message->extension_range(i);
+      add_range(range->start, range->end);
+    }
+    used_ordinals.push_back(
+        {FieldDescriptor::kMaxNumber, FieldDescriptor::kMaxNumber + 1});
+    used_ordinals.push_back({FieldDescriptor::kFirstReservedNumber,
+                             FieldDescriptor::kLastReservedNumber});
+    std::sort(used_ordinals.begin(), used_ordinals.end(),
+              [](Range lhs, Range rhs) {
+                return std::tie(lhs.from, lhs.to) < std::tie(rhs.from, rhs.to);
+              });
+    int current_ordinal = 1;
+    std::stringstream id_list;
+    id_list << "Suggested field numbers for " << message->full_name() << ": ";
+    const char* separator = "";
+    for (auto& current_range : used_ordinals) {
+      while (current_ordinal < current_range.from && fields_to_suggest > 0) {
+        id_list << separator << current_ordinal++;
+        separator = ", ";
+        fields_to_suggest--;
+      }
+      if (fields_to_suggest == 0) break;
+      current_ordinal = std::max(current_ordinal, current_range.to);
+    }
+    if (hints->first_reason) {
+      AddError(message->full_name(), *hints->first_reason,
+               hints->first_reason_location, id_list.str());
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+
+#define VALIDATE_OPTIONS_FROM_ARRAY(descriptor, array_name, type) \
+  for (int i = 0; i < descriptor->array_name##_count(); ++i) {    \
+    Validate##type##Options(descriptor->array_name##s_ + i,       \
+                            proto.array_name(i));                 \
+  }
+
+// Determine if the file uses optimize_for = LITE_RUNTIME, being careful to
+// avoid problems that exist at init time.
+static bool IsLite(const FileDescriptor* file) {
+  // TODO(kenton):  I don't even remember how many of these conditions are
+  //   actually possible.  I'm just being super-safe.
+  return file != nullptr &&
+         &file->options() != &FileOptions::default_instance() &&
+         file->options().optimize_for() == FileOptions::LITE_RUNTIME;
+}
+
+void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file,
+                                            const FileDescriptorProto& proto) {
+  VALIDATE_OPTIONS_FROM_ARRAY(file, message_type, Message);
+  VALIDATE_OPTIONS_FROM_ARRAY(file, enum_type, Enum);
+  VALIDATE_OPTIONS_FROM_ARRAY(file, service, Service);
+  VALIDATE_OPTIONS_FROM_ARRAY(file, extension, Field);
+
+  // Lite files can only be imported by other Lite files.
+  if (!IsLite(file)) {
+    for (int i = 0; i < file->dependency_count(); i++) {
+      if (IsLite(file->dependency(i))) {
+        AddError(
+            file->dependency(i)->name(), proto,
+            DescriptorPool::ErrorCollector::IMPORT,
+            "Files that do not use optimize_for = LITE_RUNTIME cannot import "
+            "files which do use this option.  This file is not lite, but it "
+            "imports \"" +
+                file->dependency(i)->name() + "\" which is.");
+        break;
+      }
+    }
+  }
+  if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    ValidateProto3(file, proto);
+  }
+}
+
+void DescriptorBuilder::ValidateProto3(FileDescriptor* file,
+                                       const FileDescriptorProto& proto) {
+  for (int i = 0; i < file->extension_count(); ++i) {
+    ValidateProto3Field(file->extensions_ + i, proto.extension(i));
+  }
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    ValidateProto3Message(file->message_types_ + i, proto.message_type(i));
+  }
+  for (int i = 0; i < file->enum_type_count(); ++i) {
+    ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i));
+  }
+}
+
+static std::string ToLowercaseWithoutUnderscores(const std::string& name) {
+  std::string result;
+  for (char character : name) {
+    if (character != '_') {
+      if (character >= 'A' && character <= 'Z') {
+        result.push_back(character - 'A' + 'a');
+      } else {
+        result.push_back(character);
+      }
+    }
+  }
+  return result;
+}
+
+void DescriptorBuilder::ValidateProto3Message(Descriptor* message,
+                                              const DescriptorProto& proto) {
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    ValidateProto3Message(message->nested_types_ + i, proto.nested_type(i));
+  }
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    ValidateProto3Enum(message->enum_types_ + i, proto.enum_type(i));
+  }
+  for (int i = 0; i < message->field_count(); ++i) {
+    ValidateProto3Field(message->fields_ + i, proto.field(i));
+  }
+  for (int i = 0; i < message->extension_count(); ++i) {
+    ValidateProto3Field(message->extensions_ + i, proto.extension(i));
+  }
+  if (message->extension_range_count() > 0) {
+    AddError(message->full_name(), proto.extension_range(0),
+             DescriptorPool::ErrorCollector::NUMBER,
+             "Extension ranges are not allowed in proto3.");
+  }
+  if (message->options().message_set_wire_format()) {
+    // Using MessageSet doesn't make sense since we disallow extensions.
+    AddError(message->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "MessageSet is not supported in proto3.");
+  }
+
+  // In proto3, we reject field names if they conflict in camelCase.
+  // Note that we currently enforce a stricter rule: Field names must be
+  // unique after being converted to lowercase with underscores removed.
+  std::map<std::string, const FieldDescriptor*> name_to_field;
+  for (int i = 0; i < message->field_count(); ++i) {
+    std::string lowercase_name =
+        ToLowercaseWithoutUnderscores(message->field(i)->name());
+    if (name_to_field.find(lowercase_name) != name_to_field.end()) {
+      AddError(message->full_name(), proto.field(i),
+               DescriptorPool::ErrorCollector::NAME,
+               "The JSON camel-case name of field \"" +
+                   message->field(i)->name() + "\" conflicts with field \"" +
+                   name_to_field[lowercase_name]->name() + "\". This is not " +
+                   "allowed in proto3.");
+    } else {
+      name_to_field[lowercase_name] = message->field(i);
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateProto3Field(FieldDescriptor* field,
+                                            const FieldDescriptorProto& proto) {
+  if (field->is_extension() &&
+      !AllowedExtendeeInProto3(field->containing_type()->full_name())) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::EXTENDEE,
+             "Extensions in proto3 are only allowed for defining options.");
+  }
+  if (field->is_required()) {
+    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "Required fields are not allowed in proto3.");
+  }
+  if (field->has_default_value()) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::DEFAULT_VALUE,
+             "Explicit default values are not allowed in proto3.");
+  }
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+      field->enum_type() &&
+      field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
+      field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_UNKNOWN) {
+    // Proto3 messages can only use Proto3 enum types; otherwise we can't
+    // guarantee that the default value is zero.
+    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "Enum type \"" + field->enum_type()->full_name() +
+                 "\" is not a proto3 enum, but is used in \"" +
+                 field->containing_type()->full_name() +
+                 "\" which is a proto3 message type.");
+  }
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+             "Groups are not supported in proto3 syntax.");
+  }
+}
+
+void DescriptorBuilder::ValidateProto3Enum(EnumDescriptor* enm,
+                                           const EnumDescriptorProto& proto) {
+  if (enm->value_count() > 0 && enm->value(0)->number() != 0) {
+    AddError(enm->full_name(), proto.value(0),
+             DescriptorPool::ErrorCollector::NUMBER,
+             "The first enum value must be zero in proto3.");
+  }
+}
+
+void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
+                                               const DescriptorProto& proto) {
+  VALIDATE_OPTIONS_FROM_ARRAY(message, field, Field);
+  VALIDATE_OPTIONS_FROM_ARRAY(message, nested_type, Message);
+  VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum);
+  VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field);
+
+  const int64_t max_extension_range =
+      static_cast<int64_t>(message->options().message_set_wire_format()
+                               ? std::numeric_limits<int32_t>::max()
+                               : FieldDescriptor::kMaxNumber);
+  for (int i = 0; i < message->extension_range_count(); ++i) {
+    if (message->extension_range(i)->end > max_extension_range + 1) {
+      AddError(message->full_name(), proto.extension_range(i),
+               DescriptorPool::ErrorCollector::NUMBER,
+               strings::Substitute("Extension numbers cannot be greater than $0.",
+                                max_extension_range));
+    }
+
+    ValidateExtensionRangeOptions(message->full_name(),
+                                  message->extension_ranges_ + i,
+                                  proto.extension_range(i));
+  }
+}
+
+
+void DescriptorBuilder::ValidateFieldOptions(
+    FieldDescriptor* field, const FieldDescriptorProto& proto) {
+  if (pool_->lazily_build_dependencies_ && (!field || !field->message_type())) {
+    return;
+  }
+  // Only message type fields may be lazy.
+  if (field->options().lazy() || field->options().unverified_lazy()) {
+    if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "[lazy = true] can only be specified for submessage fields.");
+    }
+  }
+
+  // Only repeated primitive fields may be packed.
+  if (field->options().packed() && !field->is_packable()) {
+    AddError(
+        field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+        "[packed = true] can only be specified for repeated primitive fields.");
+  }
+
+  // Note:  Default instance may not yet be initialized here, so we have to
+  //   avoid reading from it.
+  if (field->containing_type_ != nullptr &&
+      &field->containing_type()->options() !=
+          &MessageOptions::default_instance() &&
+      field->containing_type()->options().message_set_wire_format()) {
+    if (field->is_extension()) {
+      if (!field->is_optional() ||
+          field->type() != FieldDescriptor::TYPE_MESSAGE) {
+        AddError(field->full_name(), proto,
+                 DescriptorPool::ErrorCollector::TYPE,
+                 "Extensions of MessageSets must be optional messages.");
+      }
+    } else {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+               "MessageSets cannot have fields, only extensions.");
+    }
+  }
+
+  // Lite extensions can only be of Lite types.
+  if (IsLite(field->file()) && field->containing_type_ != nullptr &&
+      !IsLite(field->containing_type()->file())) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::EXTENDEE,
+             "Extensions to non-lite types can only be declared in non-lite "
+             "files.  Note that you cannot extend a non-lite type to contain "
+             "a lite type, but the reverse is allowed.");
+  }
+
+  // Validate map types.
+  if (field->is_map()) {
+    if (!ValidateMapEntry(field, proto)) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "map_entry should not be set explicitly. Use map<KeyType, "
+               "ValueType> instead.");
+    }
+  }
+
+  ValidateJSType(field, proto);
+
+  // json_name option is not allowed on extension fields. Note that the
+  // json_name field in FieldDescriptorProto is always populated by protoc
+  // when it sends descriptor data to plugins (calculated from field name if
+  // the option is not explicitly set) so we can't rely on its presence to
+  // determine whether the json_name option is set on the field. Here we
+  // compare it against the default calculated json_name value and consider
+  // the option set if they are different. This won't catch the case when
+  // an user explicitly sets json_name to the default value, but should be
+  // good enough to catch common misuses.
+  if (field->is_extension() &&
+      (field->has_json_name() &&
+       field->json_name() != ToJsonName(field->name()))) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::OPTION_NAME,
+             "option json_name is not allowed on extension fields.");
+  }
+
+}
+
+void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
+                                            const EnumDescriptorProto& proto) {
+  VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue);
+  if (!enm->options().has_allow_alias() || !enm->options().allow_alias()) {
+    std::map<int, std::string> used_values;
+    for (int i = 0; i < enm->value_count(); ++i) {
+      const EnumValueDescriptor* enum_value = enm->value(i);
+      if (used_values.find(enum_value->number()) != used_values.end()) {
+        std::string error =
+            "\"" + enum_value->full_name() +
+            "\" uses the same enum value as \"" +
+            used_values[enum_value->number()] +
+            "\". If this is intended, set "
+            "'option allow_alias = true;' to the enum definition.";
+        if (!enm->options().allow_alias()) {
+          // Generate error if duplicated enum values are explicitly disallowed.
+          AddError(enm->full_name(), proto.value(i),
+                   DescriptorPool::ErrorCollector::NUMBER, error);
+        }
+      } else {
+        used_values[enum_value->number()] = enum_value->full_name();
+      }
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateEnumValueOptions(
+    EnumValueDescriptor* /* enum_value */,
+    const EnumValueDescriptorProto& /* proto */) {
+  // Nothing to do so far.
+}
+
+void DescriptorBuilder::ValidateExtensionRangeOptions(
+    const std::string& full_name, Descriptor::ExtensionRange* extension_range,
+    const DescriptorProto_ExtensionRange& proto) {
+  (void)full_name;        // Parameter is used by Google-internal code.
+  (void)extension_range;  // Parameter is used by Google-internal code.
+}
+
+void DescriptorBuilder::ValidateServiceOptions(
+    ServiceDescriptor* service, const ServiceDescriptorProto& proto) {
+  if (IsLite(service->file()) &&
+      (service->file()->options().cc_generic_services() ||
+       service->file()->options().java_generic_services())) {
+    AddError(service->full_name(), proto, DescriptorPool::ErrorCollector::NAME,
+             "Files with optimize_for = LITE_RUNTIME cannot define services "
+             "unless you set both options cc_generic_services and "
+             "java_generic_services to false.");
+  }
+
+  VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method);
+}
+
+void DescriptorBuilder::ValidateMethodOptions(
+    MethodDescriptor* /* method */, const MethodDescriptorProto& /* proto */) {
+  // Nothing to do so far.
+}
+
+bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field,
+                                         const FieldDescriptorProto& proto) {
+  const Descriptor* message = field->message_type();
+  if (  // Must not contain extensions, extension range or nested message or
+        // enums
+      message->extension_count() != 0 ||
+      field->label() != FieldDescriptor::LABEL_REPEATED ||
+      message->extension_range_count() != 0 ||
+      message->nested_type_count() != 0 || message->enum_type_count() != 0 ||
+      // Must contain exactly two fields
+      message->field_count() != 2 ||
+      // Field name and message name must match
+      message->name() != ToCamelCase(field->name(), false) + "Entry" ||
+      // Entry message must be in the same containing type of the field.
+      field->containing_type() != message->containing_type()) {
+    return false;
+  }
+
+  const FieldDescriptor* key = message->map_key();
+  const FieldDescriptor* value = message->map_value();
+  if (key->label() != FieldDescriptor::LABEL_OPTIONAL || key->number() != 1 ||
+      key->name() != "key") {
+    return false;
+  }
+  if (value->label() != FieldDescriptor::LABEL_OPTIONAL ||
+      value->number() != 2 || value->name() != "value") {
+    return false;
+  }
+
+  // Check key types are legal.
+  switch (key->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Key in map fields cannot be enum types.");
+      break;
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_BYTES:
+      AddError(
+          field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+          "Key in map fields cannot be float/double, bytes or message types.");
+      break;
+    case FieldDescriptor::TYPE_BOOL:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_SFIXED64:
+      // Legal cases
+      break;
+      // Do not add a default, so that the compiler will complain when new types
+      // are added.
+  }
+
+  if (value->type() == FieldDescriptor::TYPE_ENUM) {
+    if (value->enum_type()->value(0)->number() != 0) {
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Enum value in map must define 0 as the first value.");
+    }
+  }
+
+  return true;
+}
+
+void DescriptorBuilder::DetectMapConflicts(const Descriptor* message,
+                                           const DescriptorProto& proto) {
+  std::map<std::string, const Descriptor*> seen_types;
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    const Descriptor* nested = message->nested_type(i);
+    std::pair<std::map<std::string, const Descriptor*>::iterator, bool> result =
+        seen_types.insert(std::make_pair(nested->name(), nested));
+    if (!result.second) {
+      if (result.first->second->options().map_entry() ||
+          nested->options().map_entry()) {
+        AddError(message->full_name(), proto,
+                 DescriptorPool::ErrorCollector::NAME,
+                 "Expanded map entry type " + nested->name() +
+                     " conflicts with an existing nested message type.");
+        break;
+      }
+    }
+    // Recursively test on the nested types.
+    DetectMapConflicts(message->nested_type(i), proto.nested_type(i));
+  }
+  // Check for conflicted field names.
+  for (int i = 0; i < message->field_count(); ++i) {
+    const FieldDescriptor* field = message->field(i);
+    std::map<std::string, const Descriptor*>::iterator iter =
+        seen_types.find(field->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+                   " conflicts with an existing field.");
+    }
+  }
+  // Check for conflicted enum names.
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    const EnumDescriptor* enum_desc = message->enum_type(i);
+    std::map<std::string, const Descriptor*>::iterator iter =
+        seen_types.find(enum_desc->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+                   " conflicts with an existing enum type.");
+    }
+  }
+  // Check for conflicted oneof names.
+  for (int i = 0; i < message->oneof_decl_count(); ++i) {
+    const OneofDescriptor* oneof_desc = message->oneof_decl(i);
+    std::map<std::string, const Descriptor*>::iterator iter =
+        seen_types.find(oneof_desc->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+                   " conflicts with an existing oneof type.");
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateJSType(FieldDescriptor* field,
+                                       const FieldDescriptorProto& proto) {
+  FieldOptions::JSType jstype = field->options().jstype();
+  // The default is always acceptable.
+  if (jstype == FieldOptions::JS_NORMAL) {
+    return;
+  }
+
+  switch (field->type()) {
+    // Integral 64-bit types may be represented as JavaScript numbers or
+    // strings.
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+      if (jstype == FieldOptions::JS_STRING ||
+          jstype == FieldOptions::JS_NUMBER) {
+        return;
+      }
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "Illegal jstype for int64, uint64, sint64, fixed64 "
+               "or sfixed64 field: " +
+                   FieldOptions_JSType_descriptor()->value(jstype)->name());
+      break;
+
+    // No other types permit a jstype option.
+    default:
+      AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+               "jstype is only allowed on int64, uint64, sint64, fixed64 "
+               "or sfixed64 fields.");
+      break;
+  }
+}
+
+#undef VALIDATE_OPTIONS_FROM_ARRAY
+
+// -------------------------------------------------------------------
+
+DescriptorBuilder::OptionInterpreter::OptionInterpreter(
+    DescriptorBuilder* builder)
+    : builder_(builder) {
+  GOOGLE_CHECK(builder_);
+}
+
+DescriptorBuilder::OptionInterpreter::~OptionInterpreter() {}
+
+bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
+    OptionsToInterpret* options_to_interpret) {
+  // Note that these may be in different pools, so we can't use the same
+  // descriptor and reflection objects on both.
+  Message* options = options_to_interpret->options;
+  const Message* original_options = options_to_interpret->original_options;
+
+  bool failed = false;
+  options_to_interpret_ = options_to_interpret;
+
+  // Find the uninterpreted_option field in the mutable copy of the options
+  // and clear them, since we're about to interpret them.
+  const FieldDescriptor* uninterpreted_options_field =
+      options->GetDescriptor()->FindFieldByName("uninterpreted_option");
+  GOOGLE_CHECK(uninterpreted_options_field != nullptr)
+      << "No field named \"uninterpreted_option\" in the Options proto.";
+  options->GetReflection()->ClearField(options, uninterpreted_options_field);
+
+  std::vector<int> src_path = options_to_interpret->element_path;
+  src_path.push_back(uninterpreted_options_field->number());
+
+  // Find the uninterpreted_option field in the original options.
+  const FieldDescriptor* original_uninterpreted_options_field =
+      original_options->GetDescriptor()->FindFieldByName(
+          "uninterpreted_option");
+  GOOGLE_CHECK(original_uninterpreted_options_field != nullptr)
+      << "No field named \"uninterpreted_option\" in the Options proto.";
+
+  const int num_uninterpreted_options =
+      original_options->GetReflection()->FieldSize(
+          *original_options, original_uninterpreted_options_field);
+  for (int i = 0; i < num_uninterpreted_options; ++i) {
+    src_path.push_back(i);
+    uninterpreted_option_ = down_cast<const UninterpretedOption*>(
+        &original_options->GetReflection()->GetRepeatedMessage(
+            *original_options, original_uninterpreted_options_field, i));
+    if (!InterpretSingleOption(options, src_path,
+                               options_to_interpret->element_path)) {
+      // Error already added by InterpretSingleOption().
+      failed = true;
+      break;
+    }
+    src_path.pop_back();
+  }
+  // Reset these, so we don't have any dangling pointers.
+  uninterpreted_option_ = nullptr;
+  options_to_interpret_ = nullptr;
+
+  if (!failed) {
+    // InterpretSingleOption() added the interpreted options in the
+    // UnknownFieldSet, in case the option isn't yet known to us.  Now we
+    // serialize the options message and deserialize it back.  That way, any
+    // option fields that we do happen to know about will get moved from the
+    // UnknownFieldSet into the real fields, and thus be available right away.
+    // If they are not known, that's OK too. They will get reparsed into the
+    // UnknownFieldSet and wait there until the message is parsed by something
+    // that does know about the options.
+
+    // Keep the unparsed options around in case the reparsing fails.
+    std::unique_ptr<Message> unparsed_options(options->New());
+    options->GetReflection()->Swap(unparsed_options.get(), options);
+
+    std::string buf;
+    if (!unparsed_options->AppendToString(&buf) ||
+        !options->ParseFromString(buf)) {
+      builder_->AddError(
+          options_to_interpret->element_name, *original_options,
+          DescriptorPool::ErrorCollector::OTHER,
+          "Some options could not be correctly parsed using the proto "
+          "descriptors compiled into this binary.\n"
+          "Unparsed options: " +
+              unparsed_options->ShortDebugString() +
+              "\n"
+              "Parsing attempt:  " +
+              options->ShortDebugString());
+      // Restore the unparsed options.
+      options->GetReflection()->Swap(unparsed_options.get(), options);
+    }
+  }
+
+  return !failed;
+}
+
+bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
+    Message* options, const std::vector<int>& src_path,
+    const std::vector<int>& options_path) {
+  // First do some basic validation.
+  if (uninterpreted_option_->name_size() == 0) {
+    // This should never happen unless the parser has gone seriously awry or
+    // someone has manually created the uninterpreted option badly.
+    return AddNameError("Option must have a name.");
+  }
+  if (uninterpreted_option_->name(0).name_part() == "uninterpreted_option") {
+    return AddNameError(
+        "Option must not use reserved name "
+        "\"uninterpreted_option\".");
+  }
+
+  const Descriptor* options_descriptor = nullptr;
+  // Get the options message's descriptor from the builder's pool, so that we
+  // get the version that knows about any extension options declared in the file
+  // we're currently building. The descriptor should be there as long as the
+  // file we're building imported descriptor.proto.
+
+  // Note that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
+  // DescriptorPool::FindMessageTypeByName() because we're already holding the
+  // pool's mutex, and the latter method locks it again.  We don't use
+  // FindSymbol() because files that use custom options only need to depend on
+  // the file that defines the option, not descriptor.proto itself.
+  Symbol symbol = builder_->FindSymbolNotEnforcingDeps(
+      options->GetDescriptor()->full_name());
+  options_descriptor = symbol.descriptor();
+  if (options_descriptor == nullptr) {
+    // The options message's descriptor was not in the builder's pool, so use
+    // the standard version from the generated pool. We're not holding the
+    // generated pool's mutex, so we can search it the straightforward way.
+    options_descriptor = options->GetDescriptor();
+  }
+  GOOGLE_CHECK(options_descriptor);
+
+  // We iterate over the name parts to drill into the submessages until we find
+  // the leaf field for the option. As we drill down we remember the current
+  // submessage's descriptor in |descriptor| and the next field in that
+  // submessage in |field|. We also track the fields we're drilling down
+  // through in |intermediate_fields|. As we go, we reconstruct the full option
+  // name in |debug_msg_name|, for use in error messages.
+  const Descriptor* descriptor = options_descriptor;
+  const FieldDescriptor* field = nullptr;
+  std::vector<const FieldDescriptor*> intermediate_fields;
+  std::string debug_msg_name = "";
+
+  std::vector<int> dest_path = options_path;
+
+  for (int i = 0; i < uninterpreted_option_->name_size(); ++i) {
+    builder_->undefine_resolved_name_.clear();
+    const std::string& name_part = uninterpreted_option_->name(i).name_part();
+    if (debug_msg_name.size() > 0) {
+      debug_msg_name += ".";
+    }
+    if (uninterpreted_option_->name(i).is_extension()) {
+      debug_msg_name += "(" + name_part + ")";
+      // Search for the extension's descriptor as an extension in the builder's
+      // pool. Note that we use DescriptorBuilder::LookupSymbol(), not
+      // DescriptorPool::FindExtensionByName(), for two reasons: 1) It allows
+      // relative lookups, and 2) because we're already holding the pool's
+      // mutex, and the latter method locks it again.
+      symbol =
+          builder_->LookupSymbol(name_part, options_to_interpret_->name_scope);
+      field = symbol.field_descriptor();
+      // If we don't find the field then the field's descriptor was not in the
+      // builder's pool, but there's no point in looking in the generated
+      // pool. We require that you import the file that defines any extensions
+      // you use, so they must be present in the builder's pool.
+    } else {
+      debug_msg_name += name_part;
+      // Search for the field's descriptor as a regular field.
+      field = descriptor->FindFieldByName(name_part);
+    }
+
+    if (field == nullptr) {
+      if (get_allow_unknown(builder_->pool_)) {
+        // We can't find the option, but AllowUnknownDependencies() is enabled,
+        // so we will just leave it as uninterpreted.
+        AddWithoutInterpreting(*uninterpreted_option_, options);
+        return true;
+      } else if (!(builder_->undefine_resolved_name_).empty()) {
+        // Option is resolved to a name which is not defined.
+        return AddNameError(
+            "Option \"" + debug_msg_name + "\" is resolved to \"(" +
+            builder_->undefine_resolved_name_ +
+            ")\", which is not defined. The innermost scope is searched first "
+            "in name resolution. Consider using a leading '.'(i.e., \"(." +
+            debug_msg_name.substr(1) +
+            "\") to start from the outermost scope.");
+      } else {
+        return AddNameError(
+            "Option \"" + debug_msg_name +
+            "\" unknown. Ensure that your proto" +
+            " definition file imports the proto which defines the option.");
+      }
+    } else if (field->containing_type() != descriptor) {
+      if (get_is_placeholder(field->containing_type())) {
+        // The field is an extension of a placeholder type, so we can't
+        // reliably verify whether it is a valid extension to use here (e.g.
+        // we don't know if it is an extension of the correct *Options message,
+        // or if it has a valid field number, etc.).  Just leave it as
+        // uninterpreted instead.
+        AddWithoutInterpreting(*uninterpreted_option_, options);
+        return true;
+      } else {
+        // This can only happen if, due to some insane misconfiguration of the
+        // pools, we find the options message in one pool but the field in
+        // another. This would probably imply a hefty bug somewhere.
+        return AddNameError("Option field \"" + debug_msg_name +
+                            "\" is not a field or extension of message \"" +
+                            descriptor->name() + "\".");
+      }
+    } else {
+      // accumulate field numbers to form path to interpreted option
+      dest_path.push_back(field->number());
+
+      if (i < uninterpreted_option_->name_size() - 1) {
+        if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+          return AddNameError("Option \"" + debug_msg_name +
+                              "\" is an atomic type, not a message.");
+        } else if (field->is_repeated()) {
+          return AddNameError("Option field \"" + debug_msg_name +
+                              "\" is a repeated message. Repeated message "
+                              "options must be initialized using an "
+                              "aggregate value.");
+        } else {
+          // Drill down into the submessage.
+          intermediate_fields.push_back(field);
+          descriptor = field->message_type();
+        }
+      }
+    }
+  }
+
+  // We've found the leaf field. Now we use UnknownFieldSets to set its value
+  // on the options message. We do so because the message may not yet know
+  // about its extension fields, so we may not be able to set the fields
+  // directly. But the UnknownFieldSets will serialize to the same wire-format
+  // message, so reading that message back in once the extension fields are
+  // known will populate them correctly.
+
+  // First see if the option is already set.
+  if (!field->is_repeated() &&
+      !ExamineIfOptionIsSet(
+          intermediate_fields.begin(), intermediate_fields.end(), field,
+          debug_msg_name,
+          options->GetReflection()->GetUnknownFields(*options))) {
+    return false;  // ExamineIfOptionIsSet() already added the error.
+  }
+
+  // First set the value on the UnknownFieldSet corresponding to the
+  // innermost message.
+  std::unique_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
+  if (!SetOptionValue(field, unknown_fields.get())) {
+    return false;  // SetOptionValue() already added the error.
+  }
+
+  // Now wrap the UnknownFieldSet with UnknownFieldSets corresponding to all
+  // the intermediate messages.
+  for (std::vector<const FieldDescriptor*>::reverse_iterator iter =
+           intermediate_fields.rbegin();
+       iter != intermediate_fields.rend(); ++iter) {
+    std::unique_ptr<UnknownFieldSet> parent_unknown_fields(
+        new UnknownFieldSet());
+    switch ((*iter)->type()) {
+      case FieldDescriptor::TYPE_MESSAGE: {
+        std::string* outstr =
+            parent_unknown_fields->AddLengthDelimited((*iter)->number());
+        GOOGLE_CHECK(unknown_fields->SerializeToString(outstr))
+            << "Unexpected failure while serializing option submessage "
+            << debug_msg_name << "\".";
+        break;
+      }
+
+      case FieldDescriptor::TYPE_GROUP: {
+        parent_unknown_fields->AddGroup((*iter)->number())
+            ->MergeFrom(*unknown_fields);
+        break;
+      }
+
+      default:
+        GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: "
+                   << (*iter)->type();
+        return false;
+    }
+    unknown_fields.reset(parent_unknown_fields.release());
+  }
+
+  // Now merge the UnknownFieldSet corresponding to the top-level message into
+  // the options message.
+  options->GetReflection()->MutableUnknownFields(options)->MergeFrom(
+      *unknown_fields);
+
+  // record the element path of the interpreted option
+  if (field->is_repeated()) {
+    int index = repeated_option_counts_[dest_path]++;
+    dest_path.push_back(index);
+  }
+  interpreted_paths_[src_path] = dest_path;
+
+  return true;
+}
+
+void DescriptorBuilder::OptionInterpreter::UpdateSourceCodeInfo(
+    SourceCodeInfo* info) {
+  if (interpreted_paths_.empty()) {
+    // nothing to do!
+    return;
+  }
+
+  // We find locations that match keys in interpreted_paths_ and
+  // 1) replace the path with the corresponding value in interpreted_paths_
+  // 2) remove any subsequent sub-locations (sub-location is one whose path
+  //    has the parent path as a prefix)
+  //
+  // To avoid quadratic behavior of removing interior rows as we go,
+  // we keep a copy. But we don't actually copy anything until we've
+  // found the first match (so if the source code info has no locations
+  // that need to be changed, there is zero copy overhead).
+
+  RepeatedPtrField<SourceCodeInfo_Location>* locs = info->mutable_location();
+  RepeatedPtrField<SourceCodeInfo_Location> new_locs;
+  bool copying = false;
+
+  std::vector<int> pathv;
+  bool matched = false;
+
+  for (RepeatedPtrField<SourceCodeInfo_Location>::iterator loc = locs->begin();
+       loc != locs->end(); loc++) {
+    if (matched) {
+      // see if this location is in the range to remove
+      bool loc_matches = true;
+      if (loc->path_size() < static_cast<int64_t>(pathv.size())) {
+        loc_matches = false;
+      } else {
+        for (size_t j = 0; j < pathv.size(); j++) {
+          if (loc->path(j) != pathv[j]) {
+            loc_matches = false;
+            break;
+          }
+        }
+      }
+
+      if (loc_matches) {
+        // don't copy this row since it is a sub-location that we're removing
+        continue;
+      }
+
+      matched = false;
+    }
+
+    pathv.clear();
+    for (int j = 0; j < loc->path_size(); j++) {
+      pathv.push_back(loc->path(j));
+    }
+
+    std::map<std::vector<int>, std::vector<int>>::iterator entry =
+        interpreted_paths_.find(pathv);
+
+    if (entry == interpreted_paths_.end()) {
+      // not a match
+      if (copying) {
+        *new_locs.Add() = *loc;
+      }
+      continue;
+    }
+
+    matched = true;
+
+    if (!copying) {
+      // initialize the copy we are building
+      copying = true;
+      new_locs.Reserve(locs->size());
+      for (RepeatedPtrField<SourceCodeInfo_Location>::iterator it =
+               locs->begin();
+           it != loc; it++) {
+        *new_locs.Add() = *it;
+      }
+    }
+
+    // add replacement and update its path
+    SourceCodeInfo_Location* replacement = new_locs.Add();
+    *replacement = *loc;
+    replacement->clear_path();
+    for (std::vector<int>::iterator rit = entry->second.begin();
+         rit != entry->second.end(); rit++) {
+      replacement->add_path(*rit);
+    }
+  }
+
+  // if we made a changed copy, put it in place
+  if (copying) {
+    *locs = new_locs;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting(
+    const UninterpretedOption& uninterpreted_option, Message* options) {
+  const FieldDescriptor* field =
+      options->GetDescriptor()->FindFieldByName("uninterpreted_option");
+  GOOGLE_CHECK(field != nullptr);
+
+  options->GetReflection()
+      ->AddMessage(options, field)
+      ->CopyFrom(uninterpreted_option);
+}
+
+bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
+    std::vector<const FieldDescriptor*>::const_iterator
+        intermediate_fields_iter,
+    std::vector<const FieldDescriptor*>::const_iterator intermediate_fields_end,
+    const FieldDescriptor* innermost_field, const std::string& debug_msg_name,
+    const UnknownFieldSet& unknown_fields) {
+  // We do linear searches of the UnknownFieldSet and its sub-groups.  This
+  // should be fine since it's unlikely that any one options structure will
+  // contain more than a handful of options.
+
+  if (intermediate_fields_iter == intermediate_fields_end) {
+    // We're at the innermost submessage.
+    for (int i = 0; i < unknown_fields.field_count(); i++) {
+      if (unknown_fields.field(i).number() == innermost_field->number()) {
+        return AddNameError("Option \"" + debug_msg_name +
+                            "\" was already set.");
+      }
+    }
+    return true;
+  }
+
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    if (unknown_fields.field(i).number() ==
+        (*intermediate_fields_iter)->number()) {
+      const UnknownField* unknown_field = &unknown_fields.field(i);
+      FieldDescriptor::Type type = (*intermediate_fields_iter)->type();
+      // Recurse into the next submessage.
+      switch (type) {
+        case FieldDescriptor::TYPE_MESSAGE:
+          if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+            UnknownFieldSet intermediate_unknown_fields;
+            if (intermediate_unknown_fields.ParseFromString(
+                    unknown_field->length_delimited()) &&
+                !ExamineIfOptionIsSet(intermediate_fields_iter + 1,
+                                      intermediate_fields_end, innermost_field,
+                                      debug_msg_name,
+                                      intermediate_unknown_fields)) {
+              return false;  // Error already added.
+            }
+          }
+          break;
+
+        case FieldDescriptor::TYPE_GROUP:
+          if (unknown_field->type() == UnknownField::TYPE_GROUP) {
+            if (!ExamineIfOptionIsSet(intermediate_fields_iter + 1,
+                                      intermediate_fields_end, innermost_field,
+                                      debug_msg_name, unknown_field->group())) {
+              return false;  // Error already added.
+            }
+          }
+          break;
+
+        default:
+          GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type;
+          return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
+    const FieldDescriptor* option_field, UnknownFieldSet* unknown_fields) {
+  // We switch on the CppType to validate.
+  switch (option_field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        if (uninterpreted_option_->positive_int_value() >
+            static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
+          return AddValueError("Value out of range for int32 option \"" +
+                               option_field->full_name() + "\".");
+        } else {
+          SetInt32(option_field->number(),
+                   uninterpreted_option_->positive_int_value(),
+                   option_field->type(), unknown_fields);
+        }
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        if (uninterpreted_option_->negative_int_value() <
+            static_cast<int64_t>(std::numeric_limits<int32_t>::min())) {
+          return AddValueError("Value out of range for int32 option \"" +
+                               option_field->full_name() + "\".");
+        } else {
+          SetInt32(option_field->number(),
+                   uninterpreted_option_->negative_int_value(),
+                   option_field->type(), unknown_fields);
+        }
+      } else {
+        return AddValueError("Value must be integer for int32 option \"" +
+                             option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_INT64:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        if (uninterpreted_option_->positive_int_value() >
+            static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+          return AddValueError("Value out of range for int64 option \"" +
+                               option_field->full_name() + "\".");
+        } else {
+          SetInt64(option_field->number(),
+                   uninterpreted_option_->positive_int_value(),
+                   option_field->type(), unknown_fields);
+        }
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        SetInt64(option_field->number(),
+                 uninterpreted_option_->negative_int_value(),
+                 option_field->type(), unknown_fields);
+      } else {
+        return AddValueError("Value must be integer for int64 option \"" +
+                             option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_UINT32:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        if (uninterpreted_option_->positive_int_value() >
+            std::numeric_limits<uint32_t>::max()) {
+          return AddValueError("Value out of range for uint32 option \"" +
+                               option_field->name() + "\".");
+        } else {
+          SetUInt32(option_field->number(),
+                    uninterpreted_option_->positive_int_value(),
+                    option_field->type(), unknown_fields);
+        }
+      } else {
+        return AddValueError(
+            "Value must be non-negative integer for uint32 "
+            "option \"" +
+            option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_UINT64:
+      if (uninterpreted_option_->has_positive_int_value()) {
+        SetUInt64(option_field->number(),
+                  uninterpreted_option_->positive_int_value(),
+                  option_field->type(), unknown_fields);
+      } else {
+        return AddValueError(
+            "Value must be non-negative integer for uint64 "
+            "option \"" +
+            option_field->full_name() + "\".");
+      }
+      break;
+
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value;
+      if (uninterpreted_option_->has_double_value()) {
+        value = uninterpreted_option_->double_value();
+      } else if (uninterpreted_option_->has_positive_int_value()) {
+        value = uninterpreted_option_->positive_int_value();
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        value = uninterpreted_option_->negative_int_value();
+      } else {
+        return AddValueError("Value must be number for float option \"" +
+                             option_field->full_name() + "\".");
+      }
+      unknown_fields->AddFixed32(option_field->number(),
+                                 internal::WireFormatLite::EncodeFloat(value));
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value;
+      if (uninterpreted_option_->has_double_value()) {
+        value = uninterpreted_option_->double_value();
+      } else if (uninterpreted_option_->has_positive_int_value()) {
+        value = uninterpreted_option_->positive_int_value();
+      } else if (uninterpreted_option_->has_negative_int_value()) {
+        value = uninterpreted_option_->negative_int_value();
+      } else {
+        return AddValueError("Value must be number for double option \"" +
+                             option_field->full_name() + "\".");
+      }
+      unknown_fields->AddFixed64(option_field->number(),
+                                 internal::WireFormatLite::EncodeDouble(value));
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      uint64_t value;
+      if (!uninterpreted_option_->has_identifier_value()) {
+        return AddValueError(
+            "Value must be identifier for boolean option "
+            "\"" +
+            option_field->full_name() + "\".");
+      }
+      if (uninterpreted_option_->identifier_value() == "true") {
+        value = 1;
+      } else if (uninterpreted_option_->identifier_value() == "false") {
+        value = 0;
+      } else {
+        return AddValueError(
+            "Value must be \"true\" or \"false\" for boolean "
+            "option \"" +
+            option_field->full_name() + "\".");
+      }
+      unknown_fields->AddVarint(option_field->number(), value);
+      break;
+
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      if (!uninterpreted_option_->has_identifier_value()) {
+        return AddValueError(
+            "Value must be identifier for enum-valued option "
+            "\"" +
+            option_field->full_name() + "\".");
+      }
+      const EnumDescriptor* enum_type = option_field->enum_type();
+      const std::string& value_name = uninterpreted_option_->identifier_value();
+      const EnumValueDescriptor* enum_value = nullptr;
+
+      if (enum_type->file()->pool() != DescriptorPool::generated_pool()) {
+        // Note that the enum value's fully-qualified name is a sibling of the
+        // enum's name, not a child of it.
+        std::string fully_qualified_name = enum_type->full_name();
+        fully_qualified_name.resize(fully_qualified_name.size() -
+                                    enum_type->name().size());
+        fully_qualified_name += value_name;
+
+        // Search for the enum value's descriptor in the builder's pool. Note
+        // that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
+        // DescriptorPool::FindEnumValueByName() because we're already holding
+        // the pool's mutex, and the latter method locks it again.
+        Symbol symbol =
+            builder_->FindSymbolNotEnforcingDeps(fully_qualified_name);
+        if (auto* candicate_descriptor = symbol.enum_value_descriptor()) {
+          if (candicate_descriptor->type() != enum_type) {
+            return AddValueError(
+                "Enum type \"" + enum_type->full_name() +
+                "\" has no value named \"" + value_name + "\" for option \"" +
+                option_field->full_name() +
+                "\". This appears to be a value from a sibling type.");
+          } else {
+            enum_value = candicate_descriptor;
+          }
+        }
+      } else {
+        // The enum type is in the generated pool, so we can search for the
+        // value there.
+        enum_value = enum_type->FindValueByName(value_name);
+      }
+
+      if (enum_value == nullptr) {
+        return AddValueError("Enum type \"" +
+                             option_field->enum_type()->full_name() +
+                             "\" has no value named \"" + value_name +
+                             "\" for "
+                             "option \"" +
+                             option_field->full_name() + "\".");
+      } else {
+        // Sign-extension is not a problem, since we cast directly from int32_t
+        // to uint64_t, without first going through uint32_t.
+        unknown_fields->AddVarint(
+            option_field->number(),
+            static_cast<uint64_t>(static_cast<int64_t>(enum_value->number())));
+      }
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (!uninterpreted_option_->has_string_value()) {
+        return AddValueError(
+            "Value must be quoted string for string option "
+            "\"" +
+            option_field->full_name() + "\".");
+      }
+      // The string has already been unquoted and unescaped by the parser.
+      unknown_fields->AddLengthDelimited(option_field->number(),
+                                         uninterpreted_option_->string_value());
+      break;
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      if (!SetAggregateOption(option_field, unknown_fields)) {
+        return false;
+      }
+      break;
+  }
+
+  return true;
+}
+
+class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder
+    : public TextFormat::Finder {
+ public:
+  DescriptorBuilder* builder_;
+
+  const Descriptor* FindAnyType(const Message& /*message*/,
+                                const std::string& prefix,
+                                const std::string& name) const override {
+    if (prefix != internal::kTypeGoogleApisComPrefix &&
+        prefix != internal::kTypeGoogleProdComPrefix) {
+      return nullptr;
+    }
+    assert_mutex_held(builder_->pool_);
+    return builder_->FindSymbol(name).descriptor();
+  }
+
+  const FieldDescriptor* FindExtension(Message* message,
+                                       const std::string& name) const override {
+    assert_mutex_held(builder_->pool_);
+    const Descriptor* descriptor = message->GetDescriptor();
+    Symbol result =
+        builder_->LookupSymbolNoPlaceholder(name, descriptor->full_name());
+    if (auto* field = result.field_descriptor()) {
+      return field;
+    } else if (result.type() == Symbol::MESSAGE &&
+               descriptor->options().message_set_wire_format()) {
+      const Descriptor* foreign_type = result.descriptor();
+      // The text format allows MessageSet items to be specified using
+      // the type name, rather than the extension identifier. If the symbol
+      // lookup returned a Message, and the enclosing Message has
+      // message_set_wire_format = true, then return the message set
+      // extension, if one exists.
+      for (int i = 0; i < foreign_type->extension_count(); i++) {
+        const FieldDescriptor* extension = foreign_type->extension(i);
+        if (extension->containing_type() == descriptor &&
+            extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+            extension->is_optional() &&
+            extension->message_type() == foreign_type) {
+          // Found it.
+          return extension;
+        }
+      }
+    }
+    return nullptr;
+  }
+};
+
+// A custom error collector to record any text-format parsing errors
+namespace {
+class AggregateErrorCollector : public io::ErrorCollector {
+ public:
+  std::string error_;
+
+  void AddError(int /* line */, int /* column */,
+                const std::string& message) override {
+    if (!error_.empty()) {
+      error_ += "; ";
+    }
+    error_ += message;
+  }
+
+  void AddWarning(int /* line */, int /* column */,
+                  const std::string& /* message */) override {
+    // Ignore warnings
+  }
+};
+}  // namespace
+
+// We construct a dynamic message of the type corresponding to
+// option_field, parse the supplied text-format string into this
+// message, and serialize the resulting message to produce the value.
+bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
+    const FieldDescriptor* option_field, UnknownFieldSet* unknown_fields) {
+  if (!uninterpreted_option_->has_aggregate_value()) {
+    return AddValueError("Option \"" + option_field->full_name() +
+                         "\" is a message. To set the entire message, use "
+                         "syntax like \"" +
+                         option_field->name() +
+                         " = { <proto text format> }\". "
+                         "To set fields within it, use "
+                         "syntax like \"" +
+                         option_field->name() + ".foo = value\".");
+  }
+
+  const Descriptor* type = option_field->message_type();
+  std::unique_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
+  GOOGLE_CHECK(dynamic.get() != nullptr)
+      << "Could not create an instance of " << option_field->DebugString();
+
+  AggregateErrorCollector collector;
+  AggregateOptionFinder finder;
+  finder.builder_ = builder_;
+  TextFormat::Parser parser;
+  parser.RecordErrorsTo(&collector);
+  parser.SetFinder(&finder);
+  if (!parser.ParseFromString(uninterpreted_option_->aggregate_value(),
+                              dynamic.get())) {
+    AddValueError("Error while parsing option value for \"" +
+                  option_field->name() + "\": " + collector.error_);
+    return false;
+  } else {
+    std::string serial;
+    dynamic->SerializeToString(&serial);  // Never fails
+    if (option_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      unknown_fields->AddLengthDelimited(option_field->number(), serial);
+    } else {
+      GOOGLE_CHECK_EQ(option_field->type(), FieldDescriptor::TYPE_GROUP);
+      UnknownFieldSet* group = unknown_fields->AddGroup(option_field->number());
+      group->ParseFromString(serial);
+    }
+    return true;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetInt32(
+    int number, int32_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT32:
+      unknown_fields->AddVarint(
+          number, static_cast<uint64_t>(static_cast<int64_t>(value)));
+      break;
+
+    case FieldDescriptor::TYPE_SFIXED32:
+      unknown_fields->AddFixed32(number, static_cast<uint32_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_SINT32:
+      unknown_fields->AddVarint(
+          number, internal::WireFormatLite::ZigZagEncode32(value));
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT32: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetInt64(
+    int number, int64_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT64:
+      unknown_fields->AddVarint(number, static_cast<uint64_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_SFIXED64:
+      unknown_fields->AddFixed64(number, static_cast<uint64_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_SINT64:
+      unknown_fields->AddVarint(
+          number, internal::WireFormatLite::ZigZagEncode64(value));
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT64: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetUInt32(
+    int number, uint32_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_UINT32:
+      unknown_fields->AddVarint(number, static_cast<uint64_t>(value));
+      break;
+
+    case FieldDescriptor::TYPE_FIXED32:
+      unknown_fields->AddFixed32(number, static_cast<uint32_t>(value));
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT32: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::OptionInterpreter::SetUInt64(
+    int number, uint64_t value, FieldDescriptor::Type type,
+    UnknownFieldSet* unknown_fields) {
+  switch (type) {
+    case FieldDescriptor::TYPE_UINT64:
+      unknown_fields->AddVarint(number, value);
+      break;
+
+    case FieldDescriptor::TYPE_FIXED64:
+      unknown_fields->AddFixed64(number, value);
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT64: " << type;
+      break;
+  }
+}
+
+void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
+                                            const FileDescriptor* result) {
+  (void)result;  // Parameter is used by Google-internal code.
+
+  if (!unused_dependency_.empty()) {
+    auto itr = pool_->unused_import_track_files_.find(proto.name());
+    bool is_error =
+        itr != pool_->unused_import_track_files_.end() && itr->second;
+    for (std::set<const FileDescriptor*>::const_iterator it =
+             unused_dependency_.begin();
+         it != unused_dependency_.end(); ++it) {
+      std::string error_message = "Import " + (*it)->name() + " is unused.";
+      if (is_error) {
+        AddError((*it)->name(), proto, DescriptorPool::ErrorCollector::IMPORT,
+                 error_message);
+      } else {
+        AddWarning((*it)->name(), proto, DescriptorPool::ErrorCollector::IMPORT,
+                   error_message);
+      }
+    }
+  }
+}
+
+Symbol DescriptorPool::CrossLinkOnDemandHelper(StringPiece name,
+                                               bool expecting_enum) const {
+  (void)expecting_enum;  // Parameter is used by Google-internal code.
+  auto lookup_name = std::string(name);
+  if (!lookup_name.empty() && lookup_name[0] == '.') {
+    lookup_name = lookup_name.substr(1);
+  }
+  Symbol result = tables_->FindByNameHelper(this, lookup_name);
+  return result;
+}
+
+// Handle the lazy import building for a message field whose type wasn't built
+// at cross link time. If that was the case, we saved the name of the type to
+// be looked up when the accessor for the type was called. Set type_,
+// enum_type_, message_type_, and default_value_enum_ appropriately.
+void FieldDescriptor::InternalTypeOnceInit() const {
+  GOOGLE_CHECK(file()->finished_building_ == true);
+  const EnumDescriptor* enum_type = nullptr;
+  const char* lazy_type_name = reinterpret_cast<const char*>(type_once_ + 1);
+  const char* lazy_default_value_enum_name =
+      lazy_type_name + strlen(lazy_type_name) + 1;
+  Symbol result = file()->pool()->CrossLinkOnDemandHelper(
+      lazy_type_name, type_ == FieldDescriptor::TYPE_ENUM);
+  if (result.type() == Symbol::MESSAGE) {
+    type_ = FieldDescriptor::TYPE_MESSAGE;
+    type_descriptor_.message_type = result.descriptor();
+  } else if (result.type() == Symbol::ENUM) {
+    type_ = FieldDescriptor::TYPE_ENUM;
+    enum_type = type_descriptor_.enum_type = result.enum_descriptor();
+  }
+
+  if (enum_type) {
+    if (lazy_default_value_enum_name[0] != '\0') {
+      // Have to build the full name now instead of at CrossLink time,
+      // because enum_type may not be known at the time.
+      std::string name = enum_type->full_name();
+      // Enum values reside in the same scope as the enum type.
+      std::string::size_type last_dot = name.find_last_of('.');
+      if (last_dot != std::string::npos) {
+        name = name.substr(0, last_dot) + "." + lazy_default_value_enum_name;
+      } else {
+        name = lazy_default_value_enum_name;
+      }
+      Symbol result = file()->pool()->CrossLinkOnDemandHelper(name, true);
+      default_value_enum_ = result.enum_value_descriptor();
+    } else {
+      default_value_enum_ = nullptr;
+    }
+    if (!default_value_enum_) {
+      // We use the first defined value as the default
+      // if a default is not explicitly defined.
+      GOOGLE_CHECK(enum_type->value_count());
+      default_value_enum_ = enum_type->value(0);
+    }
+  }
+}
+
+void FieldDescriptor::TypeOnceInit(const FieldDescriptor* to_init) {
+  to_init->InternalTypeOnceInit();
+}
+
+// message_type(), enum_type(), default_value_enum(), and type()
+// all share the same internal::call_once init path to do lazy
+// import building and cross linking of a field of a message.
+const Descriptor* FieldDescriptor::message_type() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+  }
+  return type_ == TYPE_MESSAGE || type_ == TYPE_GROUP
+             ? type_descriptor_.message_type
+             : nullptr;
+}
+
+const EnumDescriptor* FieldDescriptor::enum_type() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+  }
+  return type_ == TYPE_ENUM ? type_descriptor_.enum_type : nullptr;
+}
+
+const EnumValueDescriptor* FieldDescriptor::default_value_enum() const {
+  if (type_once_) {
+    internal::call_once(*type_once_, FieldDescriptor::TypeOnceInit, this);
+  }
+  return default_value_enum_;
+}
+
+const std::string& FieldDescriptor::PrintableNameForExtension() const {
+  const bool is_message_set_extension =
+      is_extension() &&
+      containing_type()->options().message_set_wire_format() &&
+      type() == FieldDescriptor::TYPE_MESSAGE && is_optional() &&
+      extension_scope() == message_type();
+  return is_message_set_extension ? message_type()->full_name() : full_name();
+}
+
+void FileDescriptor::InternalDependenciesOnceInit() const {
+  GOOGLE_CHECK(finished_building_ == true);
+  const char* names_ptr = reinterpret_cast<const char*>(dependencies_once_ + 1);
+  for (int i = 0; i < dependency_count(); i++) {
+    const char* name = names_ptr;
+    names_ptr += strlen(name) + 1;
+    if (name[0] != '\0') {
+      dependencies_[i] = pool_->FindFileByName(name);
+    }
+  }
+}
+
+void FileDescriptor::DependenciesOnceInit(const FileDescriptor* to_init) {
+  to_init->InternalDependenciesOnceInit();
+}
+
+const FileDescriptor* FileDescriptor::dependency(int index) const {
+  if (dependencies_once_) {
+    // Do once init for all indices, as it's unlikely only a single index would
+    // be called, and saves on internal::call_once allocations.
+    internal::call_once(*dependencies_once_,
+                        FileDescriptor::DependenciesOnceInit, this);
+  }
+  return dependencies_[index];
+}
+
+const Descriptor* MethodDescriptor::input_type() const {
+  return input_type_.Get(service());
+}
+
+const Descriptor* MethodDescriptor::output_type() const {
+  return output_type_.Get(service());
+}
+
+namespace internal {
+void LazyDescriptor::Set(const Descriptor* descriptor) {
+  GOOGLE_CHECK(!once_);
+  descriptor_ = descriptor;
+}
+
+void LazyDescriptor::SetLazy(StringPiece name,
+                             const FileDescriptor* file) {
+  // verify Init() has been called and Set hasn't been called yet.
+  GOOGLE_CHECK(!descriptor_);
+  GOOGLE_CHECK(!once_);
+  GOOGLE_CHECK(file && file->pool_);
+  GOOGLE_CHECK(file->pool_->lazily_build_dependencies_);
+  GOOGLE_CHECK(!file->finished_building_);
+  once_ = ::new (file->pool_->tables_->AllocateBytes(static_cast<int>(
+      sizeof(internal::once_flag) + name.size() + 1))) internal::once_flag{};
+  char* lazy_name = reinterpret_cast<char*>(once_ + 1);
+  memcpy(lazy_name, name.data(), name.size());
+  lazy_name[name.size()] = 0;
+}
+
+void LazyDescriptor::Once(const ServiceDescriptor* service) {
+  if (once_) {
+    internal::call_once(*once_, [&] {
+      auto* file = service->file();
+      GOOGLE_CHECK(file->finished_building_);
+      const char* lazy_name = reinterpret_cast<const char*>(once_ + 1);
+      descriptor_ =
+          file->pool_->CrossLinkOnDemandHelper(lazy_name, false).descriptor();
+    });
+  }
+}
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor.pb.cpp
new file mode 100644
index 0000000..d3bfb46
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor.pb.cpp
@@ -0,0 +1,11351 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+
+#include <google/protobuf/descriptor.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR FileDescriptorSet::FileDescriptorSet(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.file_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FileDescriptorSetDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FileDescriptorSetDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FileDescriptorSetDefaultTypeInternal() {}
+  union {
+    FileDescriptorSet _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileDescriptorSetDefaultTypeInternal _FileDescriptorSet_default_instance_;
+PROTOBUF_CONSTEXPR FileDescriptorProto::FileDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.dependency_)*/{}
+  , /*decltype(_impl_.message_type_)*/{}
+  , /*decltype(_impl_.enum_type_)*/{}
+  , /*decltype(_impl_.service_)*/{}
+  , /*decltype(_impl_.extension_)*/{}
+  , /*decltype(_impl_.public_dependency_)*/{}
+  , /*decltype(_impl_.weak_dependency_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.syntax_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.source_code_info_)*/nullptr} {}
+struct FileDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FileDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FileDescriptorProtoDefaultTypeInternal() {}
+  union {
+    FileDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileDescriptorProtoDefaultTypeInternal _FileDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.start_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct DescriptorProto_ExtensionRangeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DescriptorProto_ExtensionRangeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DescriptorProto_ExtensionRangeDefaultTypeInternal() {}
+  union {
+    DescriptorProto_ExtensionRange _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProto_ExtensionRangeDefaultTypeInternal _DescriptorProto_ExtensionRange_default_instance_;
+PROTOBUF_CONSTEXPR DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.start_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct DescriptorProto_ReservedRangeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DescriptorProto_ReservedRangeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DescriptorProto_ReservedRangeDefaultTypeInternal() {}
+  union {
+    DescriptorProto_ReservedRange _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProto_ReservedRangeDefaultTypeInternal _DescriptorProto_ReservedRange_default_instance_;
+PROTOBUF_CONSTEXPR DescriptorProto::DescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.field_)*/{}
+  , /*decltype(_impl_.nested_type_)*/{}
+  , /*decltype(_impl_.enum_type_)*/{}
+  , /*decltype(_impl_.extension_range_)*/{}
+  , /*decltype(_impl_.extension_)*/{}
+  , /*decltype(_impl_.oneof_decl_)*/{}
+  , /*decltype(_impl_.reserved_range_)*/{}
+  , /*decltype(_impl_.reserved_name_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct DescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DescriptorProtoDefaultTypeInternal() {}
+  union {
+    DescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProtoDefaultTypeInternal _DescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR ExtensionRangeOptions::ExtensionRangeOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct ExtensionRangeOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ExtensionRangeOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ExtensionRangeOptionsDefaultTypeInternal() {}
+  union {
+    ExtensionRangeOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExtensionRangeOptionsDefaultTypeInternal _ExtensionRangeOptions_default_instance_;
+PROTOBUF_CONSTEXPR FieldDescriptorProto::FieldDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.extendee_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.type_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.default_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.json_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.number_)*/0
+  , /*decltype(_impl_.oneof_index_)*/0
+  , /*decltype(_impl_.proto3_optional_)*/false
+  , /*decltype(_impl_.label_)*/1
+  , /*decltype(_impl_.type_)*/1} {}
+struct FieldDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldDescriptorProtoDefaultTypeInternal() {}
+  union {
+    FieldDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldDescriptorProtoDefaultTypeInternal _FieldDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR OneofDescriptorProto::OneofDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct OneofDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR OneofDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~OneofDescriptorProtoDefaultTypeInternal() {}
+  union {
+    OneofDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OneofDescriptorProtoDefaultTypeInternal _OneofDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.start_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal() {}
+  union {
+    EnumDescriptorProto_EnumReservedRange _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal _EnumDescriptorProto_EnumReservedRange_default_instance_;
+PROTOBUF_CONSTEXPR EnumDescriptorProto::EnumDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.value_)*/{}
+  , /*decltype(_impl_.reserved_range_)*/{}
+  , /*decltype(_impl_.reserved_name_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct EnumDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumDescriptorProtoDefaultTypeInternal() {}
+  union {
+    EnumDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDescriptorProtoDefaultTypeInternal _EnumDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR EnumValueDescriptorProto::EnumValueDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.number_)*/0} {}
+struct EnumValueDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumValueDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumValueDescriptorProtoDefaultTypeInternal() {}
+  union {
+    EnumValueDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueDescriptorProtoDefaultTypeInternal _EnumValueDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR ServiceDescriptorProto::ServiceDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.method_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr} {}
+struct ServiceDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ServiceDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ServiceDescriptorProtoDefaultTypeInternal() {}
+  union {
+    ServiceDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ServiceDescriptorProtoDefaultTypeInternal _ServiceDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR MethodDescriptorProto::MethodDescriptorProto(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.input_type_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.output_type_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.options_)*/nullptr
+  , /*decltype(_impl_.client_streaming_)*/false
+  , /*decltype(_impl_.server_streaming_)*/false} {}
+struct MethodDescriptorProtoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MethodDescriptorProtoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MethodDescriptorProtoDefaultTypeInternal() {}
+  union {
+    MethodDescriptorProto _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodDescriptorProtoDefaultTypeInternal _MethodDescriptorProto_default_instance_;
+PROTOBUF_CONSTEXPR FileOptions::FileOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.java_package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.java_outer_classname_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.go_package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.objc_class_prefix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.csharp_namespace_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.swift_prefix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.php_class_prefix_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.php_namespace_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.php_metadata_namespace_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.ruby_package_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.java_multiple_files_)*/false
+  , /*decltype(_impl_.java_generate_equals_and_hash_)*/false
+  , /*decltype(_impl_.java_string_check_utf8_)*/false
+  , /*decltype(_impl_.cc_generic_services_)*/false
+  , /*decltype(_impl_.java_generic_services_)*/false
+  , /*decltype(_impl_.py_generic_services_)*/false
+  , /*decltype(_impl_.php_generic_services_)*/false
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.optimize_for_)*/1
+  , /*decltype(_impl_.cc_enable_arenas_)*/true} {}
+struct FileOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FileOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FileOptionsDefaultTypeInternal() {}
+  union {
+    FileOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileOptionsDefaultTypeInternal _FileOptions_default_instance_;
+PROTOBUF_CONSTEXPR MessageOptions::MessageOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.message_set_wire_format_)*/false
+  , /*decltype(_impl_.no_standard_descriptor_accessor_)*/false
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.map_entry_)*/false} {}
+struct MessageOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MessageOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MessageOptionsDefaultTypeInternal() {}
+  union {
+    MessageOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MessageOptionsDefaultTypeInternal _MessageOptions_default_instance_;
+PROTOBUF_CONSTEXPR FieldOptions::FieldOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.ctype_)*/0
+  , /*decltype(_impl_.jstype_)*/0
+  , /*decltype(_impl_.packed_)*/false
+  , /*decltype(_impl_.lazy_)*/false
+  , /*decltype(_impl_.unverified_lazy_)*/false
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.weak_)*/false} {}
+struct FieldOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldOptionsDefaultTypeInternal() {}
+  union {
+    FieldOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldOptionsDefaultTypeInternal _FieldOptions_default_instance_;
+PROTOBUF_CONSTEXPR OneofOptions::OneofOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct OneofOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR OneofOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~OneofOptionsDefaultTypeInternal() {}
+  union {
+    OneofOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OneofOptionsDefaultTypeInternal _OneofOptions_default_instance_;
+PROTOBUF_CONSTEXPR EnumOptions::EnumOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.allow_alias_)*/false
+  , /*decltype(_impl_.deprecated_)*/false} {}
+struct EnumOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumOptionsDefaultTypeInternal() {}
+  union {
+    EnumOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumOptionsDefaultTypeInternal _EnumOptions_default_instance_;
+PROTOBUF_CONSTEXPR EnumValueOptions::EnumValueOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.deprecated_)*/false} {}
+struct EnumValueOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumValueOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumValueOptionsDefaultTypeInternal() {}
+  union {
+    EnumValueOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueOptionsDefaultTypeInternal _EnumValueOptions_default_instance_;
+PROTOBUF_CONSTEXPR ServiceOptions::ServiceOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.deprecated_)*/false} {}
+struct ServiceOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ServiceOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ServiceOptionsDefaultTypeInternal() {}
+  union {
+    ServiceOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ServiceOptionsDefaultTypeInternal _ServiceOptions_default_instance_;
+PROTOBUF_CONSTEXPR MethodOptions::MethodOptions(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._extensions_)*/{}
+  , /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.uninterpreted_option_)*/{}
+  , /*decltype(_impl_.deprecated_)*/false
+  , /*decltype(_impl_.idempotency_level_)*/0} {}
+struct MethodOptionsDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR MethodOptionsDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~MethodOptionsDefaultTypeInternal() {}
+  union {
+    MethodOptions _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodOptionsDefaultTypeInternal _MethodOptions_default_instance_;
+PROTOBUF_CONSTEXPR UninterpretedOption_NamePart::UninterpretedOption_NamePart(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_part_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.is_extension_)*/false} {}
+struct UninterpretedOption_NamePartDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UninterpretedOption_NamePartDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UninterpretedOption_NamePartDefaultTypeInternal() {}
+  union {
+    UninterpretedOption_NamePart _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UninterpretedOption_NamePartDefaultTypeInternal _UninterpretedOption_NamePart_default_instance_;
+PROTOBUF_CONSTEXPR UninterpretedOption::UninterpretedOption(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.name_)*/{}
+  , /*decltype(_impl_.identifier_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.string_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.aggregate_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.positive_int_value_)*/uint64_t{0u}
+  , /*decltype(_impl_.negative_int_value_)*/int64_t{0}
+  , /*decltype(_impl_.double_value_)*/0} {}
+struct UninterpretedOptionDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UninterpretedOptionDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UninterpretedOptionDefaultTypeInternal() {}
+  union {
+    UninterpretedOption _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UninterpretedOptionDefaultTypeInternal _UninterpretedOption_default_instance_;
+PROTOBUF_CONSTEXPR SourceCodeInfo_Location::SourceCodeInfo_Location(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.path_)*/{}
+  , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+  , /*decltype(_impl_.span_)*/{}
+  , /*decltype(_impl_._span_cached_byte_size_)*/{0}
+  , /*decltype(_impl_.leading_detached_comments_)*/{}
+  , /*decltype(_impl_.leading_comments_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.trailing_comments_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}} {}
+struct SourceCodeInfo_LocationDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR SourceCodeInfo_LocationDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~SourceCodeInfo_LocationDefaultTypeInternal() {}
+  union {
+    SourceCodeInfo_Location _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceCodeInfo_LocationDefaultTypeInternal _SourceCodeInfo_Location_default_instance_;
+PROTOBUF_CONSTEXPR SourceCodeInfo::SourceCodeInfo(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.location_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct SourceCodeInfoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR SourceCodeInfoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~SourceCodeInfoDefaultTypeInternal() {}
+  union {
+    SourceCodeInfo _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceCodeInfoDefaultTypeInternal _SourceCodeInfo_default_instance_;
+PROTOBUF_CONSTEXPR GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_._has_bits_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_.path_)*/{}
+  , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+  , /*decltype(_impl_.source_file_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.begin_)*/0
+  , /*decltype(_impl_.end_)*/0} {}
+struct GeneratedCodeInfo_AnnotationDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR GeneratedCodeInfo_AnnotationDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~GeneratedCodeInfo_AnnotationDefaultTypeInternal() {}
+  union {
+    GeneratedCodeInfo_Annotation _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfo_AnnotationDefaultTypeInternal _GeneratedCodeInfo_Annotation_default_instance_;
+PROTOBUF_CONSTEXPR GeneratedCodeInfo::GeneratedCodeInfo(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.annotation_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct GeneratedCodeInfoDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR GeneratedCodeInfoDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~GeneratedCodeInfoDefaultTypeInternal() {}
+  union {
+    GeneratedCodeInfo _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet, _impl_.file_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.dependency_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.public_dependency_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.weak_dependency_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.message_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.enum_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.service_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.extension_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.source_code_info_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto, _impl_.syntax_),
+  0,
+  1,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  3,
+  4,
+  2,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.start_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.end_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange, _impl_.options_),
+  1,
+  2,
+  0,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_.start_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange, _impl_.end_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.field_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.extension_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.nested_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.enum_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.extension_range_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.oneof_decl_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.reserved_range_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DescriptorProto, _impl_.reserved_name_),
+  0,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  ~0u,
+  1,
+  ~0u,
+  ~0u,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions, _impl_.uninterpreted_option_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.label_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.type_name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.extendee_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.default_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.oneof_index_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.json_name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto, _impl_.proto3_optional_),
+  0,
+  6,
+  9,
+  10,
+  2,
+  1,
+  3,
+  7,
+  4,
+  5,
+  8,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto, _impl_.options_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_.start_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange, _impl_.end_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.reserved_range_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto, _impl_.reserved_name_),
+  0,
+  ~0u,
+  1,
+  ~0u,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto, _impl_.options_),
+  0,
+  2,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.method_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto, _impl_.options_),
+  0,
+  ~0u,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.input_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.output_type_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.client_streaming_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto, _impl_.server_streaming_),
+  0,
+  1,
+  2,
+  3,
+  4,
+  5,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_outer_classname_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_multiple_files_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_generate_equals_and_hash_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_string_check_utf8_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.optimize_for_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.go_package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.cc_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.java_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.py_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_generic_services_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.cc_enable_arenas_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.objc_class_prefix_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.csharp_namespace_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.swift_prefix_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_class_prefix_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_namespace_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.php_metadata_namespace_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.ruby_package_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FileOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  10,
+  11,
+  12,
+  18,
+  2,
+  13,
+  14,
+  15,
+  16,
+  17,
+  19,
+  3,
+  4,
+  5,
+  6,
+  7,
+  8,
+  9,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.message_set_wire_format_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.no_standard_descriptor_accessor_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.map_entry_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MessageOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  2,
+  3,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.ctype_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.packed_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.jstype_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.lazy_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.unverified_lazy_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.weak_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, _impl_.uninterpreted_option_),
+  0,
+  2,
+  1,
+  3,
+  4,
+  5,
+  6,
+  ~0u,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _impl_.uninterpreted_option_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.allow_alias_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValueOptions, _impl_.uninterpreted_option_),
+  0,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ServiceOptions, _impl_.uninterpreted_option_),
+  0,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _internal_metadata_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_._extensions_),
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.deprecated_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.idempotency_level_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::MethodOptions, _impl_.uninterpreted_option_),
+  0,
+  1,
+  ~0u,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_.name_part_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart, _impl_.is_extension_),
+  0,
+  1,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.identifier_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.positive_int_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.negative_int_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.double_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.string_value_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UninterpretedOption, _impl_.aggregate_value_),
+  ~0u,
+  0,
+  3,
+  4,
+  5,
+  1,
+  2,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.path_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.span_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.leading_comments_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.trailing_comments_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location, _impl_.leading_detached_comments_),
+  ~0u,
+  ~0u,
+  0,
+  1,
+  ~0u,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo, _impl_.location_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_._has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.path_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.source_file_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.begin_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.end_),
+  ~0u,
+  0,
+  1,
+  2,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, _impl_.annotation_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet)},
+  { 7, 25, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto)},
+  { 37, 46, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange)},
+  { 49, 57, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange)},
+  { 59, 75, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto)},
+  { 85, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions)},
+  { 92, 109, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto)},
+  { 120, 128, -1, sizeof(::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto)},
+  { 130, 138, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange)},
+  { 140, 151, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto)},
+  { 156, 165, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto)},
+  { 168, 177, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto)},
+  { 180, 192, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto)},
+  { 198, 225, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileOptions)},
+  { 246, 257, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MessageOptions)},
+  { 262, 276, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldOptions)},
+  { 284, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::OneofOptions)},
+  { 291, 300, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumOptions)},
+  { 303, 311, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValueOptions)},
+  { 313, 321, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ServiceOptions)},
+  { 323, 332, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodOptions)},
+  { 335, 343, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart)},
+  { 345, 358, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
+  { 365, 376, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
+  { 381, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
+  { 388, 398, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
+  { 402, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_FileDescriptorSet_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FileDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ExtensionRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ReservedRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ExtensionRangeOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FieldDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_OneofDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_EnumReservedRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValueDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ServiceDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MethodDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FileOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MessageOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FieldOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_OneofOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValueOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ServiceOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MethodOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_NamePart_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_Location_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_Annotation_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n google/protobuf/descriptor.proto\022\017goog"
+  "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file"
+  "\030\001 \003(\0132$.google.protobuf.FileDescriptorP"
+  "roto\"\333\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001"
+  "(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency\030\003 \003(\t\022"
+  "\031\n\021public_dependency\030\n \003(\005\022\027\n\017weak_depen"
+  "dency\030\013 \003(\005\0226\n\014message_type\030\004 \003(\0132 .goog"
+  "le.protobuf.DescriptorProto\0227\n\tenum_type"
+  "\030\005 \003(\0132$.google.protobuf.EnumDescriptorP"
+  "roto\0228\n\007service\030\006 \003(\0132\'.google.protobuf."
+  "ServiceDescriptorProto\0228\n\textension\030\007 \003("
+  "\0132%.google.protobuf.FieldDescriptorProto"
+  "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File"
+  "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog"
+  "le.protobuf.SourceCodeInfo\022\016\n\006syntax\030\014 \001"
+  "(\t\"\251\005\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005"
+  "field\030\002 \003(\0132%.google.protobuf.FieldDescr"
+  "iptorProto\0228\n\textension\030\006 \003(\0132%.google.p"
+  "rotobuf.FieldDescriptorProto\0225\n\013nested_t"
+  "ype\030\003 \003(\0132 .google.protobuf.DescriptorPr"
+  "oto\0227\n\tenum_type\030\004 \003(\0132$.google.protobuf"
+  ".EnumDescriptorProto\022H\n\017extension_range\030"
+  "\005 \003(\0132/.google.protobuf.DescriptorProto."
+  "ExtensionRange\0229\n\noneof_decl\030\010 \003(\0132%.goo"
+  "gle.protobuf.OneofDescriptorProto\0220\n\007opt"
+  "ions\030\007 \001(\0132\037.google.protobuf.MessageOpti"
+  "ons\022F\n\016reserved_range\030\t \003(\0132..google.pro"
+  "tobuf.DescriptorProto.ReservedRange\022\025\n\rr"
+  "eserved_name\030\n \003(\t\032e\n\016ExtensionRange\022\r\n\005"
+  "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\0227\n\007options\030\003 \001("
+  "\0132&.google.protobuf.ExtensionRangeOption"
+  "s\032+\n\rReservedRange\022\r\n\005start\030\001 \001(\005\022\013\n\003end"
+  "\030\002 \001(\005\"g\n\025ExtensionRangeOptions\022C\n\024unint"
+  "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
+  ".UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\325\005\n\024Fiel"
+  "dDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number"
+  "\030\003 \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf."
+  "FieldDescriptorProto.Label\0228\n\004type\030\005 \001(\016"
+  "2*.google.protobuf.FieldDescriptorProto."
+  "Type\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001("
+  "\t\022\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030"
+  "\t \001(\005\022\021\n\tjson_name\030\n \001(\t\022.\n\007options\030\010 \001("
+  "\0132\035.google.protobuf.FieldOptions\022\027\n\017prot"
+  "o3_optional\030\021 \001(\010\"\266\002\n\004Type\022\017\n\013TYPE_DOUBL"
+  "E\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013T"
+  "YPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIX"
+  "ED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022"
+  "\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE"
+  "_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT3"
+  "2\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n"
+  "\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYP"
+  "E_SINT64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022"
+  "\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\""
+  "T\n\024OneofDescriptorProto\022\014\n\004name\030\001 \001(\t\022.\n"
+  "\007options\030\002 \001(\0132\035.google.protobuf.OneofOp"
+  "tions\"\244\002\n\023EnumDescriptorProto\022\014\n\004name\030\001 "
+  "\001(\t\0228\n\005value\030\002 \003(\0132).google.protobuf.Enu"
+  "mValueDescriptorProto\022-\n\007options\030\003 \001(\0132\034"
+  ".google.protobuf.EnumOptions\022N\n\016reserved"
+  "_range\030\004 \003(\01326.google.protobuf.EnumDescr"
+  "iptorProto.EnumReservedRange\022\025\n\rreserved"
+  "_name\030\005 \003(\t\032/\n\021EnumReservedRange\022\r\n\005star"
+  "t\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"l\n\030EnumValueDescrip"
+  "torProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222"
+  "\n\007options\030\003 \001(\0132!.google.protobuf.EnumVa"
+  "lueOptions\"\220\001\n\026ServiceDescriptorProto\022\014\n"
+  "\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.pro"
+  "tobuf.MethodDescriptorProto\0220\n\007options\030\003"
+  " \001(\0132\037.google.protobuf.ServiceOptions\"\301\001"
+  "\n\025MethodDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n"
+  "\ninput_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/"
+  "\n\007options\030\004 \001(\0132\036.google.protobuf.Method"
+  "Options\022\037\n\020client_streaming\030\005 \001(\010:\005false"
+  "\022\037\n\020server_streaming\030\006 \001(\010:\005false\"\245\006\n\013Fi"
+  "leOptions\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_"
+  "outer_classname\030\010 \001(\t\022\"\n\023java_multiple_f"
+  "iles\030\n \001(\010:\005false\022)\n\035java_generate_equal"
+  "s_and_hash\030\024 \001(\010B\002\030\001\022%\n\026java_string_chec"
+  "k_utf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001("
+  "\0162).google.protobuf.FileOptions.Optimize"
+  "Mode:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_ge"
+  "neric_services\030\020 \001(\010:\005false\022$\n\025java_gene"
+  "ric_services\030\021 \001(\010:\005false\022\"\n\023py_generic_"
+  "services\030\022 \001(\010:\005false\022#\n\024php_generic_ser"
+  "vices\030* \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005"
+  "false\022\036\n\020cc_enable_arenas\030\037 \001(\010:\004true\022\031\n"
+  "\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_names"
+  "pace\030% \001(\t\022\024\n\014swift_prefix\030\' \001(\t\022\030\n\020php_"
+  "class_prefix\030( \001(\t\022\025\n\rphp_namespace\030) \001("
+  "\t\022\036\n\026php_metadata_namespace\030, \001(\t\022\024\n\014rub"
+  "y_package\030- \001(\t\022C\n\024uninterpreted_option\030"
+  "\347\007 \003(\0132$.google.protobuf.UninterpretedOp"
+  "tion\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_"
+  "SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002J\004\010&\020"
+  "\'\"\204\002\n\016MessageOptions\022&\n\027message_set_wire"
+  "_format\030\001 \001(\010:\005false\022.\n\037no_standard_desc"
+  "riptor_accessor\030\002 \001(\010:\005false\022\031\n\ndeprecat"
+  "ed\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024un"
+  "interpreted_option\030\347\007 \003(\0132$.google.proto"
+  "buf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\004\020\005"
+  "J\004\010\005\020\006J\004\010\006\020\007J\004\010\010\020\tJ\004\010\t\020\n\"\276\003\n\014FieldOption"
+  "s\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Field"
+  "Options.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n"
+  "\006jstype\030\006 \001(\0162$.google.protobuf.FieldOpt"
+  "ions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005fa"
+  "lse\022\036\n\017unverified_lazy\030\017 \001(\010:\005false\022\031\n\nd"
+  "eprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005fa"
+  "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
+  "gle.protobuf.UninterpretedOption\"/\n\005CTyp"
+  "e\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020"
+  "\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020"
+  "\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002J\004\010\004\020\005\"^\n\014One"
+  "ofOptions\022C\n\024uninterpreted_option\030\347\007 \003(\013"
+  "2$.google.protobuf.UninterpretedOption*\t"
+  "\010\350\007\020\200\200\200\200\002\"\223\001\n\013EnumOptions\022\023\n\013allow_alias"
+  "\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024uni"
+  "nterpreted_option\030\347\007 \003(\0132$.google.protob"
+  "uf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\005\020\006\""
+  "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:"
+  "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
+  "google.protobuf.UninterpretedOption*\t\010\350\007"
+  "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!"
+  " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
+  "(\0132$.google.protobuf.UninterpretedOption"
+  "*\t\010\350\007\020\200\200\200\200\002\"\255\002\n\rMethodOptions\022\031\n\ndepreca"
+  "ted\030! \001(\010:\005false\022_\n\021idempotency_level\030\" "
+  "\001(\0162/.google.protobuf.MethodOptions.Idem"
+  "potencyLevel:\023IDEMPOTENCY_UNKNOWN\022C\n\024uni"
+  "nterpreted_option\030\347\007 \003(\0132$.google.protob"
+  "uf.UninterpretedOption\"P\n\020IdempotencyLev"
+  "el\022\027\n\023IDEMPOTENCY_UNKNOWN\020\000\022\023\n\017NO_SIDE_E"
+  "FFECTS\020\001\022\016\n\nIDEMPOTENT\020\002*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023"
+  "UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goog"
+  "le.protobuf.UninterpretedOption.NamePart"
+  "\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_i"
+  "nt_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001"
+  "(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_value"
+  "\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010NameP"
+  "art\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002"
+  " \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003("
+  "\0132(.google.protobuf.SourceCodeInfo.Locat"
+  "ion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004sp"
+  "an\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022\031"
+  "\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_det"
+  "ached_comments\030\006 \003(\t\"\247\001\n\021GeneratedCodeIn"
+  "fo\022A\n\nannotation\030\001 \003(\0132-.google.protobuf"
+  ".GeneratedCodeInfo.Annotation\032O\n\nAnnotat"
+  "ion\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source_file\030\002 \001"
+  "(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B~\n\023com.go"
+  "ogle.protobufB\020DescriptorProtosH\001Z-googl"
+  "e.golang.org/protobuf/types/descriptorpb"
+  "\370\001\001\242\002\003GPB\252\002\032Google.Protobuf.Reflection"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
+    false, false, 6078, descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
+    "google/protobuf/descriptor.proto",
+    &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, nullptr, 0, 27,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fdescriptor_2eproto(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[0];
+}
+bool FieldDescriptorProto_Type_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+    case 18:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BOOL;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_STRING;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_GROUP;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_MESSAGE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BYTES;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_ENUM;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
+constexpr int FieldDescriptorProto::Type_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[1];
+}
+bool FieldDescriptorProto_Label_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
+constexpr int FieldDescriptorProto::Label_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[2];
+}
+bool FileOptions_OptimizeMode_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FileOptions_OptimizeMode FileOptions::SPEED;
+constexpr FileOptions_OptimizeMode FileOptions::CODE_SIZE;
+constexpr FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
+constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
+constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
+constexpr int FileOptions::OptimizeMode_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[3];
+}
+bool FieldOptions_CType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldOptions_CType FieldOptions::STRING;
+constexpr FieldOptions_CType FieldOptions::CORD;
+constexpr FieldOptions_CType FieldOptions::STRING_PIECE;
+constexpr FieldOptions_CType FieldOptions::CType_MIN;
+constexpr FieldOptions_CType FieldOptions::CType_MAX;
+constexpr int FieldOptions::CType_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[4];
+}
+bool FieldOptions_JSType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr FieldOptions_JSType FieldOptions::JS_NORMAL;
+constexpr FieldOptions_JSType FieldOptions::JS_STRING;
+constexpr FieldOptions_JSType FieldOptions::JS_NUMBER;
+constexpr FieldOptions_JSType FieldOptions::JSType_MIN;
+constexpr FieldOptions_JSType FieldOptions::JSType_MAX;
+constexpr int FieldOptions::JSType_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[5];
+}
+bool MethodOptions_IdempotencyLevel_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENCY_UNKNOWN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::NO_SIDE_EFFECTS;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENT;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX;
+constexpr int MethodOptions::IdempotencyLevel_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+
+// ===================================================================
+
+class FileDescriptorSet::_Internal {
+ public:
+};
+
+FileDescriptorSet::FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorSet)
+}
+FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FileDescriptorSet* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_){from._impl_.file_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorSet)
+}
+
+inline void FileDescriptorSet::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+FileDescriptorSet::~FileDescriptorSet() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorSet)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FileDescriptorSet::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.file_.~RepeatedPtrField();
+}
+
+void FileDescriptorSet::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FileDescriptorSet::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorSet)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.file_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FileDescriptorSet::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.FileDescriptorProto file = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_file(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FileDescriptorSet::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.FileDescriptorProto file = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_file(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorSet)
+  return target;
+}
+
+size_t FileDescriptorSet::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.FileDescriptorProto file = 1;
+  total_size += 1UL * this->_internal_file_size();
+  for (const auto& msg : this->_impl_.file_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileDescriptorSet::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FileDescriptorSet::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorSet::GetClassData() const { return &_class_data_; }
+
+
+void FileDescriptorSet::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FileDescriptorSet*>(&to_msg);
+  auto& from = static_cast<const FileDescriptorSet&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.file_.MergeFrom(from._impl_.file_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorSet)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FileDescriptorSet::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.file_))
+    return false;
+  return true;
+}
+
+void FileDescriptorSet::InternalSwap(FileDescriptorSet* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.file_.InternalSwap(&other->_impl_.file_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorSet::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[0]);
+}
+
+// ===================================================================
+
+class FileDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FileDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::FileOptions& options(const FileDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo& source_code_info(const FileDescriptorProto* msg);
+  static void set_has_source_code_info(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_syntax(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::FileOptions&
+FileDescriptorProto::_Internal::options(const FileDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+const ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo&
+FileDescriptorProto::_Internal::source_code_info(const FileDescriptorProto* msg) {
+  return *msg->_impl_.source_code_info_;
+}
+FileDescriptorProto::FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorProto)
+}
+FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FileDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.dependency_){from._impl_.dependency_}
+    , decltype(_impl_.message_type_){from._impl_.message_type_}
+    , decltype(_impl_.enum_type_){from._impl_.enum_type_}
+    , decltype(_impl_.service_){from._impl_.service_}
+    , decltype(_impl_.extension_){from._impl_.extension_}
+    , decltype(_impl_.public_dependency_){from._impl_.public_dependency_}
+    , decltype(_impl_.weak_dependency_){from._impl_.weak_dependency_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.package_){}
+    , decltype(_impl_.syntax_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.source_code_info_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_package()) {
+    _this->_impl_.package_.Set(from._internal_package(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.syntax_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_syntax()) {
+    _this->_impl_.syntax_.Set(from._internal_syntax(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::FileOptions(*from._impl_.options_);
+  }
+  if (from._internal_has_source_code_info()) {
+    _this->_impl_.source_code_info_ = new ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo(*from._impl_.source_code_info_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorProto)
+}
+
+inline void FileDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.dependency_){arena}
+    , decltype(_impl_.message_type_){arena}
+    , decltype(_impl_.enum_type_){arena}
+    , decltype(_impl_.service_){arena}
+    , decltype(_impl_.extension_){arena}
+    , decltype(_impl_.public_dependency_){arena}
+    , decltype(_impl_.weak_dependency_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.package_){}
+    , decltype(_impl_.syntax_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.source_code_info_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.syntax_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.syntax_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+FileDescriptorProto::~FileDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FileDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.dependency_.~RepeatedPtrField();
+  _impl_.message_type_.~RepeatedPtrField();
+  _impl_.enum_type_.~RepeatedPtrField();
+  _impl_.service_.~RepeatedPtrField();
+  _impl_.extension_.~RepeatedPtrField();
+  _impl_.public_dependency_.~RepeatedField();
+  _impl_.weak_dependency_.~RepeatedField();
+  _impl_.name_.Destroy();
+  _impl_.package_.Destroy();
+  _impl_.syntax_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+  if (this != internal_default_instance()) delete _impl_.source_code_info_;
+}
+
+void FileDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FileDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.dependency_.Clear();
+  _impl_.message_type_.Clear();
+  _impl_.enum_type_.Clear();
+  _impl_.service_.Clear();
+  _impl_.extension_.Clear();
+  _impl_.public_dependency_.Clear();
+  _impl_.weak_dependency_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000001fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.package_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.syntax_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+    if (cached_has_bits & 0x00000010u) {
+      GOOGLE_DCHECK(_impl_.source_code_info_ != nullptr);
+      _impl_.source_code_info_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FileDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string package = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string dependency = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_dependency();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.dependency");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto message_type = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_message_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_enum_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_service(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_extension(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<58>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FileOptions options = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_code_info(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated int32 public_dependency = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            _internal_add_public_dependency(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<80>(ptr));
+        } else if (static_cast<uint8_t>(tag) == 82) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_public_dependency(), ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated int32 weak_dependency = 11;
+      case 11:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 88)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            _internal_add_weak_dependency(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<88>(ptr));
+        } else if (static_cast<uint8_t>(tag) == 90) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_weak_dependency(), ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string syntax = 12;
+      case 12:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 98)) {
+          auto str = _internal_mutable_syntax();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.syntax");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FileDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string package = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_package().data(), static_cast<int>(this->_internal_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.package");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_package(), target);
+  }
+
+  // repeated string dependency = 3;
+  for (int i = 0, n = this->_internal_dependency_size(); i < n; i++) {
+    const auto& s = this->_internal_dependency(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.dependency");
+    target = stream->WriteString(3, s, target);
+  }
+
+  // repeated .google.protobuf.DescriptorProto message_type = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_message_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_message_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enum_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enum_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(5, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_service_size()); i < n; i++) {
+    const auto& repfield = this->_internal_service(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(7, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.FileOptions options = 8;
+  if (cached_has_bits & 0x00000008u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(8, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+  if (cached_has_bits & 0x00000010u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(9, _Internal::source_code_info(this),
+        _Internal::source_code_info(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated int32 public_dependency = 10;
+  for (int i = 0, n = this->_internal_public_dependency_size(); i < n; i++) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(10, this->_internal_public_dependency(i), target);
+  }
+
+  // repeated int32 weak_dependency = 11;
+  for (int i = 0, n = this->_internal_weak_dependency_size(); i < n; i++) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(11, this->_internal_weak_dependency(i), target);
+  }
+
+  // optional string syntax = 12;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_syntax().data(), static_cast<int>(this->_internal_syntax().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.syntax");
+    target = stream->WriteStringMaybeAliased(
+        12, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorProto)
+  return target;
+}
+
+size_t FileDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated string dependency = 3;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.dependency_.size());
+  for (int i = 0, n = _impl_.dependency_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.dependency_.Get(i));
+  }
+
+  // repeated .google.protobuf.DescriptorProto message_type = 4;
+  total_size += 1UL * this->_internal_message_type_size();
+  for (const auto& msg : this->_impl_.message_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+  total_size += 1UL * this->_internal_enum_type_size();
+  for (const auto& msg : this->_impl_.enum_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
+  total_size += 1UL * this->_internal_service_size();
+  for (const auto& msg : this->_impl_.service_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
+  total_size += 1UL * this->_internal_extension_size();
+  for (const auto& msg : this->_impl_.extension_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated int32 public_dependency = 10;
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.public_dependency_);
+    total_size += 1 *
+                  ::_pbi::FromIntSize(this->_internal_public_dependency_size());
+    total_size += data_size;
+  }
+
+  // repeated int32 weak_dependency = 11;
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.weak_dependency_);
+    total_size += 1 *
+                  ::_pbi::FromIntSize(this->_internal_weak_dependency_size());
+    total_size += data_size;
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000001fu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string package = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_package());
+    }
+
+    // optional string syntax = 12;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_syntax());
+    }
+
+    // optional .google.protobuf.FileOptions options = 8;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.source_code_info_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FileDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void FileDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FileDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const FileDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.dependency_.MergeFrom(from._impl_.dependency_);
+  _this->_impl_.message_type_.MergeFrom(from._impl_.message_type_);
+  _this->_impl_.enum_type_.MergeFrom(from._impl_.enum_type_);
+  _this->_impl_.service_.MergeFrom(from._impl_.service_);
+  _this->_impl_.extension_.MergeFrom(from._impl_.extension_);
+  _this->_impl_.public_dependency_.MergeFrom(from._impl_.public_dependency_);
+  _this->_impl_.weak_dependency_.MergeFrom(from._impl_.weak_dependency_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000001fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_package(from._internal_package());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_syntax(from._internal_syntax());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::FileOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_internal_mutable_source_code_info()->::PROTOBUF_NAMESPACE_ID::SourceCodeInfo::MergeFrom(
+          from._internal_source_code_info());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FileDescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.message_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.enum_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.service_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.extension_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.dependency_.InternalSwap(&other->_impl_.dependency_);
+  _impl_.message_type_.InternalSwap(&other->_impl_.message_type_);
+  _impl_.enum_type_.InternalSwap(&other->_impl_.enum_type_);
+  _impl_.service_.InternalSwap(&other->_impl_.service_);
+  _impl_.extension_.InternalSwap(&other->_impl_.extension_);
+  _impl_.public_dependency_.InternalSwap(&other->_impl_.public_dependency_);
+  _impl_.weak_dependency_.InternalSwap(&other->_impl_.weak_dependency_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.package_, lhs_arena,
+      &other->_impl_.package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.syntax_, lhs_arena,
+      &other->_impl_.syntax_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FileDescriptorProto, _impl_.source_code_info_)
+      + sizeof(FileDescriptorProto::_impl_.source_code_info_)
+      - PROTOBUF_FIELD_OFFSET(FileDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[1]);
+}
+
+// ===================================================================
+
+class DescriptorProto_ExtensionRange::_Internal {
+ public:
+  using HasBits = decltype(std::declval<DescriptorProto_ExtensionRange>()._impl_._has_bits_);
+  static void set_has_start(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions& options(const DescriptorProto_ExtensionRange* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions&
+DescriptorProto_ExtensionRange::_Internal::options(const DescriptorProto_ExtensionRange* msg) {
+  return *msg->_impl_.options_;
+}
+DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ExtensionRange)
+}
+DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DescriptorProto_ExtensionRange* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.start_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions(*from._impl_.options_);
+  }
+  ::memcpy(&_impl_.start_, &from._impl_.start_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ExtensionRange)
+}
+
+inline void DescriptorProto_ExtensionRange::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.start_){0}
+    , decltype(_impl_.end_){0}
+  };
+}
+
+DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ExtensionRange)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DescriptorProto_ExtensionRange::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void DescriptorProto_ExtensionRange::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DescriptorProto_ExtensionRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ExtensionRange)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    GOOGLE_DCHECK(_impl_.options_ != nullptr);
+    _impl_.options_->Clear();
+  }
+  if (cached_has_bits & 0x00000006u) {
+    ::memset(&_impl_.start_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 start = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_start(&has_bits);
+          _impl_.start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.ExtensionRangeOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DescriptorProto_ExtensionRange::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 start = 1;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+  }
+
+  // optional .google.protobuf.ExtensionRangeOptions options = 3;
+  if (cached_has_bits & 0x00000001u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ExtensionRange)
+  return target;
+}
+
+size_t DescriptorProto_ExtensionRange::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    // optional .google.protobuf.ExtensionRangeOptions options = 3;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional int32 start = 1;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+    }
+
+    // optional int32 end = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto_ExtensionRange::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DescriptorProto_ExtensionRange::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ExtensionRange::GetClassData() const { return &_class_data_; }
+
+
+void DescriptorProto_ExtensionRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DescriptorProto_ExtensionRange*>(&to_msg);
+  auto& from = static_cast<const DescriptorProto_ExtensionRange&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.start_ = from._impl_.start_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto_ExtensionRange::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(DescriptorProto_ExtensionRange, _impl_.end_)
+      + sizeof(DescriptorProto_ExtensionRange::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(DescriptorProto_ExtensionRange, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ExtensionRange::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[2]);
+}
+
+// ===================================================================
+
+class DescriptorProto_ReservedRange::_Internal {
+ public:
+  using HasBits = decltype(std::declval<DescriptorProto_ReservedRange>()._impl_._has_bits_);
+  static void set_has_start(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DescriptorProto_ReservedRange* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.start_, &from._impl_.start_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+inline void DescriptorProto_ReservedRange::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){0}
+    , decltype(_impl_.end_){0}
+  };
+}
+
+DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ReservedRange)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DescriptorProto_ReservedRange::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void DescriptorProto_ReservedRange::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DescriptorProto_ReservedRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ReservedRange)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    ::memset(&_impl_.start_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 start = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_start(&has_bits);
+          _impl_.start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DescriptorProto_ReservedRange::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 start = 1;
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange)
+  return target;
+}
+
+size_t DescriptorProto_ReservedRange::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional int32 start = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+    }
+
+    // optional int32 end = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto_ReservedRange::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DescriptorProto_ReservedRange::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ReservedRange::GetClassData() const { return &_class_data_; }
+
+
+void DescriptorProto_ReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DescriptorProto_ReservedRange*>(&to_msg);
+  auto& from = static_cast<const DescriptorProto_ReservedRange&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.start_ = from._impl_.start_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto_ReservedRange::IsInitialized() const {
+  return true;
+}
+
+void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(DescriptorProto_ReservedRange, _impl_.end_)
+      + sizeof(DescriptorProto_ReservedRange::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(DescriptorProto_ReservedRange, _impl_.start_)>(
+          reinterpret_cast<char*>(&_impl_.start_),
+          reinterpret_cast<char*>(&other->_impl_.start_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ReservedRange::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[3]);
+}
+
+// ===================================================================
+
+class DescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<DescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::MessageOptions& options(const DescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::MessageOptions&
+DescriptorProto::_Internal::options(const DescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+DescriptorProto::DescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto)
+}
+DescriptorProto::DescriptorProto(const DescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.field_){from._impl_.field_}
+    , decltype(_impl_.nested_type_){from._impl_.nested_type_}
+    , decltype(_impl_.enum_type_){from._impl_.enum_type_}
+    , decltype(_impl_.extension_range_){from._impl_.extension_range_}
+    , decltype(_impl_.extension_){from._impl_.extension_}
+    , decltype(_impl_.oneof_decl_){from._impl_.oneof_decl_}
+    , decltype(_impl_.reserved_range_){from._impl_.reserved_range_}
+    , decltype(_impl_.reserved_name_){from._impl_.reserved_name_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::MessageOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto)
+}
+
+inline void DescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.field_){arena}
+    , decltype(_impl_.nested_type_){arena}
+    , decltype(_impl_.enum_type_){arena}
+    , decltype(_impl_.extension_range_){arena}
+    , decltype(_impl_.extension_){arena}
+    , decltype(_impl_.oneof_decl_){arena}
+    , decltype(_impl_.reserved_range_){arena}
+    , decltype(_impl_.reserved_name_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+DescriptorProto::~DescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.field_.~RepeatedPtrField();
+  _impl_.nested_type_.~RepeatedPtrField();
+  _impl_.enum_type_.~RepeatedPtrField();
+  _impl_.extension_range_.~RepeatedPtrField();
+  _impl_.extension_.~RepeatedPtrField();
+  _impl_.oneof_decl_.~RepeatedPtrField();
+  _impl_.reserved_range_.~RepeatedPtrField();
+  _impl_.reserved_name_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void DescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.field_.Clear();
+  _impl_.nested_type_.Clear();
+  _impl_.enum_type_.Clear();
+  _impl_.extension_range_.Clear();
+  _impl_.extension_.Clear();
+  _impl_.oneof_decl_.Clear();
+  _impl_.reserved_range_.Clear();
+  _impl_.reserved_name_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.DescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FieldDescriptorProto field = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_field(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto nested_type = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_nested_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_enum_type(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_extension_range(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_extension(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.MessageOptions options = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_oneof_decl(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<66>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_reserved_range(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<74>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string reserved_name = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_reserved_name();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.DescriptorProto.reserved_name");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<82>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto field = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_field_size()); i < n; i++) {
+    const auto& repfield = this->_internal_field(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.DescriptorProto nested_type = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_nested_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_nested_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enum_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enum_type(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension_range(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(5, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.MessageOptions options = 7;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(7, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_oneof_decl_size()); i < n; i++) {
+    const auto& repfield = this->_internal_oneof_decl(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(8, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_reserved_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_reserved_range(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(9, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated string reserved_name = 10;
+  for (int i = 0, n = this->_internal_reserved_name_size(); i < n; i++) {
+    const auto& s = this->_internal_reserved_name(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.reserved_name");
+    target = stream->WriteString(10, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto)
+  return target;
+}
+
+size_t DescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.FieldDescriptorProto field = 2;
+  total_size += 1UL * this->_internal_field_size();
+  for (const auto& msg : this->_impl_.field_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.DescriptorProto nested_type = 3;
+  total_size += 1UL * this->_internal_nested_type_size();
+  for (const auto& msg : this->_impl_.nested_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+  total_size += 1UL * this->_internal_enum_type_size();
+  for (const auto& msg : this->_impl_.enum_type_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+  total_size += 1UL * this->_internal_extension_range_size();
+  for (const auto& msg : this->_impl_.extension_range_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
+  total_size += 1UL * this->_internal_extension_size();
+  for (const auto& msg : this->_impl_.extension_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+  total_size += 1UL * this->_internal_oneof_decl_size();
+  for (const auto& msg : this->_impl_.oneof_decl_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  total_size += 1UL * this->_internal_reserved_range_size();
+  for (const auto& msg : this->_impl_.reserved_range_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated string reserved_name = 10;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.reserved_name_.size());
+  for (int i = 0, n = _impl_.reserved_name_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.reserved_name_.Get(i));
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.MessageOptions options = 7;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void DescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DescriptorProto*>(&to_msg);
+  auto& from = static_cast<const DescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.field_.MergeFrom(from._impl_.field_);
+  _this->_impl_.nested_type_.MergeFrom(from._impl_.nested_type_);
+  _this->_impl_.enum_type_.MergeFrom(from._impl_.enum_type_);
+  _this->_impl_.extension_range_.MergeFrom(from._impl_.extension_range_);
+  _this->_impl_.extension_.MergeFrom(from._impl_.extension_);
+  _this->_impl_.oneof_decl_.MergeFrom(from._impl_.oneof_decl_);
+  _this->_impl_.reserved_range_.MergeFrom(from._impl_.reserved_range_);
+  _this->_impl_.reserved_name_.MergeFrom(from._impl_.reserved_name_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::MessageOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DescriptorProto::CopyFrom(const DescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.field_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.nested_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.enum_type_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.extension_range_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.extension_))
+    return false;
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.oneof_decl_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void DescriptorProto::InternalSwap(DescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.field_.InternalSwap(&other->_impl_.field_);
+  _impl_.nested_type_.InternalSwap(&other->_impl_.nested_type_);
+  _impl_.enum_type_.InternalSwap(&other->_impl_.enum_type_);
+  _impl_.extension_range_.InternalSwap(&other->_impl_.extension_range_);
+  _impl_.extension_.InternalSwap(&other->_impl_.extension_);
+  _impl_.oneof_decl_.InternalSwap(&other->_impl_.oneof_decl_);
+  _impl_.reserved_range_.InternalSwap(&other->_impl_.reserved_range_);
+  _impl_.reserved_name_.InternalSwap(&other->_impl_.reserved_name_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[4]);
+}
+
+// ===================================================================
+
+class ExtensionRangeOptions::_Internal {
+ public:
+};
+
+ExtensionRangeOptions::ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ExtensionRangeOptions)
+}
+ExtensionRangeOptions::ExtensionRangeOptions(const ExtensionRangeOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ExtensionRangeOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ExtensionRangeOptions)
+}
+
+inline void ExtensionRangeOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+ExtensionRangeOptions::~ExtensionRangeOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ExtensionRangeOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ExtensionRangeOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void ExtensionRangeOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ExtensionRangeOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ExtensionRangeOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ExtensionRangeOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ExtensionRangeOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ExtensionRangeOptions)
+  return target;
+}
+
+size_t ExtensionRangeOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ExtensionRangeOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ExtensionRangeOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ExtensionRangeOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ExtensionRangeOptions::GetClassData() const { return &_class_data_; }
+
+
+void ExtensionRangeOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ExtensionRangeOptions*>(&to_msg);
+  auto& from = static_cast<const ExtensionRangeOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ExtensionRangeOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ExtensionRangeOptions::CopyFrom(const ExtensionRangeOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ExtensionRangeOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ExtensionRangeOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void ExtensionRangeOptions::InternalSwap(ExtensionRangeOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ExtensionRangeOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[5]);
+}
+
+// ===================================================================
+
+class FieldDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FieldDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_number(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
+  static void set_has_label(HasBits* has_bits) {
+    (*has_bits)[0] |= 512u;
+  }
+  static void set_has_type(HasBits* has_bits) {
+    (*has_bits)[0] |= 1024u;
+  }
+  static void set_has_type_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_extendee(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_default_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_oneof_index(HasBits* has_bits) {
+    (*has_bits)[0] |= 128u;
+  }
+  static void set_has_json_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::FieldOptions& options(const FieldDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_proto3_optional(HasBits* has_bits) {
+    (*has_bits)[0] |= 256u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::FieldOptions&
+FieldDescriptorProto::_Internal::options(const FieldDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+FieldDescriptorProto::FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldDescriptorProto)
+}
+FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FieldDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.extendee_){}
+    , decltype(_impl_.type_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){}
+    , decltype(_impl_.oneof_index_){}
+    , decltype(_impl_.proto3_optional_){}
+    , decltype(_impl_.label_){}
+    , decltype(_impl_.type_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.extendee_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_extendee()) {
+    _this->_impl_.extendee_.Set(from._internal_extendee(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.type_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_type_name()) {
+    _this->_impl_.type_name_.Set(from._internal_type_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_default_value()) {
+    _this->_impl_.default_value_.Set(from._internal_default_value(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_json_name()) {
+    _this->_impl_.json_name_.Set(from._internal_json_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::FieldOptions(*from._impl_.options_);
+  }
+  ::memcpy(&_impl_.number_, &from._impl_.number_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.type_) -
+    reinterpret_cast<char*>(&_impl_.number_)) + sizeof(_impl_.type_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldDescriptorProto)
+}
+
+inline void FieldDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.extendee_){}
+    , decltype(_impl_.type_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){0}
+    , decltype(_impl_.oneof_index_){0}
+    , decltype(_impl_.proto3_optional_){false}
+    , decltype(_impl_.label_){1}
+    , decltype(_impl_.type_){1}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.extendee_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.extendee_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.type_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+FieldDescriptorProto::~FieldDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FieldDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.extendee_.Destroy();
+  _impl_.type_name_.Destroy();
+  _impl_.default_value_.Destroy();
+  _impl_.json_name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void FieldDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FieldDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.extendee_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.type_name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _impl_.default_value_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _impl_.json_name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000020u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  if (cached_has_bits & 0x000000c0u) {
+    ::memset(&_impl_.number_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.oneof_index_) -
+        reinterpret_cast<char*>(&_impl_.number_)) + sizeof(_impl_.oneof_index_));
+  }
+  if (cached_has_bits & 0x00000700u) {
+    _impl_.proto3_optional_ = false;
+    _impl_.label_ = 1;
+    _impl_.type_ = 1;
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string extendee = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_extendee();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.extendee");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 number = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_number(&has_bits);
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_IsValid(val))) {
+            _internal_set_label(static_cast<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(4, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_IsValid(val))) {
+            _internal_set_type(static_cast<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(5, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string type_name = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          auto str = _internal_mutable_type_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.type_name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string default_value = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          auto str = _internal_mutable_default_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.default_value");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldOptions options = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 oneof_index = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 72)) {
+          _Internal::set_has_oneof_index(&has_bits);
+          _impl_.oneof_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string json_name = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
+          auto str = _internal_mutable_json_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.json_name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool proto3_optional = 17;
+      case 17:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 136)) {
+          _Internal::set_has_proto3_optional(&has_bits);
+          _impl_.proto3_optional_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FieldDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string extendee = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_extendee().data(), static_cast<int>(this->_internal_extendee().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.extendee");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_extendee(), target);
+  }
+
+  // optional int32 number = 3;
+  if (cached_has_bits & 0x00000040u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
+  }
+
+  // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+  if (cached_has_bits & 0x00000200u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      4, this->_internal_label(), target);
+  }
+
+  // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+  if (cached_has_bits & 0x00000400u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      5, this->_internal_type(), target);
+  }
+
+  // optional string type_name = 6;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_type_name().data(), static_cast<int>(this->_internal_type_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.type_name");
+    target = stream->WriteStringMaybeAliased(
+        6, this->_internal_type_name(), target);
+  }
+
+  // optional string default_value = 7;
+  if (cached_has_bits & 0x00000008u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_default_value().data(), static_cast<int>(this->_internal_default_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.default_value");
+    target = stream->WriteStringMaybeAliased(
+        7, this->_internal_default_value(), target);
+  }
+
+  // optional .google.protobuf.FieldOptions options = 8;
+  if (cached_has_bits & 0x00000020u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(8, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // optional int32 oneof_index = 9;
+  if (cached_has_bits & 0x00000080u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(9, this->_internal_oneof_index(), target);
+  }
+
+  // optional string json_name = 10;
+  if (cached_has_bits & 0x00000010u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_json_name().data(), static_cast<int>(this->_internal_json_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.json_name");
+    target = stream->WriteStringMaybeAliased(
+        10, this->_internal_json_name(), target);
+  }
+
+  // optional bool proto3_optional = 17;
+  if (cached_has_bits & 0x00000100u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(17, this->_internal_proto3_optional(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldDescriptorProto)
+  return target;
+}
+
+size_t FieldDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string extendee = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_extendee());
+    }
+
+    // optional string type_name = 6;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_type_name());
+    }
+
+    // optional string default_value = 7;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_default_value());
+    }
+
+    // optional string json_name = 10;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_json_name());
+    }
+
+    // optional .google.protobuf.FieldOptions options = 8;
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional int32 number = 3;
+    if (cached_has_bits & 0x00000040u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+    }
+
+    // optional int32 oneof_index = 9;
+    if (cached_has_bits & 0x00000080u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
+    }
+
+  }
+  if (cached_has_bits & 0x00000700u) {
+    // optional bool proto3_optional = 17;
+    if (cached_has_bits & 0x00000100u) {
+      total_size += 2 + 1;
+    }
+
+    // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+    if (cached_has_bits & 0x00000200u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_label());
+    }
+
+    // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+    if (cached_has_bits & 0x00000400u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_type());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FieldDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void FieldDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FieldDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const FieldDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_extendee(from._internal_extendee());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_type_name(from._internal_type_name());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_set_default_value(from._internal_default_value());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_internal_set_json_name(from._internal_json_name());
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::FieldOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _this->_impl_.number_ = from._impl_.number_;
+    }
+    if (cached_has_bits & 0x00000080u) {
+      _this->_impl_.oneof_index_ = from._impl_.oneof_index_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  if (cached_has_bits & 0x00000700u) {
+    if (cached_has_bits & 0x00000100u) {
+      _this->_impl_.proto3_optional_ = from._impl_.proto3_optional_;
+    }
+    if (cached_has_bits & 0x00000200u) {
+      _this->_impl_.label_ = from._impl_.label_;
+    }
+    if (cached_has_bits & 0x00000400u) {
+      _this->_impl_.type_ = from._impl_.type_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.extendee_, lhs_arena,
+      &other->_impl_.extendee_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.type_name_, lhs_arena,
+      &other->_impl_.type_name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.default_value_, lhs_arena,
+      &other->_impl_.default_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.json_name_, lhs_arena,
+      &other->_impl_.json_name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FieldDescriptorProto, _impl_.proto3_optional_)
+      + sizeof(FieldDescriptorProto::_impl_.proto3_optional_)
+      - PROTOBUF_FIELD_OFFSET(FieldDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+  swap(_impl_.label_, other->_impl_.label_);
+  swap(_impl_.type_, other->_impl_.type_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FieldDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[6]);
+}
+
+// ===================================================================
+
+class OneofDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<OneofDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::OneofOptions& options(const OneofDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::OneofOptions&
+OneofDescriptorProto::_Internal::options(const OneofDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+OneofDescriptorProto::OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofDescriptorProto)
+}
+OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  OneofDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::OneofOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofDescriptorProto)
+}
+
+inline void OneofDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+OneofDescriptorProto::~OneofDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.OneofDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void OneofDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void OneofDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void OneofDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.OneofDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.OneofOptions options = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* OneofDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.OneofDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional .google.protobuf.OneofOptions options = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(2, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofDescriptorProto)
+  return target;
+}
+
+size_t OneofDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.OneofOptions options = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData OneofDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    OneofDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void OneofDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<OneofDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const OneofDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::OneofOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool OneofDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata OneofDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[7]);
+}
+
+// ===================================================================
+
+class EnumDescriptorProto_EnumReservedRange::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumDescriptorProto_EnumReservedRange>()._impl_._has_bits_);
+  static void set_has_start(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+}
+EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(const EnumDescriptorProto_EnumReservedRange& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumDescriptorProto_EnumReservedRange* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.start_, &from._impl_.start_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+}
+
+inline void EnumDescriptorProto_EnumReservedRange::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.start_){0}
+    , decltype(_impl_.end_){0}
+  };
+}
+
+EnumDescriptorProto_EnumReservedRange::~EnumDescriptorProto_EnumReservedRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumDescriptorProto_EnumReservedRange::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void EnumDescriptorProto_EnumReservedRange::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumDescriptorProto_EnumReservedRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    ::memset(&_impl_.start_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.start_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional int32 start = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_start(&has_bits);
+          _impl_.start_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumDescriptorProto_EnumReservedRange::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional int32 start = 1;
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  return target;
+}
+
+size_t EnumDescriptorProto_EnumReservedRange::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional int32 start = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+    }
+
+    // optional int32 end = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumDescriptorProto_EnumReservedRange::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumDescriptorProto_EnumReservedRange::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto_EnumReservedRange::GetClassData() const { return &_class_data_; }
+
+
+void EnumDescriptorProto_EnumReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumDescriptorProto_EnumReservedRange*>(&to_msg);
+  auto& from = static_cast<const EnumDescriptorProto_EnumReservedRange&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.start_ = from._impl_.start_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumDescriptorProto_EnumReservedRange::CopyFrom(const EnumDescriptorProto_EnumReservedRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumDescriptorProto_EnumReservedRange::IsInitialized() const {
+  return true;
+}
+
+void EnumDescriptorProto_EnumReservedRange::InternalSwap(EnumDescriptorProto_EnumReservedRange* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(EnumDescriptorProto_EnumReservedRange, _impl_.end_)
+      + sizeof(EnumDescriptorProto_EnumReservedRange::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(EnumDescriptorProto_EnumReservedRange, _impl_.start_)>(
+          reinterpret_cast<char*>(&_impl_.start_),
+          reinterpret_cast<char*>(&other->_impl_.start_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto_EnumReservedRange::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[8]);
+}
+
+// ===================================================================
+
+class EnumDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::EnumOptions& options(const EnumDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::EnumOptions&
+EnumDescriptorProto::_Internal::options(const EnumDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+EnumDescriptorProto::EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto)
+}
+EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.value_){from._impl_.value_}
+    , decltype(_impl_.reserved_range_){from._impl_.reserved_range_}
+    , decltype(_impl_.reserved_name_){from._impl_.reserved_name_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::EnumOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto)
+}
+
+inline void EnumDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.value_){arena}
+    , decltype(_impl_.reserved_range_){arena}
+    , decltype(_impl_.reserved_name_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+EnumDescriptorProto::~EnumDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.value_.~RepeatedPtrField();
+  _impl_.reserved_range_.~RepeatedPtrField();
+  _impl_.reserved_name_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void EnumDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_.Clear();
+  _impl_.reserved_range_.Clear();
+  _impl_.reserved_name_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_value(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.EnumOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_reserved_range(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string reserved_name = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_reserved_name();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.reserved_name");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.EnumDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_value_size()); i < n; i++) {
+    const auto& repfield = this->_internal_value(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.EnumOptions options = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_reserved_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_reserved_range(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated string reserved_name = 5;
+  for (int i = 0, n = this->_internal_reserved_name_size(); i < n; i++) {
+    const auto& s = this->_internal_reserved_name(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.EnumDescriptorProto.reserved_name");
+    target = stream->WriteString(5, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto)
+  return target;
+}
+
+size_t EnumDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+  total_size += 1UL * this->_internal_value_size();
+  for (const auto& msg : this->_impl_.value_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
+  total_size += 1UL * this->_internal_reserved_range_size();
+  for (const auto& msg : this->_impl_.reserved_range_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated string reserved_name = 5;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.reserved_name_.size());
+  for (int i = 0, n = _impl_.reserved_name_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.reserved_name_.Get(i));
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.EnumOptions options = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void EnumDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const EnumDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.value_.MergeFrom(from._impl_.value_);
+  _this->_impl_.reserved_range_.MergeFrom(from._impl_.reserved_range_);
+  _this->_impl_.reserved_name_.MergeFrom(from._impl_.reserved_name_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::EnumOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumDescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.value_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.value_.InternalSwap(&other->_impl_.value_);
+  _impl_.reserved_range_.InternalSwap(&other->_impl_.reserved_range_);
+  _impl_.reserved_name_.InternalSwap(&other->_impl_.reserved_name_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[9]);
+}
+
+// ===================================================================
+
+class EnumValueDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumValueDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_number(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions& options(const EnumValueDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::EnumValueOptions&
+EnumValueDescriptorProto::_Internal::options(const EnumValueDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+EnumValueDescriptorProto::EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueDescriptorProto)
+}
+EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumValueDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::EnumValueOptions(*from._impl_.options_);
+  }
+  _this->_impl_.number_ = from._impl_.number_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueDescriptorProto)
+}
+
+inline void EnumValueDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.number_){0}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+EnumValueDescriptorProto::~EnumValueDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValueDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumValueDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void EnumValueDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumValueDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_.number_ = 0;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.EnumValueDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 number = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_number(&has_bits);
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.EnumValueOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumValueDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.EnumValueDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional int32 number = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
+  }
+
+  // optional .google.protobuf.EnumValueOptions options = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueDescriptorProto)
+  return target;
+}
+
+size_t EnumValueDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.EnumValueOptions options = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional int32 number = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValueDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumValueDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void EnumValueDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumValueDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const EnumValueDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::EnumValueOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.number_ = from._impl_.number_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValueDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(EnumValueDescriptorProto, _impl_.number_)
+      + sizeof(EnumValueDescriptorProto::_impl_.number_)
+      - PROTOBUF_FIELD_OFFSET(EnumValueDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumValueDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[10]);
+}
+
+// ===================================================================
+
+class ServiceDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<ServiceDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::ServiceOptions& options(const ServiceDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::ServiceOptions&
+ServiceDescriptorProto::_Internal::options(const ServiceDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+ServiceDescriptorProto::ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceDescriptorProto)
+}
+ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ServiceDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.method_){from._impl_.method_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::ServiceOptions(*from._impl_.options_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceDescriptorProto)
+}
+
+inline void ServiceDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.method_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.options_){nullptr}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+ServiceDescriptorProto::~ServiceDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ServiceDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ServiceDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.method_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void ServiceDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ServiceDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.method_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.ServiceDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.MethodDescriptorProto method = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_method(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.ServiceOptions options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ServiceDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.ServiceDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.MethodDescriptorProto method = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_method_size()); i < n; i++) {
+    const auto& repfield = this->_internal_method(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // optional .google.protobuf.ServiceOptions options = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceDescriptorProto)
+  return target;
+}
+
+size_t ServiceDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.MethodDescriptorProto method = 2;
+  total_size += 1UL * this->_internal_method_size();
+  for (const auto& msg : this->_impl_.method_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional .google.protobuf.ServiceOptions options = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ServiceDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ServiceDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void ServiceDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ServiceDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const ServiceDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.method_.MergeFrom(from._impl_.method_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::ServiceOptions::MergeFrom(
+          from._internal_options());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ServiceDescriptorProto::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.method_))
+    return false;
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.method_.InternalSwap(&other->_impl_.method_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.options_, other->_impl_.options_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ServiceDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[11]);
+}
+
+// ===================================================================
+
+class MethodDescriptorProto::_Internal {
+ public:
+  using HasBits = decltype(std::declval<MethodDescriptorProto>()._impl_._has_bits_);
+  static void set_has_name(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_input_type(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_output_type(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static const ::PROTOBUF_NAMESPACE_ID::MethodOptions& options(const MethodDescriptorProto* msg);
+  static void set_has_options(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_client_streaming(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_server_streaming(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+};
+
+const ::PROTOBUF_NAMESPACE_ID::MethodOptions&
+MethodDescriptorProto::_Internal::options(const MethodDescriptorProto* msg) {
+  return *msg->_impl_.options_;
+}
+MethodDescriptorProto::MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodDescriptorProto)
+}
+MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MethodDescriptorProto* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.input_type_){}
+    , decltype(_impl_.output_type_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.client_streaming_){}
+    , decltype(_impl_.server_streaming_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.input_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_input_type()) {
+    _this->_impl_.input_type_.Set(from._internal_input_type(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.output_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_output_type()) {
+    _this->_impl_.output_type_.Set(from._internal_output_type(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_options()) {
+    _this->_impl_.options_ = new ::PROTOBUF_NAMESPACE_ID::MethodOptions(*from._impl_.options_);
+  }
+  ::memcpy(&_impl_.client_streaming_, &from._impl_.client_streaming_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.server_streaming_) -
+    reinterpret_cast<char*>(&_impl_.client_streaming_)) + sizeof(_impl_.server_streaming_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodDescriptorProto)
+}
+
+inline void MethodDescriptorProto::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.input_type_){}
+    , decltype(_impl_.output_type_){}
+    , decltype(_impl_.options_){nullptr}
+    , decltype(_impl_.client_streaming_){false}
+    , decltype(_impl_.server_streaming_){false}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.input_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.input_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.output_type_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.output_type_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+MethodDescriptorProto::~MethodDescriptorProto() {
+  // @@protoc_insertion_point(destructor:google.protobuf.MethodDescriptorProto)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MethodDescriptorProto::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  _impl_.input_type_.Destroy();
+  _impl_.output_type_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.options_;
+}
+
+void MethodDescriptorProto::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MethodDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.name_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.input_type_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.output_type_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      GOOGLE_DCHECK(_impl_.options_ != nullptr);
+      _impl_.options_->Clear();
+    }
+  }
+  ::memset(&_impl_.client_streaming_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.server_streaming_) -
+      reinterpret_cast<char*>(&_impl_.client_streaming_)) + sizeof(_impl_.server_streaming_));
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.name");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string input_type = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_input_type();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.input_type");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string output_type = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_output_type();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.output_type");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.MethodOptions options = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr = ctx->ParseMessage(_internal_mutable_options(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool client_streaming = 5 [default = false];
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _Internal::set_has_client_streaming(&has_bits);
+          _impl_.client_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool server_streaming = 6 [default = false];
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 48)) {
+          _Internal::set_has_server_streaming(&has_bits);
+          _impl_.server_streaming_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* MethodDescriptorProto::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string name = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.MethodDescriptorProto.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // optional string input_type = 2;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_input_type().data(), static_cast<int>(this->_internal_input_type().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.MethodDescriptorProto.input_type");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_input_type(), target);
+  }
+
+  // optional string output_type = 3;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_output_type().data(), static_cast<int>(this->_internal_output_type().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.MethodDescriptorProto.output_type");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_output_type(), target);
+  }
+
+  // optional .google.protobuf.MethodOptions options = 4;
+  if (cached_has_bits & 0x00000008u) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(4, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
+  }
+
+  // optional bool client_streaming = 5 [default = false];
+  if (cached_has_bits & 0x00000010u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_client_streaming(), target);
+  }
+
+  // optional bool server_streaming = 6 [default = false];
+  if (cached_has_bits & 0x00000020u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(6, this->_internal_server_streaming(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodDescriptorProto)
+  return target;
+}
+
+size_t MethodDescriptorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    // optional string name = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_name());
+    }
+
+    // optional string input_type = 2;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_input_type());
+    }
+
+    // optional string output_type = 3;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_output_type());
+    }
+
+    // optional .google.protobuf.MethodOptions options = 4;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.options_);
+    }
+
+    // optional bool client_streaming = 5 [default = false];
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool server_streaming = 6 [default = false];
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MethodDescriptorProto::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MethodDescriptorProto::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodDescriptorProto::GetClassData() const { return &_class_data_; }
+
+
+void MethodDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MethodDescriptorProto*>(&to_msg);
+  auto& from = static_cast<const MethodDescriptorProto&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name(from._internal_name());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_input_type(from._internal_input_type());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_output_type(from._internal_output_type());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_mutable_options()->::PROTOBUF_NAMESPACE_ID::MethodOptions::MergeFrom(
+          from._internal_options());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_impl_.client_streaming_ = from._impl_.client_streaming_;
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_impl_.server_streaming_ = from._impl_.server_streaming_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodDescriptorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MethodDescriptorProto::IsInitialized() const {
+  if (_internal_has_options()) {
+    if (!_impl_.options_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.input_type_, lhs_arena,
+      &other->_impl_.input_type_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.output_type_, lhs_arena,
+      &other->_impl_.output_type_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(MethodDescriptorProto, _impl_.server_streaming_)
+      + sizeof(MethodDescriptorProto::_impl_.server_streaming_)
+      - PROTOBUF_FIELD_OFFSET(MethodDescriptorProto, _impl_.options_)>(
+          reinterpret_cast<char*>(&_impl_.options_),
+          reinterpret_cast<char*>(&other->_impl_.options_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MethodDescriptorProto::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[12]);
+}
+
+// ===================================================================
+
+class FileOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FileOptions>()._impl_._has_bits_);
+  static void set_has_java_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_java_outer_classname(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_java_multiple_files(HasBits* has_bits) {
+    (*has_bits)[0] |= 1024u;
+  }
+  static void set_has_java_generate_equals_and_hash(HasBits* has_bits) {
+    (*has_bits)[0] |= 2048u;
+  }
+  static void set_has_java_string_check_utf8(HasBits* has_bits) {
+    (*has_bits)[0] |= 4096u;
+  }
+  static void set_has_optimize_for(HasBits* has_bits) {
+    (*has_bits)[0] |= 262144u;
+  }
+  static void set_has_go_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_cc_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 8192u;
+  }
+  static void set_has_java_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 16384u;
+  }
+  static void set_has_py_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 32768u;
+  }
+  static void set_has_php_generic_services(HasBits* has_bits) {
+    (*has_bits)[0] |= 65536u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 131072u;
+  }
+  static void set_has_cc_enable_arenas(HasBits* has_bits) {
+    (*has_bits)[0] |= 524288u;
+  }
+  static void set_has_objc_class_prefix(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_csharp_namespace(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_swift_prefix(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_php_class_prefix(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
+  static void set_has_php_namespace(HasBits* has_bits) {
+    (*has_bits)[0] |= 128u;
+  }
+  static void set_has_php_metadata_namespace(HasBits* has_bits) {
+    (*has_bits)[0] |= 256u;
+  }
+  static void set_has_ruby_package(HasBits* has_bits) {
+    (*has_bits)[0] |= 512u;
+  }
+};
+
+FileOptions::FileOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FileOptions)
+}
+FileOptions::FileOptions(const FileOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FileOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.java_package_){}
+    , decltype(_impl_.java_outer_classname_){}
+    , decltype(_impl_.go_package_){}
+    , decltype(_impl_.objc_class_prefix_){}
+    , decltype(_impl_.csharp_namespace_){}
+    , decltype(_impl_.swift_prefix_){}
+    , decltype(_impl_.php_class_prefix_){}
+    , decltype(_impl_.php_namespace_){}
+    , decltype(_impl_.php_metadata_namespace_){}
+    , decltype(_impl_.ruby_package_){}
+    , decltype(_impl_.java_multiple_files_){}
+    , decltype(_impl_.java_generate_equals_and_hash_){}
+    , decltype(_impl_.java_string_check_utf8_){}
+    , decltype(_impl_.cc_generic_services_){}
+    , decltype(_impl_.java_generic_services_){}
+    , decltype(_impl_.py_generic_services_){}
+    , decltype(_impl_.php_generic_services_){}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.optimize_for_){}
+    , decltype(_impl_.cc_enable_arenas_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _impl_.java_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_java_package()) {
+    _this->_impl_.java_package_.Set(from._internal_java_package(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.java_outer_classname_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_java_outer_classname()) {
+    _this->_impl_.java_outer_classname_.Set(from._internal_java_outer_classname(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.go_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_go_package()) {
+    _this->_impl_.go_package_.Set(from._internal_go_package(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.objc_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_objc_class_prefix()) {
+    _this->_impl_.objc_class_prefix_.Set(from._internal_objc_class_prefix(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.csharp_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_csharp_namespace()) {
+    _this->_impl_.csharp_namespace_.Set(from._internal_csharp_namespace(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.swift_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_swift_prefix()) {
+    _this->_impl_.swift_prefix_.Set(from._internal_swift_prefix(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.php_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_php_class_prefix()) {
+    _this->_impl_.php_class_prefix_.Set(from._internal_php_class_prefix(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.php_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_php_namespace()) {
+    _this->_impl_.php_namespace_.Set(from._internal_php_namespace(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.php_metadata_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_php_metadata_namespace()) {
+    _this->_impl_.php_metadata_namespace_.Set(from._internal_php_metadata_namespace(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.ruby_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_ruby_package()) {
+    _this->_impl_.ruby_package_.Set(from._internal_ruby_package(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.java_multiple_files_, &from._impl_.java_multiple_files_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.cc_enable_arenas_) -
+    reinterpret_cast<char*>(&_impl_.java_multiple_files_)) + sizeof(_impl_.cc_enable_arenas_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FileOptions)
+}
+
+inline void FileOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.java_package_){}
+    , decltype(_impl_.java_outer_classname_){}
+    , decltype(_impl_.go_package_){}
+    , decltype(_impl_.objc_class_prefix_){}
+    , decltype(_impl_.csharp_namespace_){}
+    , decltype(_impl_.swift_prefix_){}
+    , decltype(_impl_.php_class_prefix_){}
+    , decltype(_impl_.php_namespace_){}
+    , decltype(_impl_.php_metadata_namespace_){}
+    , decltype(_impl_.ruby_package_){}
+    , decltype(_impl_.java_multiple_files_){false}
+    , decltype(_impl_.java_generate_equals_and_hash_){false}
+    , decltype(_impl_.java_string_check_utf8_){false}
+    , decltype(_impl_.cc_generic_services_){false}
+    , decltype(_impl_.java_generic_services_){false}
+    , decltype(_impl_.py_generic_services_){false}
+    , decltype(_impl_.php_generic_services_){false}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.optimize_for_){1}
+    , decltype(_impl_.cc_enable_arenas_){true}
+  };
+  _impl_.java_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.java_outer_classname_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.java_outer_classname_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.go_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.go_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.objc_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.objc_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.csharp_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.csharp_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.swift_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.swift_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.php_class_prefix_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_class_prefix_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.php_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.php_metadata_namespace_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.php_metadata_namespace_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.ruby_package_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.ruby_package_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+FileOptions::~FileOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FileOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FileOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+  _impl_.java_package_.Destroy();
+  _impl_.java_outer_classname_.Destroy();
+  _impl_.go_package_.Destroy();
+  _impl_.objc_class_prefix_.Destroy();
+  _impl_.csharp_namespace_.Destroy();
+  _impl_.swift_prefix_.Destroy();
+  _impl_.php_class_prefix_.Destroy();
+  _impl_.php_namespace_.Destroy();
+  _impl_.php_metadata_namespace_.Destroy();
+  _impl_.ruby_package_.Destroy();
+}
+
+void FileOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FileOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.java_package_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.java_outer_classname_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.go_package_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _impl_.objc_class_prefix_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _impl_.csharp_namespace_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _impl_.swift_prefix_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _impl_.php_class_prefix_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000080u) {
+      _impl_.php_namespace_.ClearNonDefaultToEmpty();
+    }
+  }
+  if (cached_has_bits & 0x00000300u) {
+    if (cached_has_bits & 0x00000100u) {
+      _impl_.php_metadata_namespace_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000200u) {
+      _impl_.ruby_package_.ClearNonDefaultToEmpty();
+    }
+  }
+  if (cached_has_bits & 0x0000fc00u) {
+    ::memset(&_impl_.java_multiple_files_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.py_generic_services_) -
+        reinterpret_cast<char*>(&_impl_.java_multiple_files_)) + sizeof(_impl_.py_generic_services_));
+  }
+  if (cached_has_bits & 0x000f0000u) {
+    ::memset(&_impl_.php_generic_services_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.deprecated_) -
+        reinterpret_cast<char*>(&_impl_.php_generic_services_)) + sizeof(_impl_.deprecated_));
+    _impl_.optimize_for_ = 1;
+    _impl_.cc_enable_arenas_ = true;
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FileOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional string java_package = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_java_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.java_package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string java_outer_classname = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          auto str = _internal_mutable_java_outer_classname();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.java_outer_classname");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 72)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_IsValid(val))) {
+            _internal_set_optimize_for(static_cast<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(9, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_multiple_files = 10 [default = false];
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          _Internal::set_has_java_multiple_files(&has_bits);
+          _impl_.java_multiple_files_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string go_package = 11;
+      case 11:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 90)) {
+          auto str = _internal_mutable_go_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.go_package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool cc_generic_services = 16 [default = false];
+      case 16:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 128)) {
+          _Internal::set_has_cc_generic_services(&has_bits);
+          _impl_.cc_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_generic_services = 17 [default = false];
+      case 17:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 136)) {
+          _Internal::set_has_java_generic_services(&has_bits);
+          _impl_.java_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool py_generic_services = 18 [default = false];
+      case 18:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 144)) {
+          _Internal::set_has_py_generic_services(&has_bits);
+          _impl_.py_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+      case 20:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 160)) {
+          _Internal::set_has_java_generate_equals_and_hash(&has_bits);
+          _impl_.java_generate_equals_and_hash_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 23 [default = false];
+      case 23:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 184)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool java_string_check_utf8 = 27 [default = false];
+      case 27:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 216)) {
+          _Internal::set_has_java_string_check_utf8(&has_bits);
+          _impl_.java_string_check_utf8_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool cc_enable_arenas = 31 [default = true];
+      case 31:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 248)) {
+          _Internal::set_has_cc_enable_arenas(&has_bits);
+          _impl_.cc_enable_arenas_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string objc_class_prefix = 36;
+      case 36:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_objc_class_prefix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.objc_class_prefix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string csharp_namespace = 37;
+      case 37:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          auto str = _internal_mutable_csharp_namespace();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.csharp_namespace");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string swift_prefix = 39;
+      case 39:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          auto str = _internal_mutable_swift_prefix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.swift_prefix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string php_class_prefix = 40;
+      case 40:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          auto str = _internal_mutable_php_class_prefix();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_class_prefix");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string php_namespace = 41;
+      case 41:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          auto str = _internal_mutable_php_namespace();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_namespace");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool php_generic_services = 42 [default = false];
+      case 42:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          _Internal::set_has_php_generic_services(&has_bits);
+          _impl_.php_generic_services_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string php_metadata_namespace = 44;
+      case 44:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 98)) {
+          auto str = _internal_mutable_php_metadata_namespace();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_metadata_namespace");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string ruby_package = 45;
+      case 45:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 106)) {
+          auto str = _internal_mutable_ruby_package();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.ruby_package");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FileOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string java_package = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_java_package().data(), static_cast<int>(this->_internal_java_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.java_package");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_java_package(), target);
+  }
+
+  // optional string java_outer_classname = 8;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_java_outer_classname().data(), static_cast<int>(this->_internal_java_outer_classname().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.java_outer_classname");
+    target = stream->WriteStringMaybeAliased(
+        8, this->_internal_java_outer_classname(), target);
+  }
+
+  // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+  if (cached_has_bits & 0x00040000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      9, this->_internal_optimize_for(), target);
+  }
+
+  // optional bool java_multiple_files = 10 [default = false];
+  if (cached_has_bits & 0x00000400u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(10, this->_internal_java_multiple_files(), target);
+  }
+
+  // optional string go_package = 11;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_go_package().data(), static_cast<int>(this->_internal_go_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.go_package");
+    target = stream->WriteStringMaybeAliased(
+        11, this->_internal_go_package(), target);
+  }
+
+  // optional bool cc_generic_services = 16 [default = false];
+  if (cached_has_bits & 0x00002000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(16, this->_internal_cc_generic_services(), target);
+  }
+
+  // optional bool java_generic_services = 17 [default = false];
+  if (cached_has_bits & 0x00004000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(17, this->_internal_java_generic_services(), target);
+  }
+
+  // optional bool py_generic_services = 18 [default = false];
+  if (cached_has_bits & 0x00008000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(18, this->_internal_py_generic_services(), target);
+  }
+
+  // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+  if (cached_has_bits & 0x00000800u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(20, this->_internal_java_generate_equals_and_hash(), target);
+  }
+
+  // optional bool deprecated = 23 [default = false];
+  if (cached_has_bits & 0x00020000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(23, this->_internal_deprecated(), target);
+  }
+
+  // optional bool java_string_check_utf8 = 27 [default = false];
+  if (cached_has_bits & 0x00001000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(27, this->_internal_java_string_check_utf8(), target);
+  }
+
+  // optional bool cc_enable_arenas = 31 [default = true];
+  if (cached_has_bits & 0x00080000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(31, this->_internal_cc_enable_arenas(), target);
+  }
+
+  // optional string objc_class_prefix = 36;
+  if (cached_has_bits & 0x00000008u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_objc_class_prefix().data(), static_cast<int>(this->_internal_objc_class_prefix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.objc_class_prefix");
+    target = stream->WriteStringMaybeAliased(
+        36, this->_internal_objc_class_prefix(), target);
+  }
+
+  // optional string csharp_namespace = 37;
+  if (cached_has_bits & 0x00000010u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_csharp_namespace().data(), static_cast<int>(this->_internal_csharp_namespace().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.csharp_namespace");
+    target = stream->WriteStringMaybeAliased(
+        37, this->_internal_csharp_namespace(), target);
+  }
+
+  // optional string swift_prefix = 39;
+  if (cached_has_bits & 0x00000020u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_swift_prefix().data(), static_cast<int>(this->_internal_swift_prefix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.swift_prefix");
+    target = stream->WriteStringMaybeAliased(
+        39, this->_internal_swift_prefix(), target);
+  }
+
+  // optional string php_class_prefix = 40;
+  if (cached_has_bits & 0x00000040u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_php_class_prefix().data(), static_cast<int>(this->_internal_php_class_prefix().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.php_class_prefix");
+    target = stream->WriteStringMaybeAliased(
+        40, this->_internal_php_class_prefix(), target);
+  }
+
+  // optional string php_namespace = 41;
+  if (cached_has_bits & 0x00000080u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_php_namespace().data(), static_cast<int>(this->_internal_php_namespace().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.php_namespace");
+    target = stream->WriteStringMaybeAliased(
+        41, this->_internal_php_namespace(), target);
+  }
+
+  // optional bool php_generic_services = 42 [default = false];
+  if (cached_has_bits & 0x00010000u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(42, this->_internal_php_generic_services(), target);
+  }
+
+  // optional string php_metadata_namespace = 44;
+  if (cached_has_bits & 0x00000100u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_php_metadata_namespace().data(), static_cast<int>(this->_internal_php_metadata_namespace().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.php_metadata_namespace");
+    target = stream->WriteStringMaybeAliased(
+        44, this->_internal_php_metadata_namespace(), target);
+  }
+
+  // optional string ruby_package = 45;
+  if (cached_has_bits & 0x00000200u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_ruby_package().data(), static_cast<int>(this->_internal_ruby_package().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.ruby_package");
+    target = stream->WriteStringMaybeAliased(
+        45, this->_internal_ruby_package(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileOptions)
+  return target;
+}
+
+size_t FileOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    // optional string java_package = 1;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_java_package());
+    }
+
+    // optional string java_outer_classname = 8;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_java_outer_classname());
+    }
+
+    // optional string go_package = 11;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_go_package());
+    }
+
+    // optional string objc_class_prefix = 36;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_objc_class_prefix());
+    }
+
+    // optional string csharp_namespace = 37;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_csharp_namespace());
+    }
+
+    // optional string swift_prefix = 39;
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_swift_prefix());
+    }
+
+    // optional string php_class_prefix = 40;
+    if (cached_has_bits & 0x00000040u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_php_class_prefix());
+    }
+
+    // optional string php_namespace = 41;
+    if (cached_has_bits & 0x00000080u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_php_namespace());
+    }
+
+  }
+  if (cached_has_bits & 0x0000ff00u) {
+    // optional string php_metadata_namespace = 44;
+    if (cached_has_bits & 0x00000100u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_php_metadata_namespace());
+    }
+
+    // optional string ruby_package = 45;
+    if (cached_has_bits & 0x00000200u) {
+      total_size += 2 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_ruby_package());
+    }
+
+    // optional bool java_multiple_files = 10 [default = false];
+    if (cached_has_bits & 0x00000400u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
+    if (cached_has_bits & 0x00000800u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool java_string_check_utf8 = 27 [default = false];
+    if (cached_has_bits & 0x00001000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool cc_generic_services = 16 [default = false];
+    if (cached_has_bits & 0x00002000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool java_generic_services = 17 [default = false];
+    if (cached_has_bits & 0x00004000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool py_generic_services = 18 [default = false];
+    if (cached_has_bits & 0x00008000u) {
+      total_size += 2 + 1;
+    }
+
+  }
+  if (cached_has_bits & 0x000f0000u) {
+    // optional bool php_generic_services = 42 [default = false];
+    if (cached_has_bits & 0x00010000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool deprecated = 23 [default = false];
+    if (cached_has_bits & 0x00020000u) {
+      total_size += 2 + 1;
+    }
+
+    // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+    if (cached_has_bits & 0x00040000u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_optimize_for());
+    }
+
+    // optional bool cc_enable_arenas = 31 [default = true];
+    if (cached_has_bits & 0x00080000u) {
+      total_size += 2 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FileOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FileOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileOptions::GetClassData() const { return &_class_data_; }
+
+
+void FileOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FileOptions*>(&to_msg);
+  auto& from = static_cast<const FileOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x000000ffu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_java_package(from._internal_java_package());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_java_outer_classname(from._internal_java_outer_classname());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_go_package(from._internal_go_package());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_internal_set_objc_class_prefix(from._internal_objc_class_prefix());
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_internal_set_csharp_namespace(from._internal_csharp_namespace());
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_internal_set_swift_prefix(from._internal_swift_prefix());
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _this->_internal_set_php_class_prefix(from._internal_php_class_prefix());
+    }
+    if (cached_has_bits & 0x00000080u) {
+      _this->_internal_set_php_namespace(from._internal_php_namespace());
+    }
+  }
+  if (cached_has_bits & 0x0000ff00u) {
+    if (cached_has_bits & 0x00000100u) {
+      _this->_internal_set_php_metadata_namespace(from._internal_php_metadata_namespace());
+    }
+    if (cached_has_bits & 0x00000200u) {
+      _this->_internal_set_ruby_package(from._internal_ruby_package());
+    }
+    if (cached_has_bits & 0x00000400u) {
+      _this->_impl_.java_multiple_files_ = from._impl_.java_multiple_files_;
+    }
+    if (cached_has_bits & 0x00000800u) {
+      _this->_impl_.java_generate_equals_and_hash_ = from._impl_.java_generate_equals_and_hash_;
+    }
+    if (cached_has_bits & 0x00001000u) {
+      _this->_impl_.java_string_check_utf8_ = from._impl_.java_string_check_utf8_;
+    }
+    if (cached_has_bits & 0x00002000u) {
+      _this->_impl_.cc_generic_services_ = from._impl_.cc_generic_services_;
+    }
+    if (cached_has_bits & 0x00004000u) {
+      _this->_impl_.java_generic_services_ = from._impl_.java_generic_services_;
+    }
+    if (cached_has_bits & 0x00008000u) {
+      _this->_impl_.py_generic_services_ = from._impl_.py_generic_services_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  if (cached_has_bits & 0x000f0000u) {
+    if (cached_has_bits & 0x00010000u) {
+      _this->_impl_.php_generic_services_ = from._impl_.php_generic_services_;
+    }
+    if (cached_has_bits & 0x00020000u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00040000u) {
+      _this->_impl_.optimize_for_ = from._impl_.optimize_for_;
+    }
+    if (cached_has_bits & 0x00080000u) {
+      _this->_impl_.cc_enable_arenas_ = from._impl_.cc_enable_arenas_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FileOptions::CopyFrom(const FileOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FileOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void FileOptions::InternalSwap(FileOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.java_package_, lhs_arena,
+      &other->_impl_.java_package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.java_outer_classname_, lhs_arena,
+      &other->_impl_.java_outer_classname_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.go_package_, lhs_arena,
+      &other->_impl_.go_package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.objc_class_prefix_, lhs_arena,
+      &other->_impl_.objc_class_prefix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.csharp_namespace_, lhs_arena,
+      &other->_impl_.csharp_namespace_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.swift_prefix_, lhs_arena,
+      &other->_impl_.swift_prefix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.php_class_prefix_, lhs_arena,
+      &other->_impl_.php_class_prefix_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.php_namespace_, lhs_arena,
+      &other->_impl_.php_namespace_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.php_metadata_namespace_, lhs_arena,
+      &other->_impl_.php_metadata_namespace_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.ruby_package_, lhs_arena,
+      &other->_impl_.ruby_package_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FileOptions, _impl_.deprecated_)
+      + sizeof(FileOptions::_impl_.deprecated_)
+      - PROTOBUF_FIELD_OFFSET(FileOptions, _impl_.java_multiple_files_)>(
+          reinterpret_cast<char*>(&_impl_.java_multiple_files_),
+          reinterpret_cast<char*>(&other->_impl_.java_multiple_files_));
+  swap(_impl_.optimize_for_, other->_impl_.optimize_for_);
+  swap(_impl_.cc_enable_arenas_, other->_impl_.cc_enable_arenas_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FileOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[13]);
+}
+
+// ===================================================================
+
+class MessageOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<MessageOptions>()._impl_._has_bits_);
+  static void set_has_message_set_wire_format(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_no_standard_descriptor_accessor(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_map_entry(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+};
+
+MessageOptions::MessageOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.MessageOptions)
+}
+MessageOptions::MessageOptions(const MessageOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MessageOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.message_set_wire_format_){}
+    , decltype(_impl_.no_standard_descriptor_accessor_){}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.map_entry_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.message_set_wire_format_, &from._impl_.message_set_wire_format_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.map_entry_) -
+    reinterpret_cast<char*>(&_impl_.message_set_wire_format_)) + sizeof(_impl_.map_entry_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.MessageOptions)
+}
+
+inline void MessageOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.message_set_wire_format_){false}
+    , decltype(_impl_.no_standard_descriptor_accessor_){false}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.map_entry_){false}
+  };
+}
+
+MessageOptions::~MessageOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.MessageOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MessageOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void MessageOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MessageOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MessageOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  ::memset(&_impl_.message_set_wire_format_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.map_entry_) -
+      reinterpret_cast<char*>(&_impl_.message_set_wire_format_)) + sizeof(_impl_.map_entry_));
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MessageOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool message_set_wire_format = 1 [default = false];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_message_set_wire_format(&has_bits);
+          _impl_.message_set_wire_format_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool no_standard_descriptor_accessor = 2 [default = false];
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_no_standard_descriptor_accessor(&has_bits);
+          _impl_.no_standard_descriptor_accessor_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 3 [default = false];
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool map_entry = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          _Internal::set_has_map_entry(&has_bits);
+          _impl_.map_entry_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* MessageOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool message_set_wire_format = 1 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_message_set_wire_format(), target);
+  }
+
+  // optional bool no_standard_descriptor_accessor = 2 [default = false];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_no_standard_descriptor_accessor(), target);
+  }
+
+  // optional bool deprecated = 3 [default = false];
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+  }
+
+  // optional bool map_entry = 7;
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(7, this->_internal_map_entry(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MessageOptions)
+  return target;
+}
+
+size_t MessageOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    // optional bool message_set_wire_format = 1 [default = false];
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool no_standard_descriptor_accessor = 2 [default = false];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool deprecated = 3 [default = false];
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool map_entry = 7;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MessageOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MessageOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MessageOptions::GetClassData() const { return &_class_data_; }
+
+
+void MessageOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MessageOptions*>(&to_msg);
+  auto& from = static_cast<const MessageOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000000fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.message_set_wire_format_ = from._impl_.message_set_wire_format_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.no_standard_descriptor_accessor_ = from._impl_.no_standard_descriptor_accessor_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.map_entry_ = from._impl_.map_entry_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MessageOptions::CopyFrom(const MessageOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MessageOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MessageOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void MessageOptions::InternalSwap(MessageOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(MessageOptions, _impl_.map_entry_)
+      + sizeof(MessageOptions::_impl_.map_entry_)
+      - PROTOBUF_FIELD_OFFSET(MessageOptions, _impl_.message_set_wire_format_)>(
+          reinterpret_cast<char*>(&_impl_.message_set_wire_format_),
+          reinterpret_cast<char*>(&other->_impl_.message_set_wire_format_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MessageOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[14]);
+}
+
+// ===================================================================
+
+class FieldOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<FieldOptions>()._impl_._has_bits_);
+  static void set_has_ctype(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_packed(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+  static void set_has_jstype(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_lazy(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_unverified_lazy(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_weak(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
+};
+
+FieldOptions::FieldOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldOptions)
+}
+FieldOptions::FieldOptions(const FieldOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FieldOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.ctype_){}
+    , decltype(_impl_.jstype_){}
+    , decltype(_impl_.packed_){}
+    , decltype(_impl_.lazy_){}
+    , decltype(_impl_.unverified_lazy_){}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.weak_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.ctype_, &from._impl_.ctype_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.weak_) -
+    reinterpret_cast<char*>(&_impl_.ctype_)) + sizeof(_impl_.weak_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldOptions)
+}
+
+inline void FieldOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.ctype_){0}
+    , decltype(_impl_.jstype_){0}
+    , decltype(_impl_.packed_){false}
+    , decltype(_impl_.lazy_){false}
+    , decltype(_impl_.unverified_lazy_){false}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.weak_){false}
+  };
+}
+
+FieldOptions::~FieldOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FieldOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void FieldOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FieldOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000007fu) {
+    ::memset(&_impl_.ctype_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.weak_) -
+        reinterpret_cast<char*>(&_impl_.ctype_)) + sizeof(_impl_.weak_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FieldOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_IsValid(val))) {
+            _internal_set_ctype(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(1, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool packed = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_packed(&has_bits);
+          _impl_.packed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 3 [default = false];
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool lazy = 5 [default = false];
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _Internal::set_has_lazy(&has_bits);
+          _impl_.lazy_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 48)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_IsValid(val))) {
+            _internal_set_jstype(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(6, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool weak = 10 [default = false];
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 80)) {
+          _Internal::set_has_weak(&has_bits);
+          _impl_.weak_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool unverified_lazy = 15 [default = false];
+      case 15:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 120)) {
+          _Internal::set_has_unverified_lazy(&has_bits);
+          _impl_.unverified_lazy_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FieldOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      1, this->_internal_ctype(), target);
+  }
+
+  // optional bool packed = 2;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_packed(), target);
+  }
+
+  // optional bool deprecated = 3 [default = false];
+  if (cached_has_bits & 0x00000020u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+  }
+
+  // optional bool lazy = 5 [default = false];
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_lazy(), target);
+  }
+
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      6, this->_internal_jstype(), target);
+  }
+
+  // optional bool weak = 10 [default = false];
+  if (cached_has_bits & 0x00000040u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(10, this->_internal_weak(), target);
+  }
+
+  // optional bool unverified_lazy = 15 [default = false];
+  if (cached_has_bits & 0x00000010u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(15, this->_internal_unverified_lazy(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldOptions)
+  return target;
+}
+
+size_t FieldOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000007fu) {
+    // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_ctype());
+    }
+
+    // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_jstype());
+    }
+
+    // optional bool packed = 2;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool lazy = 5 [default = false];
+    if (cached_has_bits & 0x00000008u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool unverified_lazy = 15 [default = false];
+    if (cached_has_bits & 0x00000010u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool deprecated = 3 [default = false];
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool weak = 10 [default = false];
+    if (cached_has_bits & 0x00000040u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FieldOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldOptions::GetClassData() const { return &_class_data_; }
+
+
+void FieldOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FieldOptions*>(&to_msg);
+  auto& from = static_cast<const FieldOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000007fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.ctype_ = from._impl_.ctype_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.jstype_ = from._impl_.jstype_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.packed_ = from._impl_.packed_;
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.lazy_ = from._impl_.lazy_;
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_impl_.unverified_lazy_ = from._impl_.unverified_lazy_;
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00000040u) {
+      _this->_impl_.weak_ = from._impl_.weak_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FieldOptions::CopyFrom(const FieldOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void FieldOptions::InternalSwap(FieldOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(FieldOptions, _impl_.weak_)
+      + sizeof(FieldOptions::_impl_.weak_)
+      - PROTOBUF_FIELD_OFFSET(FieldOptions, _impl_.ctype_)>(
+          reinterpret_cast<char*>(&_impl_.ctype_),
+          reinterpret_cast<char*>(&other->_impl_.ctype_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FieldOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[15]);
+}
+
+// ===================================================================
+
+class OneofOptions::_Internal {
+ public:
+};
+
+OneofOptions::OneofOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofOptions)
+}
+OneofOptions::OneofOptions(const OneofOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  OneofOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofOptions)
+}
+
+inline void OneofOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+OneofOptions::~OneofOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.OneofOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void OneofOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void OneofOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void OneofOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* OneofOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* OneofOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofOptions)
+  return target;
+}
+
+size_t OneofOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData OneofOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    OneofOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofOptions::GetClassData() const { return &_class_data_; }
+
+
+void OneofOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<OneofOptions*>(&to_msg);
+  auto& from = static_cast<const OneofOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void OneofOptions::CopyFrom(const OneofOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool OneofOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void OneofOptions::InternalSwap(OneofOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata OneofOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[16]);
+}
+
+// ===================================================================
+
+class EnumOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumOptions>()._impl_._has_bits_);
+  static void set_has_allow_alias(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+EnumOptions::EnumOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumOptions)
+}
+EnumOptions::EnumOptions(const EnumOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.allow_alias_){}
+    , decltype(_impl_.deprecated_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.allow_alias_, &from._impl_.allow_alias_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.deprecated_) -
+    reinterpret_cast<char*>(&_impl_.allow_alias_)) + sizeof(_impl_.deprecated_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumOptions)
+}
+
+inline void EnumOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.allow_alias_){false}
+    , decltype(_impl_.deprecated_){false}
+  };
+}
+
+EnumOptions::~EnumOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void EnumOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  ::memset(&_impl_.allow_alias_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.deprecated_) -
+      reinterpret_cast<char*>(&_impl_.allow_alias_)) + sizeof(_impl_.deprecated_));
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool allow_alias = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_allow_alias(&has_bits);
+          _impl_.allow_alias_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bool deprecated = 3 [default = false];
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool allow_alias = 2;
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_allow_alias(), target);
+  }
+
+  // optional bool deprecated = 3 [default = false];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumOptions)
+  return target;
+}
+
+size_t EnumOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional bool allow_alias = 2;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool deprecated = 3 [default = false];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 + 1;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumOptions::GetClassData() const { return &_class_data_; }
+
+
+void EnumOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumOptions*>(&to_msg);
+  auto& from = static_cast<const EnumOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.allow_alias_ = from._impl_.allow_alias_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumOptions::CopyFrom(const EnumOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void EnumOptions::InternalSwap(EnumOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(EnumOptions, _impl_.deprecated_)
+      + sizeof(EnumOptions::_impl_.deprecated_)
+      - PROTOBUF_FIELD_OFFSET(EnumOptions, _impl_.allow_alias_)>(
+          reinterpret_cast<char*>(&_impl_.allow_alias_),
+          reinterpret_cast<char*>(&other->_impl_.allow_alias_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[17]);
+}
+
+// ===================================================================
+
+class EnumValueOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<EnumValueOptions>()._impl_._has_bits_);
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+EnumValueOptions::EnumValueOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueOptions)
+}
+EnumValueOptions::EnumValueOptions(const EnumValueOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumValueOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.deprecated_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_impl_.deprecated_ = from._impl_.deprecated_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueOptions)
+}
+
+inline void EnumValueOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.deprecated_){false}
+  };
+}
+
+EnumValueOptions::~EnumValueOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValueOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumValueOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void EnumValueOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumValueOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumValueOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool deprecated = 1 [default = false];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumValueOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool deprecated = 1 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_deprecated(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueOptions)
+  return target;
+}
+
+size_t EnumValueOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // optional bool deprecated = 1 [default = false];
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    total_size += 1 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValueOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumValueOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueOptions::GetClassData() const { return &_class_data_; }
+
+
+void EnumValueOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumValueOptions*>(&to_msg);
+  auto& from = static_cast<const EnumValueOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  if (from._internal_has_deprecated()) {
+    _this->_internal_set_deprecated(from._internal_deprecated());
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumValueOptions::CopyFrom(const EnumValueOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValueOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void EnumValueOptions::InternalSwap(EnumValueOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  swap(_impl_.deprecated_, other->_impl_.deprecated_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumValueOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[18]);
+}
+
+// ===================================================================
+
+class ServiceOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<ServiceOptions>()._impl_._has_bits_);
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+};
+
+ServiceOptions::ServiceOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceOptions)
+}
+ServiceOptions::ServiceOptions(const ServiceOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ServiceOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.deprecated_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_impl_.deprecated_ = from._impl_.deprecated_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceOptions)
+}
+
+inline void ServiceOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.deprecated_){false}
+  };
+}
+
+ServiceOptions::~ServiceOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ServiceOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ServiceOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void ServiceOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ServiceOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  _impl_.deprecated_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ServiceOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool deprecated = 33 [default = false];
+      case 33:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ServiceOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool deprecated = 33 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceOptions)
+  return target;
+}
+
+size_t ServiceOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // optional bool deprecated = 33 [default = false];
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    total_size += 2 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ServiceOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ServiceOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceOptions::GetClassData() const { return &_class_data_; }
+
+
+void ServiceOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ServiceOptions*>(&to_msg);
+  auto& from = static_cast<const ServiceOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  if (from._internal_has_deprecated()) {
+    _this->_internal_set_deprecated(from._internal_deprecated());
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ServiceOptions::CopyFrom(const ServiceOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ServiceOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void ServiceOptions::InternalSwap(ServiceOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  swap(_impl_.deprecated_, other->_impl_.deprecated_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ServiceOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[19]);
+}
+
+// ===================================================================
+
+class MethodOptions::_Internal {
+ public:
+  using HasBits = decltype(std::declval<MethodOptions>()._impl_._has_bits_);
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_idempotency_level(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+MethodOptions::MethodOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodOptions)
+}
+MethodOptions::MethodOptions(const MethodOptions& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  MethodOptions* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{}
+    , decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){from._impl_.uninterpreted_option_}
+    , decltype(_impl_.deprecated_){}
+    , decltype(_impl_.idempotency_level_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  ::memcpy(&_impl_.deprecated_, &from._impl_.deprecated_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.idempotency_level_) -
+    reinterpret_cast<char*>(&_impl_.deprecated_)) + sizeof(_impl_.idempotency_level_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodOptions)
+}
+
+inline void MethodOptions::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_._extensions_)*/{::_pbi::ArenaInitialized(), arena}
+    , decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.uninterpreted_option_){arena}
+    , decltype(_impl_.deprecated_){false}
+    , decltype(_impl_.idempotency_level_){0}
+  };
+}
+
+MethodOptions::~MethodOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.MethodOptions)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void MethodOptions::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_._extensions_.~ExtensionSet();
+  _impl_.uninterpreted_option_.~RepeatedPtrField();
+}
+
+void MethodOptions::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void MethodOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodOptions)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_._extensions_.Clear();
+  _impl_.uninterpreted_option_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    ::memset(&_impl_.deprecated_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.idempotency_level_) -
+        reinterpret_cast<char*>(&_impl_.deprecated_)) + sizeof(_impl_.idempotency_level_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* MethodOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // optional bool deprecated = 33 [default = false];
+      case 33:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _Internal::set_has_deprecated(&has_bits);
+          _impl_.deprecated_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+      case 34:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_IsValid(val))) {
+            _internal_set_idempotency_level(static_cast<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>(val));
+          } else {
+            ::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(34, val, mutable_unknown_fields());
+          }
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          ptr -= 2;
+          do {
+            ptr += 2;
+            ptr = ctx->ParseMessage(_internal_add_uninterpreted_option(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<7994>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    if ((8000u <= tag)) {
+      ptr = _impl_._extensions_.ParseField(tag, ptr, internal_default_instance(), &_internal_metadata_, ctx);
+      CHK_(ptr != nullptr);
+      continue;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* MethodOptions::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional bool deprecated = 33 [default = false];
+  if (cached_has_bits & 0x00000001u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
+  }
+
+  // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      34, this->_internal_idempotency_level(), target);
+  }
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _impl_._extensions_._InternalSerialize(
+  internal_default_instance(), 1000, 536870912, target, stream);
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodOptions)
+  return target;
+}
+
+size_t MethodOptions::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions)
+  size_t total_size = 0;
+
+  total_size += _impl_._extensions_.ByteSize();
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2UL * this->_internal_uninterpreted_option_size();
+  for (const auto& msg : this->_impl_.uninterpreted_option_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional bool deprecated = 33 [default = false];
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 2 + 1;
+    }
+
+    // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 2 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_idempotency_level());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData MethodOptions::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    MethodOptions::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodOptions::GetClassData() const { return &_class_data_; }
+
+
+void MethodOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<MethodOptions*>(&to_msg);
+  auto& from = static_cast<const MethodOptions&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.uninterpreted_option_.MergeFrom(from._impl_.uninterpreted_option_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_impl_.deprecated_ = from._impl_.deprecated_;
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.idempotency_level_ = from._impl_.idempotency_level_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_impl_._extensions_.MergeFrom(internal_default_instance(), from._impl_._extensions_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void MethodOptions::CopyFrom(const MethodOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool MethodOptions::IsInitialized() const {
+  if (!_impl_._extensions_.IsInitialized()) {
+    return false;
+  }
+
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.uninterpreted_option_))
+    return false;
+  return true;
+}
+
+void MethodOptions::InternalSwap(MethodOptions* other) {
+  using std::swap;
+  _impl_._extensions_.InternalSwap(&other->_impl_._extensions_);
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.uninterpreted_option_.InternalSwap(&other->_impl_.uninterpreted_option_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(MethodOptions, _impl_.idempotency_level_)
+      + sizeof(MethodOptions::_impl_.idempotency_level_)
+      - PROTOBUF_FIELD_OFFSET(MethodOptions, _impl_.deprecated_)>(
+          reinterpret_cast<char*>(&_impl_.deprecated_),
+          reinterpret_cast<char*>(&other->_impl_.deprecated_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata MethodOptions::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[20]);
+}
+
+// ===================================================================
+
+class UninterpretedOption_NamePart::_Internal {
+ public:
+  using HasBits = decltype(std::declval<UninterpretedOption_NamePart>()._impl_._has_bits_);
+  static void set_has_name_part(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_is_extension(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static bool MissingRequiredFields(const HasBits& has_bits) {
+    return ((has_bits[0] & 0x00000003) ^ 0x00000003) != 0;
+  }
+};
+
+UninterpretedOption_NamePart::UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption.NamePart)
+}
+UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UninterpretedOption_NamePart* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_part_){}
+    , decltype(_impl_.is_extension_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_part_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_name_part()) {
+    _this->_impl_.name_part_.Set(from._internal_name_part(), 
+      _this->GetArenaForAllocation());
+  }
+  _this->_impl_.is_extension_ = from._impl_.is_extension_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption.NamePart)
+}
+
+inline void UninterpretedOption_NamePart::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_part_){}
+    , decltype(_impl_.is_extension_){false}
+  };
+  _impl_.name_part_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_part_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+UninterpretedOption_NamePart::~UninterpretedOption_NamePart() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption.NamePart)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UninterpretedOption_NamePart::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_part_.Destroy();
+}
+
+void UninterpretedOption_NamePart::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UninterpretedOption_NamePart::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption.NamePart)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    _impl_.name_part_.ClearNonDefaultToEmpty();
+  }
+  _impl_.is_extension_ = false;
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // required string name_part = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name_part();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.NamePart.name_part");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // required bool is_extension = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _Internal::set_has_is_extension(&has_bits);
+          _impl_.is_extension_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UninterpretedOption_NamePart::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // required string name_part = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_name_part().data(), static_cast<int>(this->_internal_name_part().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.UninterpretedOption.NamePart.name_part");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name_part(), target);
+  }
+
+  // required bool is_extension = 2;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_is_extension(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption.NamePart)
+  return target;
+}
+
+size_t UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const {
+// @@protoc_insertion_point(required_fields_byte_size_fallback_start:google.protobuf.UninterpretedOption.NamePart)
+  size_t total_size = 0;
+
+  if (_internal_has_name_part()) {
+    // required string name_part = 1;
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name_part());
+  }
+
+  if (_internal_has_is_extension()) {
+    // required bool is_extension = 2;
+    total_size += 1 + 1;
+  }
+
+  return total_size;
+}
+size_t UninterpretedOption_NamePart::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart)
+  size_t total_size = 0;
+
+  if (((_impl_._has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) {  // All required fields are present.
+    // required string name_part = 1;
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name_part());
+
+    // required bool is_extension = 2;
+    total_size += 1 + 1;
+
+  } else {
+    total_size += RequiredFieldsByteSizeFallback();
+  }
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UninterpretedOption_NamePart::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UninterpretedOption_NamePart::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption_NamePart::GetClassData() const { return &_class_data_; }
+
+
+void UninterpretedOption_NamePart::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UninterpretedOption_NamePart*>(&to_msg);
+  auto& from = static_cast<const UninterpretedOption_NamePart&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_name_part(from._internal_name_part());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.is_extension_ = from._impl_.is_extension_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption.NamePart)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UninterpretedOption_NamePart::IsInitialized() const {
+  if (_Internal::MissingRequiredFields(_impl_._has_bits_)) return false;
+  return true;
+}
+
+void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_part_, lhs_arena,
+      &other->_impl_.name_part_, rhs_arena
+  );
+  swap(_impl_.is_extension_, other->_impl_.is_extension_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption_NamePart::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[21]);
+}
+
+// ===================================================================
+
+class UninterpretedOption::_Internal {
+ public:
+  using HasBits = decltype(std::declval<UninterpretedOption>()._impl_._has_bits_);
+  static void set_has_identifier_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_positive_int_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 8u;
+  }
+  static void set_has_negative_int_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 16u;
+  }
+  static void set_has_double_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_string_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_aggregate_value(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+};
+
+UninterpretedOption::UninterpretedOption(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption)
+}
+UninterpretedOption::UninterpretedOption(const UninterpretedOption& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UninterpretedOption* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){from._impl_.name_}
+    , decltype(_impl_.identifier_value_){}
+    , decltype(_impl_.string_value_){}
+    , decltype(_impl_.aggregate_value_){}
+    , decltype(_impl_.positive_int_value_){}
+    , decltype(_impl_.negative_int_value_){}
+    , decltype(_impl_.double_value_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.identifier_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_identifier_value()) {
+    _this->_impl_.identifier_value_.Set(from._internal_identifier_value(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.string_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_string_value()) {
+    _this->_impl_.string_value_.Set(from._internal_string_value(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.aggregate_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_aggregate_value()) {
+    _this->_impl_.aggregate_value_.Set(from._internal_aggregate_value(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.positive_int_value_, &from._impl_.positive_int_value_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.double_value_) -
+    reinterpret_cast<char*>(&_impl_.positive_int_value_)) + sizeof(_impl_.double_value_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption)
+}
+
+inline void UninterpretedOption::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.name_){arena}
+    , decltype(_impl_.identifier_value_){}
+    , decltype(_impl_.string_value_){}
+    , decltype(_impl_.aggregate_value_){}
+    , decltype(_impl_.positive_int_value_){uint64_t{0u}}
+    , decltype(_impl_.negative_int_value_){int64_t{0}}
+    , decltype(_impl_.double_value_){0}
+  };
+  _impl_.identifier_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.identifier_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.string_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.string_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.aggregate_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.aggregate_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+UninterpretedOption::~UninterpretedOption() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UninterpretedOption::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.~RepeatedPtrField();
+  _impl_.identifier_value_.Destroy();
+  _impl_.string_value_.Destroy();
+  _impl_.aggregate_value_.Destroy();
+}
+
+void UninterpretedOption::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UninterpretedOption::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.name_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.identifier_value_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.string_value_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _impl_.aggregate_value_.ClearNonDefaultToEmpty();
+    }
+  }
+  if (cached_has_bits & 0x00000038u) {
+    ::memset(&_impl_.positive_int_value_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.double_value_) -
+        reinterpret_cast<char*>(&_impl_.positive_int_value_)) + sizeof(_impl_.double_value_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UninterpretedOption::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_name(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string identifier_value = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_identifier_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.identifier_value");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional uint64 positive_int_value = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          _Internal::set_has_positive_int_value(&has_bits);
+          _impl_.positive_int_value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int64 negative_int_value = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          _Internal::set_has_negative_int_value(&has_bits);
+          _impl_.negative_int_value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional double double_value = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 49)) {
+          _Internal::set_has_double_value(&has_bits);
+          _impl_.double_value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr);
+          ptr += sizeof(double);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional bytes string_value = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
+          auto str = _internal_mutable_string_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string aggregate_value = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
+          auto str = _internal_mutable_aggregate_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.aggregate_value");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UninterpretedOption::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_name_size()); i < n; i++) {
+    const auto& repfield = this->_internal_name(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string identifier_value = 3;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_identifier_value().data(), static_cast<int>(this->_internal_identifier_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.UninterpretedOption.identifier_value");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_identifier_value(), target);
+  }
+
+  // optional uint64 positive_int_value = 4;
+  if (cached_has_bits & 0x00000008u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(4, this->_internal_positive_int_value(), target);
+  }
+
+  // optional int64 negative_int_value = 5;
+  if (cached_has_bits & 0x00000010u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(5, this->_internal_negative_int_value(), target);
+  }
+
+  // optional double double_value = 6;
+  if (cached_has_bits & 0x00000020u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(6, this->_internal_double_value(), target);
+  }
+
+  // optional bytes string_value = 7;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->WriteBytesMaybeAliased(
+        7, this->_internal_string_value(), target);
+  }
+
+  // optional string aggregate_value = 8;
+  if (cached_has_bits & 0x00000004u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_aggregate_value().data(), static_cast<int>(this->_internal_aggregate_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.UninterpretedOption.aggregate_value");
+    target = stream->WriteStringMaybeAliased(
+        8, this->_internal_aggregate_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption)
+  return target;
+}
+
+size_t UninterpretedOption::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+  total_size += 1UL * this->_internal_name_size();
+  for (const auto& msg : this->_impl_.name_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    // optional string identifier_value = 3;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_identifier_value());
+    }
+
+    // optional bytes string_value = 7;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
+          this->_internal_string_value());
+    }
+
+    // optional string aggregate_value = 8;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_aggregate_value());
+    }
+
+    // optional uint64 positive_int_value = 4;
+    if (cached_has_bits & 0x00000008u) {
+      total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_positive_int_value());
+    }
+
+    // optional int64 negative_int_value = 5;
+    if (cached_has_bits & 0x00000010u) {
+      total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_negative_int_value());
+    }
+
+    // optional double double_value = 6;
+    if (cached_has_bits & 0x00000020u) {
+      total_size += 1 + 8;
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UninterpretedOption::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UninterpretedOption::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption::GetClassData() const { return &_class_data_; }
+
+
+void UninterpretedOption::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UninterpretedOption*>(&to_msg);
+  auto& from = static_cast<const UninterpretedOption&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.name_.MergeFrom(from._impl_.name_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x0000003fu) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_identifier_value(from._internal_identifier_value());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_string_value(from._internal_string_value());
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_internal_set_aggregate_value(from._internal_aggregate_value());
+    }
+    if (cached_has_bits & 0x00000008u) {
+      _this->_impl_.positive_int_value_ = from._impl_.positive_int_value_;
+    }
+    if (cached_has_bits & 0x00000010u) {
+      _this->_impl_.negative_int_value_ = from._impl_.negative_int_value_;
+    }
+    if (cached_has_bits & 0x00000020u) {
+      _this->_impl_.double_value_ = from._impl_.double_value_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UninterpretedOption::CopyFrom(const UninterpretedOption& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UninterpretedOption::IsInitialized() const {
+  if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(_impl_.name_))
+    return false;
+  return true;
+}
+
+void UninterpretedOption::InternalSwap(UninterpretedOption* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.name_.InternalSwap(&other->_impl_.name_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.identifier_value_, lhs_arena,
+      &other->_impl_.identifier_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.string_value_, lhs_arena,
+      &other->_impl_.string_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.aggregate_value_, lhs_arena,
+      &other->_impl_.aggregate_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(UninterpretedOption, _impl_.double_value_)
+      + sizeof(UninterpretedOption::_impl_.double_value_)
+      - PROTOBUF_FIELD_OFFSET(UninterpretedOption, _impl_.positive_int_value_)>(
+          reinterpret_cast<char*>(&_impl_.positive_int_value_),
+          reinterpret_cast<char*>(&other->_impl_.positive_int_value_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[22]);
+}
+
+// ===================================================================
+
+class SourceCodeInfo_Location::_Internal {
+ public:
+  using HasBits = decltype(std::declval<SourceCodeInfo_Location>()._impl_._has_bits_);
+  static void set_has_leading_comments(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_trailing_comments(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+};
+
+SourceCodeInfo_Location::SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo.Location)
+}
+SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  SourceCodeInfo_Location* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){from._impl_.path_}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.span_){from._impl_.span_}
+    , /*decltype(_impl_._span_cached_byte_size_)*/{0}
+    , decltype(_impl_.leading_detached_comments_){from._impl_.leading_detached_comments_}
+    , decltype(_impl_.leading_comments_){}
+    , decltype(_impl_.trailing_comments_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.leading_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_leading_comments()) {
+    _this->_impl_.leading_comments_.Set(from._internal_leading_comments(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.trailing_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_trailing_comments()) {
+    _this->_impl_.trailing_comments_.Set(from._internal_trailing_comments(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo.Location)
+}
+
+inline void SourceCodeInfo_Location::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){arena}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.span_){arena}
+    , /*decltype(_impl_._span_cached_byte_size_)*/{0}
+    , decltype(_impl_.leading_detached_comments_){arena}
+    , decltype(_impl_.leading_comments_){}
+    , decltype(_impl_.trailing_comments_){}
+  };
+  _impl_.leading_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.leading_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.trailing_comments_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.trailing_comments_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+SourceCodeInfo_Location::~SourceCodeInfo_Location() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo.Location)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void SourceCodeInfo_Location::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.path_.~RepeatedField();
+  _impl_.span_.~RepeatedField();
+  _impl_.leading_detached_comments_.~RepeatedPtrField();
+  _impl_.leading_comments_.Destroy();
+  _impl_.trailing_comments_.Destroy();
+}
+
+void SourceCodeInfo_Location::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void SourceCodeInfo_Location::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo.Location)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.path_.Clear();
+  _impl_.span_.Clear();
+  _impl_.leading_detached_comments_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _impl_.leading_comments_.ClearNonDefaultToEmpty();
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _impl_.trailing_comments_.ClearNonDefaultToEmpty();
+    }
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated int32 path = 1 [packed = true];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_path(), ptr, ctx);
+          CHK_(ptr);
+        } else if (static_cast<uint8_t>(tag) == 8) {
+          _internal_add_path(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated int32 span = 2 [packed = true];
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_span(), ptr, ctx);
+          CHK_(ptr);
+        } else if (static_cast<uint8_t>(tag) == 16) {
+          _internal_add_span(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string leading_comments = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_leading_comments();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_comments");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string trailing_comments = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_trailing_comments();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string leading_detached_comments = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_leading_detached_comments();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+            #endif  // !NDEBUG
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* SourceCodeInfo_Location::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    int byte_size = _impl_._path_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          1, _internal_path(), byte_size, target);
+    }
+  }
+
+  // repeated int32 span = 2 [packed = true];
+  {
+    int byte_size = _impl_._span_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          2, _internal_span(), byte_size, target);
+    }
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string leading_comments = 3;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_leading_comments().data(), static_cast<int>(this->_internal_leading_comments().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.leading_comments");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_leading_comments(), target);
+  }
+
+  // optional string trailing_comments = 4;
+  if (cached_has_bits & 0x00000002u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_trailing_comments().data(), static_cast<int>(this->_internal_trailing_comments().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_trailing_comments(), target);
+  }
+
+  // repeated string leading_detached_comments = 6;
+  for (int i = 0, n = this->_internal_leading_detached_comments_size(); i < n; i++) {
+    const auto& s = this->_internal_leading_detached_comments(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+    target = stream->WriteString(6, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo.Location)
+  return target;
+}
+
+size_t SourceCodeInfo_Location::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.path_);
+    if (data_size > 0) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
+    }
+    int cached_size = ::_pbi::ToCachedSize(data_size);
+    _impl_._path_cached_byte_size_.store(cached_size,
+                                    std::memory_order_relaxed);
+    total_size += data_size;
+  }
+
+  // repeated int32 span = 2 [packed = true];
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.span_);
+    if (data_size > 0) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
+    }
+    int cached_size = ::_pbi::ToCachedSize(data_size);
+    _impl_._span_cached_byte_size_.store(cached_size,
+                                    std::memory_order_relaxed);
+    total_size += data_size;
+  }
+
+  // repeated string leading_detached_comments = 6;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.leading_detached_comments_.size());
+  for (int i = 0, n = _impl_.leading_detached_comments_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.leading_detached_comments_.Get(i));
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    // optional string leading_comments = 3;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_leading_comments());
+    }
+
+    // optional string trailing_comments = 4;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_trailing_comments());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceCodeInfo_Location::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    SourceCodeInfo_Location::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo_Location::GetClassData() const { return &_class_data_; }
+
+
+void SourceCodeInfo_Location::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<SourceCodeInfo_Location*>(&to_msg);
+  auto& from = static_cast<const SourceCodeInfo_Location&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.path_.MergeFrom(from._impl_.path_);
+  _this->_impl_.span_.MergeFrom(from._impl_.span_);
+  _this->_impl_.leading_detached_comments_.MergeFrom(from._impl_.leading_detached_comments_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000003u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_leading_comments(from._internal_leading_comments());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_internal_set_trailing_comments(from._internal_trailing_comments());
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo.Location)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceCodeInfo_Location::IsInitialized() const {
+  return true;
+}
+
+void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.path_.InternalSwap(&other->_impl_.path_);
+  _impl_.span_.InternalSwap(&other->_impl_.span_);
+  _impl_.leading_detached_comments_.InternalSwap(&other->_impl_.leading_detached_comments_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.leading_comments_, lhs_arena,
+      &other->_impl_.leading_comments_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.trailing_comments_, lhs_arena,
+      &other->_impl_.trailing_comments_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo_Location::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[23]);
+}
+
+// ===================================================================
+
+class SourceCodeInfo::_Internal {
+ public:
+};
+
+SourceCodeInfo::SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo)
+}
+SourceCodeInfo::SourceCodeInfo(const SourceCodeInfo& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  SourceCodeInfo* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.location_){from._impl_.location_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo)
+}
+
+inline void SourceCodeInfo::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.location_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+SourceCodeInfo::~SourceCodeInfo() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void SourceCodeInfo::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.location_.~RepeatedPtrField();
+}
+
+void SourceCodeInfo::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void SourceCodeInfo::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.location_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* SourceCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_location(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* SourceCodeInfo::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_location_size()); i < n; i++) {
+    const auto& repfield = this->_internal_location(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo)
+  return target;
+}
+
+size_t SourceCodeInfo::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+  total_size += 1UL * this->_internal_location_size();
+  for (const auto& msg : this->_impl_.location_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceCodeInfo::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    SourceCodeInfo::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo::GetClassData() const { return &_class_data_; }
+
+
+void SourceCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<SourceCodeInfo*>(&to_msg);
+  auto& from = static_cast<const SourceCodeInfo&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.location_.MergeFrom(from._impl_.location_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceCodeInfo::IsInitialized() const {
+  return true;
+}
+
+void SourceCodeInfo::InternalSwap(SourceCodeInfo* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.location_.InternalSwap(&other->_impl_.location_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[24]);
+}
+
+// ===================================================================
+
+class GeneratedCodeInfo_Annotation::_Internal {
+ public:
+  using HasBits = decltype(std::declval<GeneratedCodeInfo_Annotation>()._impl_._has_bits_);
+  static void set_has_source_file(HasBits* has_bits) {
+    (*has_bits)[0] |= 1u;
+  }
+  static void set_has_begin(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_end(HasBits* has_bits) {
+    (*has_bits)[0] |= 4u;
+  }
+};
+
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  GeneratedCodeInfo_Annotation* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){from._impl_._has_bits_}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){from._impl_.path_}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.source_file_){}
+    , decltype(_impl_.begin_){}
+    , decltype(_impl_.end_){}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.source_file_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (from._internal_has_source_file()) {
+    _this->_impl_.source_file_.Set(from._internal_source_file(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.begin_, &from._impl_.begin_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
+    reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.end_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+inline void GeneratedCodeInfo_Annotation::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_._has_bits_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , decltype(_impl_.path_){arena}
+    , /*decltype(_impl_._path_cached_byte_size_)*/{0}
+    , decltype(_impl_.source_file_){}
+    , decltype(_impl_.begin_){0}
+    , decltype(_impl_.end_){0}
+  };
+  _impl_.source_file_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.source_file_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+GeneratedCodeInfo_Annotation::~GeneratedCodeInfo_Annotation() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void GeneratedCodeInfo_Annotation::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.path_.~RepeatedField();
+  _impl_.source_file_.Destroy();
+}
+
+void GeneratedCodeInfo_Annotation::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void GeneratedCodeInfo_Annotation::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.path_.Clear();
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    _impl_.source_file_.ClearNonDefaultToEmpty();
+  }
+  if (cached_has_bits & 0x00000006u) {
+    ::memset(&_impl_.begin_, 0, static_cast<size_t>(
+        reinterpret_cast<char*>(&_impl_.end_) -
+        reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.end_));
+  }
+  _impl_._has_bits_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  _Internal::HasBits has_bits{};
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated int32 path = 1 [packed = true];
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedInt32Parser(_internal_mutable_path(), ptr, ctx);
+          CHK_(ptr);
+        } else if (static_cast<uint8_t>(tag) == 8) {
+          _internal_add_path(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional string source_file = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          auto str = _internal_mutable_source_file();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+          #endif  // !NDEBUG
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 begin = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _Internal::set_has_begin(&has_bits);
+          _impl_.begin_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // optional int32 end = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          _Internal::set_has_end(&has_bits);
+          _impl_.end_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  _impl_._has_bits_.Or(has_bits);
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* GeneratedCodeInfo_Annotation::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    int byte_size = _impl_._path_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          1, _internal_path(), byte_size, target);
+    }
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  // optional string source_file = 2;
+  if (cached_has_bits & 0x00000001u) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->_internal_source_file().data(), static_cast<int>(this->_internal_source_file().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
+      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+    target = stream->WriteStringMaybeAliased(
+        2, this->_internal_source_file(), target);
+  }
+
+  // optional int32 begin = 3;
+  if (cached_has_bits & 0x00000002u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_begin(), target);
+  }
+
+  // optional int32 end = 4;
+  if (cached_has_bits & 0x00000004u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(4, this->_internal_end(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation)
+  return target;
+}
+
+size_t GeneratedCodeInfo_Annotation::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated int32 path = 1 [packed = true];
+  {
+    size_t data_size = ::_pbi::WireFormatLite::
+      Int32Size(this->_impl_.path_);
+    if (data_size > 0) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
+    }
+    int cached_size = ::_pbi::ToCachedSize(data_size);
+    _impl_._path_cached_byte_size_.store(cached_size,
+                                    std::memory_order_relaxed);
+    total_size += data_size;
+  }
+
+  cached_has_bits = _impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    // optional string source_file = 2;
+    if (cached_has_bits & 0x00000001u) {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_source_file());
+    }
+
+    // optional int32 begin = 3;
+    if (cached_has_bits & 0x00000002u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_begin());
+    }
+
+    // optional int32 end = 4;
+    if (cached_has_bits & 0x00000004u) {
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+    }
+
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData GeneratedCodeInfo_Annotation::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    GeneratedCodeInfo_Annotation::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo_Annotation::GetClassData() const { return &_class_data_; }
+
+
+void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<GeneratedCodeInfo_Annotation*>(&to_msg);
+  auto& from = static_cast<const GeneratedCodeInfo_Annotation&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.path_.MergeFrom(from._impl_.path_);
+  cached_has_bits = from._impl_._has_bits_[0];
+  if (cached_has_bits & 0x00000007u) {
+    if (cached_has_bits & 0x00000001u) {
+      _this->_internal_set_source_file(from._internal_source_file());
+    }
+    if (cached_has_bits & 0x00000002u) {
+      _this->_impl_.begin_ = from._impl_.begin_;
+    }
+    if (cached_has_bits & 0x00000004u) {
+      _this->_impl_.end_ = from._impl_.end_;
+    }
+    _this->_impl_._has_bits_[0] |= cached_has_bits;
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo_Annotation::IsInitialized() const {
+  return true;
+}
+
+void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]);
+  _impl_.path_.InternalSwap(&other->_impl_.path_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.source_file_, lhs_arena,
+      &other->_impl_.source_file_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.end_)
+      + sizeof(GeneratedCodeInfo_Annotation::_impl_.end_)
+      - PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.begin_)>(
+          reinterpret_cast<char*>(&_impl_.begin_),
+          reinterpret_cast<char*>(&other->_impl_.begin_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[25]);
+}
+
+// ===================================================================
+
+class GeneratedCodeInfo::_Internal {
+ public:
+};
+
+GeneratedCodeInfo::GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.GeneratedCodeInfo)
+}
+GeneratedCodeInfo::GeneratedCodeInfo(const GeneratedCodeInfo& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  GeneratedCodeInfo* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.annotation_){from._impl_.annotation_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo)
+}
+
+inline void GeneratedCodeInfo::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.annotation_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+GeneratedCodeInfo::~GeneratedCodeInfo() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void GeneratedCodeInfo::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.annotation_.~RepeatedPtrField();
+}
+
+void GeneratedCodeInfo::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void GeneratedCodeInfo::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.annotation_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_annotation(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* GeneratedCodeInfo::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_annotation_size()); i < n; i++) {
+    const auto& repfield = this->_internal_annotation(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo)
+  return target;
+}
+
+size_t GeneratedCodeInfo::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  total_size += 1UL * this->_internal_annotation_size();
+  for (const auto& msg : this->_impl_.annotation_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData GeneratedCodeInfo::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    GeneratedCodeInfo::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo::GetClassData() const { return &_class_data_; }
+
+
+void GeneratedCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<GeneratedCodeInfo*>(&to_msg);
+  auto& from = static_cast<const GeneratedCodeInfo&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.annotation_.MergeFrom(from._impl_.annotation_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo::IsInitialized() const {
+  return true;
+}
+
+void GeneratedCodeInfo::InternalSwap(GeneratedCodeInfo* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.annotation_.InternalSwap(&other->_impl_.annotation_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[26]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MessageOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor_database.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor_database.cpp
new file mode 100644
index 0000000..203000d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/descriptor_database.cpp
@@ -0,0 +1,1048 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/descriptor_database.h>
+
+#include <algorithm>
+#include <set>
+
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+namespace google {
+namespace protobuf {
+
+namespace {
+void RecordMessageNames(const DescriptorProto& desc_proto,
+                        const std::string& prefix,
+                        std::set<std::string>* output) {
+  GOOGLE_CHECK(desc_proto.has_name());
+  std::string full_name = prefix.empty()
+                              ? desc_proto.name()
+                              : StrCat(prefix, ".", desc_proto.name());
+  output->insert(full_name);
+
+  for (const auto& d : desc_proto.nested_type()) {
+    RecordMessageNames(d, full_name, output);
+  }
+}
+
+void RecordMessageNames(const FileDescriptorProto& file_proto,
+                        std::set<std::string>* output) {
+  for (const auto& d : file_proto.message_type()) {
+    RecordMessageNames(d, file_proto.package(), output);
+  }
+}
+
+template <typename Fn>
+bool ForAllFileProtos(DescriptorDatabase* db, Fn callback,
+                      std::vector<std::string>* output) {
+  std::vector<std::string> file_names;
+  if (!db->FindAllFileNames(&file_names)) {
+    return false;
+  }
+  std::set<std::string> set;
+  FileDescriptorProto file_proto;
+  for (const auto& f : file_names) {
+    file_proto.Clear();
+    if (!db->FindFileByName(f, &file_proto)) {
+      GOOGLE_LOG(ERROR) << "File not found in database (unexpected): " << f;
+      return false;
+    }
+    callback(file_proto, &set);
+  }
+  output->insert(output->end(), set.begin(), set.end());
+  return true;
+}
+}  // namespace
+
+DescriptorDatabase::~DescriptorDatabase() {}
+
+bool DescriptorDatabase::FindAllPackageNames(std::vector<std::string>* output) {
+  return ForAllFileProtos(
+      this,
+      [](const FileDescriptorProto& file_proto, std::set<std::string>* set) {
+        set->insert(file_proto.package());
+      },
+      output);
+}
+
+bool DescriptorDatabase::FindAllMessageNames(std::vector<std::string>* output) {
+  return ForAllFileProtos(
+      this,
+      [](const FileDescriptorProto& file_proto, std::set<std::string>* set) {
+        RecordMessageNames(file_proto, set);
+      },
+      output);
+}
+
+// ===================================================================
+
+SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
+SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
+    const FileDescriptorProto& file, Value value) {
+  if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
+    GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
+    return false;
+  }
+
+  // We must be careful here -- calling file.package() if file.has_package() is
+  // false could access an uninitialized static-storage variable if we are being
+  // run at startup time.
+  std::string path = file.has_package() ? file.package() : std::string();
+  if (!path.empty()) path += '.';
+
+  for (int i = 0; i < file.message_type_size(); i++) {
+    if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
+    if (!AddNestedExtensions(file.name(), file.message_type(i), value))
+      return false;
+  }
+  for (int i = 0; i < file.enum_type_size(); i++) {
+    if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
+  }
+  for (int i = 0; i < file.extension_size(); i++) {
+    if (!AddSymbol(path + file.extension(i).name(), value)) return false;
+    if (!AddExtension(file.name(), file.extension(i), value)) return false;
+  }
+  for (int i = 0; i < file.service_size(); i++) {
+    if (!AddSymbol(path + file.service(i).name(), value)) return false;
+  }
+
+  return true;
+}
+
+namespace {
+
+// Returns true if and only if all characters in the name are alphanumerics,
+// underscores, or periods.
+bool ValidateSymbolName(StringPiece name) {
+  for (char c : name) {
+    // I don't trust ctype.h due to locales.  :(
+    if (c != '.' && c != '_' && (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
+        (c < 'a' || c > 'z')) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Find the last key in the container which sorts less than or equal to the
+// symbol name.  Since upper_bound() returns the *first* key that sorts
+// *greater* than the input, we want the element immediately before that.
+template <typename Container, typename Key>
+typename Container::const_iterator FindLastLessOrEqual(
+    const Container* container, const Key& key) {
+  auto iter = container->upper_bound(key);
+  if (iter != container->begin()) --iter;
+  return iter;
+}
+
+// As above, but using std::upper_bound instead.
+template <typename Container, typename Key, typename Cmp>
+typename Container::const_iterator FindLastLessOrEqual(
+    const Container* container, const Key& key, const Cmp& cmp) {
+  auto iter = std::upper_bound(container->begin(), container->end(), key, cmp);
+  if (iter != container->begin()) --iter;
+  return iter;
+}
+
+// True if either the arguments are equal or super_symbol identifies a
+// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
+// "foo.bar.baz", but not a parent of "foo.barbaz").
+bool IsSubSymbol(StringPiece sub_symbol, StringPiece super_symbol) {
+  return sub_symbol == super_symbol ||
+         (HasPrefixString(super_symbol, sub_symbol) &&
+          super_symbol[sub_symbol.size()] == '.');
+}
+
+}  // namespace
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
+    const std::string& name, Value value) {
+  // We need to make sure not to violate our map invariant.
+
+  // If the symbol name is invalid it could break our lookup algorithm (which
+  // relies on the fact that '.' sorts before all other characters that are
+  // valid in symbol names).
+  if (!ValidateSymbolName(name)) {
+    GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
+    return false;
+  }
+
+  // Try to look up the symbol to make sure a super-symbol doesn't already
+  // exist.
+  auto iter = FindLastLessOrEqual(&by_symbol_, name);
+
+  if (iter == by_symbol_.end()) {
+    // Apparently the map is currently empty.  Just insert and be done with it.
+    by_symbol_.insert(
+        typename std::map<std::string, Value>::value_type(name, value));
+    return true;
+  }
+
+  if (IsSubSymbol(iter->first, name)) {
+    GOOGLE_LOG(ERROR) << "Symbol name \"" << name
+               << "\" conflicts with the existing "
+                  "symbol \""
+               << iter->first << "\".";
+    return false;
+  }
+
+  // OK, that worked.  Now we have to make sure that no symbol in the map is
+  // a sub-symbol of the one we are inserting.  The only symbol which could
+  // be so is the first symbol that is greater than the new symbol.  Since
+  // |iter| points at the last symbol that is less than or equal, we just have
+  // to increment it.
+  ++iter;
+
+  if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
+    GOOGLE_LOG(ERROR) << "Symbol name \"" << name
+               << "\" conflicts with the existing "
+                  "symbol \""
+               << iter->first << "\".";
+    return false;
+  }
+
+  // OK, no conflicts.
+
+  // Insert the new symbol using the iterator as a hint, the new entry will
+  // appear immediately before the one the iterator is pointing at.
+  by_symbol_.insert(
+      iter, typename std::map<std::string, Value>::value_type(name, value));
+
+  return true;
+}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
+    const std::string& filename, const DescriptorProto& message_type,
+    Value value) {
+  for (int i = 0; i < message_type.nested_type_size(); i++) {
+    if (!AddNestedExtensions(filename, message_type.nested_type(i), value))
+      return false;
+  }
+  for (int i = 0; i < message_type.extension_size(); i++) {
+    if (!AddExtension(filename, message_type.extension(i), value)) return false;
+  }
+  return true;
+}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
+    const std::string& filename, const FieldDescriptorProto& field,
+    Value value) {
+  if (!field.extendee().empty() && field.extendee()[0] == '.') {
+    // The extension is fully-qualified.  We can use it as a lookup key in
+    // the by_symbol_ table.
+    if (!InsertIfNotPresent(
+            &by_extension_,
+            std::make_pair(field.extendee().substr(1), field.number()),
+            value)) {
+      GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
+                    "extend "
+                 << field.extendee() << " { " << field.name() << " = "
+                 << field.number() << " } from:" << filename;
+      return false;
+    }
+  } else {
+    // Not fully-qualified.  We can't really do anything here, unfortunately.
+    // We don't consider this an error, though, because the descriptor is
+    // valid.
+  }
+  return true;
+}
+
+template <typename Value>
+Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
+    const std::string& filename) {
+  return FindWithDefault(by_name_, filename, Value());
+}
+
+template <typename Value>
+Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
+    const std::string& name) {
+  auto iter = FindLastLessOrEqual(&by_symbol_, name);
+
+  return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name))
+             ? iter->second
+             : Value();
+}
+
+template <typename Value>
+Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
+    const std::string& containing_type, int field_number) {
+  return FindWithDefault(
+      by_extension_, std::make_pair(containing_type, field_number), Value());
+}
+
+template <typename Value>
+bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
+    const std::string& containing_type, std::vector<int>* output) {
+  typename std::map<std::pair<std::string, int>, Value>::const_iterator it =
+      by_extension_.lower_bound(std::make_pair(containing_type, 0));
+  bool success = false;
+
+  for (; it != by_extension_.end() && it->first.first == containing_type;
+       ++it) {
+    output->push_back(it->first.second);
+    success = true;
+  }
+
+  return success;
+}
+
+template <typename Value>
+void SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllFileNames(
+    std::vector<std::string>* output) {
+  output->resize(by_name_.size());
+  int i = 0;
+  for (const auto& kv : by_name_) {
+    (*output)[i] = kv.first;
+    i++;
+  }
+}
+
+// -------------------------------------------------------------------
+
+bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
+  FileDescriptorProto* new_file = new FileDescriptorProto;
+  new_file->CopyFrom(file);
+  return AddAndOwn(new_file);
+}
+
+bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
+  files_to_delete_.emplace_back(file);
+  return index_.AddFile(*file, file);
+}
+
+bool SimpleDescriptorDatabase::FindFileByName(const std::string& filename,
+                                              FileDescriptorProto* output) {
+  return MaybeCopy(index_.FindFile(filename), output);
+}
+
+bool SimpleDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  return MaybeCopy(index_.FindSymbol(symbol_name), output);
+}
+
+bool SimpleDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
+}
+
+bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  return index_.FindAllExtensionNumbers(extendee_type, output);
+}
+
+
+bool SimpleDescriptorDatabase::FindAllFileNames(
+    std::vector<std::string>* output) {
+  index_.FindAllFileNames(output);
+  return true;
+}
+
+bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
+                                         FileDescriptorProto* output) {
+  if (file == nullptr) return false;
+  output->CopyFrom(*file);
+  return true;
+}
+
+// -------------------------------------------------------------------
+
+class EncodedDescriptorDatabase::DescriptorIndex {
+ public:
+  using Value = std::pair<const void*, int>;
+  // Helpers to recursively add particular descriptors and all their contents
+  // to the index.
+  template <typename FileProto>
+  bool AddFile(const FileProto& file, Value value);
+
+  Value FindFile(StringPiece filename);
+  Value FindSymbol(StringPiece name);
+  Value FindSymbolOnlyFlat(StringPiece name) const;
+  Value FindExtension(StringPiece containing_type, int field_number);
+  bool FindAllExtensionNumbers(StringPiece containing_type,
+                               std::vector<int>* output);
+  void FindAllFileNames(std::vector<std::string>* output) const;
+
+ private:
+  friend class EncodedDescriptorDatabase;
+
+  bool AddSymbol(StringPiece symbol);
+
+  template <typename DescProto>
+  bool AddNestedExtensions(StringPiece filename,
+                           const DescProto& message_type);
+  template <typename FieldProto>
+  bool AddExtension(StringPiece filename, const FieldProto& field);
+
+  // All the maps below have two representations:
+  //  - a std::set<> where we insert initially.
+  //  - a std::vector<> where we flatten the structure on demand.
+  // The initial tree helps avoid O(N) behavior of inserting into a sorted
+  // vector, while the vector reduces the heap requirements of the data
+  // structure.
+
+  void EnsureFlat();
+
+  using String = std::string;
+
+  String EncodeString(StringPiece str) const { return String(str); }
+  StringPiece DecodeString(const String& str, int) const { return str; }
+
+  struct EncodedEntry {
+    // Do not use `Value` here to avoid the padding of that object.
+    const void* data;
+    int size;
+    // Keep the package here instead of each SymbolEntry to save space.
+    String encoded_package;
+
+    Value value() const { return {data, size}; }
+  };
+  std::vector<EncodedEntry> all_values_;
+
+  struct FileEntry {
+    int data_offset;
+    String encoded_name;
+
+    StringPiece name(const DescriptorIndex& index) const {
+      return index.DecodeString(encoded_name, data_offset);
+    }
+  };
+  struct FileCompare {
+    const DescriptorIndex& index;
+
+    bool operator()(const FileEntry& a, const FileEntry& b) const {
+      return a.name(index) < b.name(index);
+    }
+    bool operator()(const FileEntry& a, StringPiece b) const {
+      return a.name(index) < b;
+    }
+    bool operator()(StringPiece a, const FileEntry& b) const {
+      return a < b.name(index);
+    }
+  };
+  std::set<FileEntry, FileCompare> by_name_{FileCompare{*this}};
+  std::vector<FileEntry> by_name_flat_;
+
+  struct SymbolEntry {
+    int data_offset;
+    String encoded_symbol;
+
+    StringPiece package(const DescriptorIndex& index) const {
+      return index.DecodeString(index.all_values_[data_offset].encoded_package,
+                                data_offset);
+    }
+    StringPiece symbol(const DescriptorIndex& index) const {
+      return index.DecodeString(encoded_symbol, data_offset);
+    }
+
+    std::string AsString(const DescriptorIndex& index) const {
+      auto p = package(index);
+      return StrCat(p, p.empty() ? "" : ".", symbol(index));
+    }
+  };
+
+  struct SymbolCompare {
+    const DescriptorIndex& index;
+
+    std::string AsString(const SymbolEntry& entry) const {
+      return entry.AsString(index);
+    }
+    static StringPiece AsString(StringPiece str) { return str; }
+
+    std::pair<StringPiece, StringPiece> GetParts(
+        const SymbolEntry& entry) const {
+      auto package = entry.package(index);
+      if (package.empty()) return {entry.symbol(index), StringPiece{}};
+      return {package, entry.symbol(index)};
+    }
+    std::pair<StringPiece, StringPiece> GetParts(
+        StringPiece str) const {
+      return {str, {}};
+    }
+
+    template <typename T, typename U>
+    bool operator()(const T& lhs, const U& rhs) const {
+      auto lhs_parts = GetParts(lhs);
+      auto rhs_parts = GetParts(rhs);
+
+      // Fast path to avoid making the whole string for common cases.
+      if (int res =
+              lhs_parts.first.substr(0, rhs_parts.first.size())
+                  .compare(rhs_parts.first.substr(0, lhs_parts.first.size()))) {
+        // If the packages already differ, exit early.
+        return res < 0;
+      } else if (lhs_parts.first.size() == rhs_parts.first.size()) {
+        return lhs_parts.second < rhs_parts.second;
+      }
+      return AsString(lhs) < AsString(rhs);
+    }
+  };
+  std::set<SymbolEntry, SymbolCompare> by_symbol_{SymbolCompare{*this}};
+  std::vector<SymbolEntry> by_symbol_flat_;
+
+  struct ExtensionEntry {
+    int data_offset;
+    String encoded_extendee;
+    StringPiece extendee(const DescriptorIndex& index) const {
+      return index.DecodeString(encoded_extendee, data_offset).substr(1);
+    }
+    int extension_number;
+  };
+  struct ExtensionCompare {
+    const DescriptorIndex& index;
+
+    bool operator()(const ExtensionEntry& a, const ExtensionEntry& b) const {
+      return std::make_tuple(a.extendee(index), a.extension_number) <
+             std::make_tuple(b.extendee(index), b.extension_number);
+    }
+    bool operator()(const ExtensionEntry& a,
+                    std::tuple<StringPiece, int> b) const {
+      return std::make_tuple(a.extendee(index), a.extension_number) < b;
+    }
+    bool operator()(std::tuple<StringPiece, int> a,
+                    const ExtensionEntry& b) const {
+      return a < std::make_tuple(b.extendee(index), b.extension_number);
+    }
+  };
+  std::set<ExtensionEntry, ExtensionCompare> by_extension_{
+      ExtensionCompare{*this}};
+  std::vector<ExtensionEntry> by_extension_flat_;
+};
+
+bool EncodedDescriptorDatabase::Add(const void* encoded_file_descriptor,
+                                    int size) {
+  FileDescriptorProto file;
+  if (file.ParseFromArray(encoded_file_descriptor, size)) {
+    return index_->AddFile(file, std::make_pair(encoded_file_descriptor, size));
+  } else {
+    GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
+                  "EncodedDescriptorDatabase::Add().";
+    return false;
+  }
+}
+
+bool EncodedDescriptorDatabase::AddCopy(const void* encoded_file_descriptor,
+                                        int size) {
+  void* copy = operator new(size);
+  memcpy(copy, encoded_file_descriptor, size);
+  files_to_delete_.push_back(copy);
+  return Add(copy, size);
+}
+
+bool EncodedDescriptorDatabase::FindFileByName(const std::string& filename,
+                                               FileDescriptorProto* output) {
+  return MaybeParse(index_->FindFile(filename), output);
+}
+
+bool EncodedDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  return MaybeParse(index_->FindSymbol(symbol_name), output);
+}
+
+bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
+    const std::string& symbol_name, std::string* output) {
+  auto encoded_file = index_->FindSymbol(symbol_name);
+  if (encoded_file.first == nullptr) return false;
+
+  // Optimization:  The name should be the first field in the encoded message.
+  //   Try to just read it directly.
+  io::CodedInputStream input(static_cast<const uint8_t*>(encoded_file.first),
+                             encoded_file.second);
+
+  const uint32_t kNameTag = internal::WireFormatLite::MakeTag(
+      FileDescriptorProto::kNameFieldNumber,
+      internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+
+  if (input.ReadTagNoLastTag() == kNameTag) {
+    // Success!
+    return internal::WireFormatLite::ReadString(&input, output);
+  } else {
+    // Slow path.  Parse whole message.
+    FileDescriptorProto file_proto;
+    if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
+      return false;
+    }
+    *output = file_proto.name();
+    return true;
+  }
+}
+
+bool EncodedDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  return MaybeParse(index_->FindExtension(containing_type, field_number),
+                    output);
+}
+
+bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  return index_->FindAllExtensionNumbers(extendee_type, output);
+}
+
+template <typename FileProto>
+bool EncodedDescriptorDatabase::DescriptorIndex::AddFile(const FileProto& file,
+                                                         Value value) {
+  // We push `value` into the array first. This is important because the AddXXX
+  // functions below will expect it to be there.
+  all_values_.push_back({value.first, value.second, {}});
+
+  if (!ValidateSymbolName(file.package())) {
+    GOOGLE_LOG(ERROR) << "Invalid package name: " << file.package();
+    return false;
+  }
+  all_values_.back().encoded_package = EncodeString(file.package());
+
+  if (!InsertIfNotPresent(
+          &by_name_, FileEntry{static_cast<int>(all_values_.size() - 1),
+                               EncodeString(file.name())}) ||
+      std::binary_search(by_name_flat_.begin(), by_name_flat_.end(),
+                         file.name(), by_name_.key_comp())) {
+    GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
+    return false;
+  }
+
+  for (const auto& message_type : file.message_type()) {
+    if (!AddSymbol(message_type.name())) return false;
+    if (!AddNestedExtensions(file.name(), message_type)) return false;
+  }
+  for (const auto& enum_type : file.enum_type()) {
+    if (!AddSymbol(enum_type.name())) return false;
+  }
+  for (const auto& extension : file.extension()) {
+    if (!AddSymbol(extension.name())) return false;
+    if (!AddExtension(file.name(), extension)) return false;
+  }
+  for (const auto& service : file.service()) {
+    if (!AddSymbol(service.name())) return false;
+  }
+
+  return true;
+}
+
+template <typename Iter, typename Iter2, typename Index>
+static bool CheckForMutualSubsymbols(StringPiece symbol_name, Iter* iter,
+                                     Iter2 end, const Index& index) {
+  if (*iter != end) {
+    if (IsSubSymbol((*iter)->AsString(index), symbol_name)) {
+      GOOGLE_LOG(ERROR) << "Symbol name \"" << symbol_name
+                 << "\" conflicts with the existing symbol \""
+                 << (*iter)->AsString(index) << "\".";
+      return false;
+    }
+
+    // OK, that worked.  Now we have to make sure that no symbol in the map is
+    // a sub-symbol of the one we are inserting.  The only symbol which could
+    // be so is the first symbol that is greater than the new symbol.  Since
+    // |iter| points at the last symbol that is less than or equal, we just have
+    // to increment it.
+    ++*iter;
+
+    if (*iter != end && IsSubSymbol(symbol_name, (*iter)->AsString(index))) {
+      GOOGLE_LOG(ERROR) << "Symbol name \"" << symbol_name
+                 << "\" conflicts with the existing symbol \""
+                 << (*iter)->AsString(index) << "\".";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool EncodedDescriptorDatabase::DescriptorIndex::AddSymbol(
+    StringPiece symbol) {
+  SymbolEntry entry = {static_cast<int>(all_values_.size() - 1),
+                       EncodeString(symbol)};
+  std::string entry_as_string = entry.AsString(*this);
+
+  // We need to make sure not to violate our map invariant.
+
+  // If the symbol name is invalid it could break our lookup algorithm (which
+  // relies on the fact that '.' sorts before all other characters that are
+  // valid in symbol names).
+  if (!ValidateSymbolName(symbol)) {
+    GOOGLE_LOG(ERROR) << "Invalid symbol name: " << entry_as_string;
+    return false;
+  }
+
+  auto iter = FindLastLessOrEqual(&by_symbol_, entry);
+  if (!CheckForMutualSubsymbols(entry_as_string, &iter, by_symbol_.end(),
+                                *this)) {
+    return false;
+  }
+
+  // Same, but on by_symbol_flat_
+  auto flat_iter =
+      FindLastLessOrEqual(&by_symbol_flat_, entry, by_symbol_.key_comp());
+  if (!CheckForMutualSubsymbols(entry_as_string, &flat_iter,
+                                by_symbol_flat_.end(), *this)) {
+    return false;
+  }
+
+  // OK, no conflicts.
+
+  // Insert the new symbol using the iterator as a hint, the new entry will
+  // appear immediately before the one the iterator is pointing at.
+  by_symbol_.insert(iter, entry);
+
+  return true;
+}
+
+template <typename DescProto>
+bool EncodedDescriptorDatabase::DescriptorIndex::AddNestedExtensions(
+    StringPiece filename, const DescProto& message_type) {
+  for (const auto& nested_type : message_type.nested_type()) {
+    if (!AddNestedExtensions(filename, nested_type)) return false;
+  }
+  for (const auto& extension : message_type.extension()) {
+    if (!AddExtension(filename, extension)) return false;
+  }
+  return true;
+}
+
+template <typename FieldProto>
+bool EncodedDescriptorDatabase::DescriptorIndex::AddExtension(
+    StringPiece filename, const FieldProto& field) {
+  if (!field.extendee().empty() && field.extendee()[0] == '.') {
+    // The extension is fully-qualified.  We can use it as a lookup key in
+    // the by_symbol_ table.
+    if (!InsertIfNotPresent(
+            &by_extension_,
+            ExtensionEntry{static_cast<int>(all_values_.size() - 1),
+                           EncodeString(field.extendee()), field.number()}) ||
+        std::binary_search(
+            by_extension_flat_.begin(), by_extension_flat_.end(),
+            std::make_pair(field.extendee().substr(1), field.number()),
+            by_extension_.key_comp())) {
+      GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
+                    "extend "
+                 << field.extendee() << " { " << field.name() << " = "
+                 << field.number() << " } from:" << filename;
+      return false;
+    }
+  } else {
+    // Not fully-qualified.  We can't really do anything here, unfortunately.
+    // We don't consider this an error, though, because the descriptor is
+    // valid.
+  }
+  return true;
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindSymbol(StringPiece name) {
+  EnsureFlat();
+  return FindSymbolOnlyFlat(name);
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindSymbolOnlyFlat(
+    StringPiece name) const {
+  auto iter =
+      FindLastLessOrEqual(&by_symbol_flat_, name, by_symbol_.key_comp());
+
+  return iter != by_symbol_flat_.end() &&
+                 IsSubSymbol(iter->AsString(*this), name)
+             ? all_values_[iter->data_offset].value()
+             : Value();
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindExtension(
+    StringPiece containing_type, int field_number) {
+  EnsureFlat();
+
+  auto it = std::lower_bound(
+      by_extension_flat_.begin(), by_extension_flat_.end(),
+      std::make_tuple(containing_type, field_number), by_extension_.key_comp());
+  return it == by_extension_flat_.end() ||
+                 it->extendee(*this) != containing_type ||
+                 it->extension_number != field_number
+             ? std::make_pair(nullptr, 0)
+             : all_values_[it->data_offset].value();
+}
+
+template <typename T, typename Less>
+static void MergeIntoFlat(std::set<T, Less>* s, std::vector<T>* flat) {
+  if (s->empty()) return;
+  std::vector<T> new_flat(s->size() + flat->size());
+  std::merge(s->begin(), s->end(), flat->begin(), flat->end(), &new_flat[0],
+             s->key_comp());
+  *flat = std::move(new_flat);
+  s->clear();
+}
+
+void EncodedDescriptorDatabase::DescriptorIndex::EnsureFlat() {
+  all_values_.shrink_to_fit();
+  // Merge each of the sets into their flat counterpart.
+  MergeIntoFlat(&by_name_, &by_name_flat_);
+  MergeIntoFlat(&by_symbol_, &by_symbol_flat_);
+  MergeIntoFlat(&by_extension_, &by_extension_flat_);
+}
+
+bool EncodedDescriptorDatabase::DescriptorIndex::FindAllExtensionNumbers(
+    StringPiece containing_type, std::vector<int>* output) {
+  EnsureFlat();
+
+  bool success = false;
+  auto it = std::lower_bound(
+      by_extension_flat_.begin(), by_extension_flat_.end(),
+      std::make_tuple(containing_type, 0), by_extension_.key_comp());
+  for (;
+       it != by_extension_flat_.end() && it->extendee(*this) == containing_type;
+       ++it) {
+    output->push_back(it->extension_number);
+    success = true;
+  }
+
+  return success;
+}
+
+void EncodedDescriptorDatabase::DescriptorIndex::FindAllFileNames(
+    std::vector<std::string>* output) const {
+  output->resize(by_name_.size() + by_name_flat_.size());
+  int i = 0;
+  for (const auto& entry : by_name_) {
+    (*output)[i] = std::string(entry.name(*this));
+    i++;
+  }
+  for (const auto& entry : by_name_flat_) {
+    (*output)[i] = std::string(entry.name(*this));
+    i++;
+  }
+}
+
+std::pair<const void*, int>
+EncodedDescriptorDatabase::DescriptorIndex::FindFile(
+    StringPiece filename) {
+  EnsureFlat();
+
+  auto it = std::lower_bound(by_name_flat_.begin(), by_name_flat_.end(),
+                             filename, by_name_.key_comp());
+  return it == by_name_flat_.end() || it->name(*this) != filename
+             ? std::make_pair(nullptr, 0)
+             : all_values_[it->data_offset].value();
+}
+
+
+bool EncodedDescriptorDatabase::FindAllFileNames(
+    std::vector<std::string>* output) {
+  index_->FindAllFileNames(output);
+  return true;
+}
+
+bool EncodedDescriptorDatabase::MaybeParse(
+    std::pair<const void*, int> encoded_file, FileDescriptorProto* output) {
+  if (encoded_file.first == nullptr) return false;
+  return output->ParseFromArray(encoded_file.first, encoded_file.second);
+}
+
+EncodedDescriptorDatabase::EncodedDescriptorDatabase()
+    : index_(new DescriptorIndex()) {}
+
+EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
+  for (void* p : files_to_delete_) {
+    operator delete(p);
+  }
+}
+
+// ===================================================================
+
+DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
+    : pool_(pool) {}
+DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
+
+bool DescriptorPoolDatabase::FindFileByName(const std::string& filename,
+                                            FileDescriptorProto* output) {
+  const FileDescriptor* file = pool_.FindFileByName(filename);
+  if (file == nullptr) return false;
+  output->Clear();
+  file->CopyTo(output);
+  return true;
+}
+
+bool DescriptorPoolDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
+  if (file == nullptr) return false;
+  output->Clear();
+  file->CopyTo(output);
+  return true;
+}
+
+bool DescriptorPoolDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
+  if (extendee == nullptr) return false;
+
+  const FieldDescriptor* extension =
+      pool_.FindExtensionByNumber(extendee, field_number);
+  if (extension == nullptr) return false;
+
+  output->Clear();
+  extension->file()->CopyTo(output);
+  return true;
+}
+
+bool DescriptorPoolDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
+  if (extendee == nullptr) return false;
+
+  std::vector<const FieldDescriptor*> extensions;
+  pool_.FindAllExtensions(extendee, &extensions);
+
+  for (const FieldDescriptor* extension : extensions) {
+    output->push_back(extension->number());
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+MergedDescriptorDatabase::MergedDescriptorDatabase(
+    DescriptorDatabase* source1, DescriptorDatabase* source2) {
+  sources_.push_back(source1);
+  sources_.push_back(source2);
+}
+MergedDescriptorDatabase::MergedDescriptorDatabase(
+    const std::vector<DescriptorDatabase*>& sources)
+    : sources_(sources) {}
+MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
+
+bool MergedDescriptorDatabase::FindFileByName(const std::string& filename,
+                                              FileDescriptorProto* output) {
+  for (DescriptorDatabase* source : sources_) {
+    if (source->FindFileByName(filename, output)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MergedDescriptorDatabase::FindFileContainingSymbol(
+    const std::string& symbol_name, FileDescriptorProto* output) {
+  for (size_t i = 0; i < sources_.size(); i++) {
+    if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
+      // The symbol was found in source i.  However, if one of the previous
+      // sources defines a file with the same name (which presumably doesn't
+      // contain the symbol, since it wasn't found in that source), then we
+      // must hide it from the caller.
+      FileDescriptorProto temp;
+      for (size_t j = 0; j < i; j++) {
+        if (sources_[j]->FindFileByName(output->name(), &temp)) {
+          // Found conflicting file in a previous source.
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MergedDescriptorDatabase::FindFileContainingExtension(
+    const std::string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  for (size_t i = 0; i < sources_.size(); i++) {
+    if (sources_[i]->FindFileContainingExtension(containing_type, field_number,
+                                                 output)) {
+      // The symbol was found in source i.  However, if one of the previous
+      // sources defines a file with the same name (which presumably doesn't
+      // contain the symbol, since it wasn't found in that source), then we
+      // must hide it from the caller.
+      FileDescriptorProto temp;
+      for (size_t j = 0; j < i; j++) {
+        if (sources_[j]->FindFileByName(output->name(), &temp)) {
+          // Found conflicting file in a previous source.
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MergedDescriptorDatabase::FindAllExtensionNumbers(
+    const std::string& extendee_type, std::vector<int>* output) {
+  std::set<int> merged_results;
+  std::vector<int> results;
+  bool success = false;
+
+  for (DescriptorDatabase* source : sources_) {
+    if (source->FindAllExtensionNumbers(extendee_type, &results)) {
+      std::copy(results.begin(), results.end(),
+                std::insert_iterator<std::set<int> >(merged_results,
+                                                     merged_results.begin()));
+      success = true;
+    }
+    results.clear();
+  }
+
+  std::copy(merged_results.begin(), merged_results.end(),
+            std::insert_iterator<std::vector<int> >(*output, output->end()));
+
+  return success;
+}
+
+
+bool MergedDescriptorDatabase::FindAllFileNames(
+    std::vector<std::string>* output) {
+  bool implemented = false;
+  for (DescriptorDatabase* source : sources_) {
+    std::vector<std::string> source_output;
+    if (source->FindAllFileNames(&source_output)) {
+      output->reserve(output->size() + source_output.size());
+      for (auto& source : source_output) {
+        output->push_back(std::move(source));
+      }
+      implemented = true;
+    }
+  }
+  return implemented;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/duration.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/duration.pb.cpp
new file mode 100644
index 0000000..72766bd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/duration.pb.cpp
@@ -0,0 +1,307 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#include <google/protobuf/duration.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Duration::Duration(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.seconds_)*/int64_t{0}
+  , /*decltype(_impl_.nanos_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct DurationDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DurationDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DurationDefaultTypeInternal() {}
+  union {
+    Duration _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DurationDefaultTypeInternal _Duration_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fduration_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, _impl_.seconds_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, _impl_.nanos_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Duration)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Duration_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\036google/protobuf/duration.proto\022\017google"
+  ".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r"
+  "\n\005nanos\030\002 \001(\005B\203\001\n\023com.google.protobufB\rD"
+  "urationProtoP\001Z1google.golang.org/protob"
+  "uf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Goo"
+  "gle.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fduration_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
+    false, false, 235, descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto,
+    "google/protobuf/duration.proto",
+    &descriptor_table_google_2fprotobuf_2fduration_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fduration_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fduration_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fduration_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fduration_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fduration_2eproto(&descriptor_table_google_2fprotobuf_2fduration_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Duration::_Internal {
+ public:
+};
+
+Duration::Duration(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Duration)
+}
+Duration::Duration(const Duration& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Duration* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){}
+    , decltype(_impl_.nanos_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.seconds_, &from._impl_.seconds_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.nanos_) -
+    reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Duration)
+}
+
+inline void Duration::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){int64_t{0}}
+    , decltype(_impl_.nanos_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Duration::~Duration() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Duration)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Duration::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Duration::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Duration::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Duration)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  ::memset(&_impl_.seconds_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.nanos_) -
+      reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Duration::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int64 seconds = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.seconds_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 nanos = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _impl_.nanos_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Duration::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Duration)
+  return target;
+}
+
+size_t Duration::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Duration::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Duration::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Duration::GetClassData() const { return &_class_data_; }
+
+
+void Duration::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Duration*>(&to_msg);
+  auto& from = static_cast<const Duration&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_seconds() != 0) {
+    _this->_internal_set_seconds(from._internal_seconds());
+  }
+  if (from._internal_nanos() != 0) {
+    _this->_internal_set_nanos(from._internal_nanos());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Duration::CopyFrom(const Duration& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Duration)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Duration::IsInitialized() const {
+  return true;
+}
+
+void Duration::InternalSwap(Duration* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Duration, _impl_.nanos_)
+      + sizeof(Duration::_impl_.nanos_)
+      - PROTOBUF_FIELD_OFFSET(Duration, _impl_.seconds_)>(
+          reinterpret_cast<char*>(&_impl_.seconds_),
+          reinterpret_cast<char*>(&other->_impl_.seconds_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Duration::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fduration_2eproto_getter, &descriptor_table_google_2fprotobuf_2fduration_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fduration_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Duration*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Duration >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Duration >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/dynamic_message.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/dynamic_message.cpp
new file mode 100644
index 0000000..1c96ca2
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/dynamic_message.cpp
@@ -0,0 +1,826 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// DynamicMessage is implemented by constructing a data structure which
+// has roughly the same memory layout as a generated message would have.
+// Then, we use Reflection to implement our reflection interface.  All
+// the other operations we need to implement (e.g.  parsing, copying,
+// etc.) are already implemented in terms of Reflection, so the rest is
+// easy.
+//
+// The up side of this strategy is that it's very efficient.  We don't
+// need to use hash_maps or generic representations of fields.  The
+// down side is that this is a low-level memory management hack which
+// can be tricky to get right.
+//
+// As mentioned in the header, we only expose a DynamicMessageFactory
+// publicly, not the DynamicMessage class itself.  This is because
+// GenericMessageReflection wants to have a pointer to a "default"
+// copy of the class, with all fields initialized to their default
+// values.  We only want to construct one of these per message type,
+// so DynamicMessageFactory stores a cache of default messages for
+// each type it sees (each unique Descriptor pointer).  The code
+// refers to the "default" copy of the class as the "prototype".
+//
+// Note on memory allocation:  This module often calls "operator new()"
+// to allocate untyped memory, rather than calling something like
+// "new uint8_t[]".  This is because "operator new()" means "Give me some
+// space which I can use as I please." while "new uint8_t[]" means "Give
+// me an array of 8-bit integers.".  In practice, the later may return
+// a pointer that is not aligned correctly for general use.  I believe
+// Item 8 of "More Effective C++" discusses this in more detail, though
+// I don't have the book on me right now so I'm not sure.
+
+#include <google/protobuf/dynamic_message.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <new>
+#include <unordered_map>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+using internal::DynamicMapField;
+using internal::ExtensionSet;
+using internal::MapField;
+
+
+using internal::ArenaStringPtr;
+
+// ===================================================================
+// Some helper tables and functions...
+
+namespace {
+
+bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); }
+
+// Sync with helpers.h.
+inline bool HasHasbit(const FieldDescriptor* field) {
+  // This predicate includes proto3 message fields only if they have "optional".
+  //   Foo submsg1 = 1;           // HasHasbit() == false
+  //   optional Foo submsg2 = 2;  // HasHasbit() == true
+  // This is slightly odd, as adding "optional" to a singular proto3 field does
+  // not change the semantics or API. However whenever any field in a message
+  // has a hasbit, it forces reflection to include hasbit offsets for *all*
+  // fields, even if almost all of them are set to -1 (no hasbit). So to avoid
+  // causing a sudden size regression for ~all proto3 messages, we give proto3
+  // message fields a hasbit only if "optional" is present. If the user is
+  // explicitly writing "optional", it is likely they are writing it on
+  // primitive fields also.
+  return (field->has_optional_keyword() || field->is_required()) &&
+         !field->options().weak();
+}
+
+inline bool InRealOneof(const FieldDescriptor* field) {
+  return field->containing_oneof() &&
+         !field->containing_oneof()->is_synthetic();
+}
+
+// Compute the byte size of the in-memory representation of the field.
+int FieldSpaceUsed(const FieldDescriptor* field) {
+  typedef FieldDescriptor FD;  // avoid line wrapping
+  if (field->label() == FD::LABEL_REPEATED) {
+    switch (field->cpp_type()) {
+      case FD::CPPTYPE_INT32:
+        return sizeof(RepeatedField<int32_t>);
+      case FD::CPPTYPE_INT64:
+        return sizeof(RepeatedField<int64_t>);
+      case FD::CPPTYPE_UINT32:
+        return sizeof(RepeatedField<uint32_t>);
+      case FD::CPPTYPE_UINT64:
+        return sizeof(RepeatedField<uint64_t>);
+      case FD::CPPTYPE_DOUBLE:
+        return sizeof(RepeatedField<double>);
+      case FD::CPPTYPE_FLOAT:
+        return sizeof(RepeatedField<float>);
+      case FD::CPPTYPE_BOOL:
+        return sizeof(RepeatedField<bool>);
+      case FD::CPPTYPE_ENUM:
+        return sizeof(RepeatedField<int>);
+      case FD::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          return sizeof(DynamicMapField);
+        } else {
+          return sizeof(RepeatedPtrField<Message>);
+        }
+
+      case FD::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            return sizeof(RepeatedPtrField<std::string>);
+        }
+        break;
+    }
+  } else {
+    switch (field->cpp_type()) {
+      case FD::CPPTYPE_INT32:
+        return sizeof(int32_t);
+      case FD::CPPTYPE_INT64:
+        return sizeof(int64_t);
+      case FD::CPPTYPE_UINT32:
+        return sizeof(uint32_t);
+      case FD::CPPTYPE_UINT64:
+        return sizeof(uint64_t);
+      case FD::CPPTYPE_DOUBLE:
+        return sizeof(double);
+      case FD::CPPTYPE_FLOAT:
+        return sizeof(float);
+      case FD::CPPTYPE_BOOL:
+        return sizeof(bool);
+      case FD::CPPTYPE_ENUM:
+        return sizeof(int);
+
+      case FD::CPPTYPE_MESSAGE:
+        return sizeof(Message*);
+
+      case FD::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            return sizeof(ArenaStringPtr);
+        }
+        break;
+    }
+  }
+
+  GOOGLE_LOG(DFATAL) << "Can't get here.";
+  return 0;
+}
+
+inline int DivideRoundingUp(int i, int j) { return (i + (j - 1)) / j; }
+
+static const int kSafeAlignment = sizeof(uint64_t);
+static const int kMaxOneofUnionSize = sizeof(uint64_t);
+
+inline int AlignTo(int offset, int alignment) {
+  return DivideRoundingUp(offset, alignment) * alignment;
+}
+
+// Rounds the given byte offset up to the next offset aligned such that any
+// type may be stored at it.
+inline int AlignOffset(int offset) { return AlignTo(offset, kSafeAlignment); }
+
+#define bitsizeof(T) (sizeof(T) * 8)
+
+}  // namespace
+
+// ===================================================================
+
+class DynamicMessage : public Message {
+ public:
+  explicit DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info);
+
+  // This should only be used by GetPrototypeNoLock() to avoid dead lock.
+  DynamicMessage(DynamicMessageFactory::TypeInfo* type_info, bool lock_factory);
+
+  ~DynamicMessage() override;
+
+  // Called on the prototype after construction to initialize message fields.
+  // Cross linking the default instances allows for fast reflection access of
+  // unset message fields. Without it we would have to go to the MessageFactory
+  // to get the prototype, which is a much more expensive operation.
+  //
+  // Generated messages do not cross-link to avoid dynamic initialization of the
+  // global instances.
+  // Instead, they keep the default instances in the FieldDescriptor objects.
+  void CrossLinkPrototypes();
+
+  // implements Message ----------------------------------------------
+
+  Message* New(Arena* arena) const override;
+
+  int GetCachedSize() const override;
+  void SetCachedSize(int size) const override;
+
+  Metadata GetMetadata() const override;
+
+#if defined(__cpp_lib_destroying_delete) && defined(__cpp_sized_deallocation)
+  static void operator delete(DynamicMessage* msg, std::destroying_delete_t);
+#else
+  // We actually allocate more memory than sizeof(*this) when this
+  // class's memory is allocated via the global operator new. Thus, we need to
+  // manually call the global operator delete. Calling the destructor is taken
+  // care of for us. This makes DynamicMessage compatible with -fsized-delete.
+  // It doesn't work for MSVC though.
+#ifndef _MSC_VER
+  static void operator delete(void* ptr) { ::operator delete(ptr); }
+#endif  // !_MSC_VER
+#endif
+
+ private:
+  DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info,
+                 Arena* arena);
+
+  void SharedCtor(bool lock_factory);
+
+  // Needed to get the offset of the internal metadata member.
+  friend class DynamicMessageFactory;
+
+  bool is_prototype() const;
+
+  inline void* OffsetToPointer(int offset) {
+    return reinterpret_cast<uint8_t*>(this) + offset;
+  }
+  inline const void* OffsetToPointer(int offset) const {
+    return reinterpret_cast<const uint8_t*>(this) + offset;
+  }
+
+  void* MutableRaw(int i);
+  void* MutableExtensionsRaw();
+  void* MutableWeakFieldMapRaw();
+  void* MutableOneofCaseRaw(int i);
+  void* MutableOneofFieldRaw(const FieldDescriptor* f);
+
+  const DynamicMessageFactory::TypeInfo* type_info_;
+  mutable std::atomic<int> cached_byte_size_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
+};
+
+struct DynamicMessageFactory::TypeInfo {
+  int size;
+  int has_bits_offset;
+  int oneof_case_offset;
+  int extensions_offset;
+
+  // Not owned by the TypeInfo.
+  DynamicMessageFactory* factory;  // The factory that created this object.
+  const DescriptorPool* pool;      // The factory's DescriptorPool.
+  const Descriptor* type;          // Type of this DynamicMessage.
+
+  // Warning:  The order in which the following pointers are defined is
+  //   important (the prototype must be deleted *before* the offsets).
+  std::unique_ptr<uint32_t[]> offsets;
+  std::unique_ptr<uint32_t[]> has_bits_indices;
+  std::unique_ptr<const Reflection> reflection;
+  // Don't use a unique_ptr to hold the prototype: the destructor for
+  // DynamicMessage needs to know whether it is the prototype, and does so by
+  // looking back at this field. This would assume details about the
+  // implementation of unique_ptr.
+  const DynamicMessage* prototype;
+  int weak_field_map_offset;  // The offset for the weak_field_map;
+
+  TypeInfo() : prototype(nullptr) {}
+
+  ~TypeInfo() { delete prototype; }
+};
+
+DynamicMessage::DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info)
+    : type_info_(type_info), cached_byte_size_(0) {
+  SharedCtor(true);
+}
+
+DynamicMessage::DynamicMessage(const DynamicMessageFactory::TypeInfo* type_info,
+                               Arena* arena)
+    : Message(arena), type_info_(type_info), cached_byte_size_(0) {
+  SharedCtor(true);
+}
+
+DynamicMessage::DynamicMessage(DynamicMessageFactory::TypeInfo* type_info,
+                               bool lock_factory)
+    : type_info_(type_info), cached_byte_size_(0) {
+  // The prototype in type_info has to be set before creating the prototype
+  // instance on memory. e.g., message Foo { map<int32_t, Foo> a = 1; }. When
+  // creating prototype for Foo, prototype of the map entry will also be
+  // created, which needs the address of the prototype of Foo (the value in
+  // map). To break the cyclic dependency, we have to assign the address of
+  // prototype into type_info first.
+  type_info->prototype = this;
+  SharedCtor(lock_factory);
+}
+
+inline void* DynamicMessage::MutableRaw(int i) {
+  return OffsetToPointer(type_info_->offsets[i]);
+}
+inline void* DynamicMessage::MutableExtensionsRaw() {
+  return OffsetToPointer(type_info_->extensions_offset);
+}
+inline void* DynamicMessage::MutableWeakFieldMapRaw() {
+  return OffsetToPointer(type_info_->weak_field_map_offset);
+}
+inline void* DynamicMessage::MutableOneofCaseRaw(int i) {
+  return OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32_t) * i);
+}
+inline void* DynamicMessage::MutableOneofFieldRaw(const FieldDescriptor* f) {
+  return OffsetToPointer(type_info_->offsets[type_info_->type->field_count() +
+                                             f->containing_oneof()->index()]);
+}
+
+void DynamicMessage::SharedCtor(bool lock_factory) {
+  // We need to call constructors for various fields manually and set
+  // default values where appropriate.  We use placement new to call
+  // constructors.  If you haven't heard of placement new, I suggest Googling
+  // it now.  We use placement new even for primitive types that don't have
+  // constructors for consistency.  (In theory, placement new should be used
+  // any time you are trying to convert untyped memory to typed memory, though
+  // in practice that's not strictly necessary for types that don't have a
+  // constructor.)
+
+  const Descriptor* descriptor = type_info_->type;
+  // Initialize oneof cases.
+  int oneof_count = 0;
+  for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
+    if (descriptor->oneof_decl(i)->is_synthetic()) continue;
+    new (MutableOneofCaseRaw(oneof_count++)) uint32_t{0};
+  }
+
+  if (type_info_->extensions_offset != -1) {
+    new (MutableExtensionsRaw()) ExtensionSet(GetArenaForAllocation());
+  }
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    void* field_ptr = MutableRaw(i);
+    if (InRealOneof(field)) {
+      continue;
+    }
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                                  \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                          \
+    if (!field->is_repeated()) {                                    \
+      new (field_ptr) TYPE(field->default_value_##TYPE());          \
+    } else {                                                        \
+      new (field_ptr) RepeatedField<TYPE>(GetArenaForAllocation()); \
+    }                                                               \
+    break;
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_ENUM:
+        if (!field->is_repeated()) {
+          new (field_ptr) int{field->default_value_enum()->number()};
+        } else {
+          new (field_ptr) RepeatedField<int>(GetArenaForAllocation());
+        }
+        break;
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            if (!field->is_repeated()) {
+              ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
+              asp->InitDefault();
+            } else {
+              new (field_ptr)
+                  RepeatedPtrField<std::string>(GetArenaForAllocation());
+            }
+            break;
+        }
+        break;
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        if (!field->is_repeated()) {
+          new (field_ptr) Message*(nullptr);
+        } else {
+          if (IsMapFieldInApi(field)) {
+            // We need to lock in most cases to avoid data racing. Only not lock
+            // when the constructor is called inside GetPrototype(), in which
+            // case we have already locked the factory.
+            if (lock_factory) {
+              if (GetArenaForAllocation() != nullptr) {
+                new (field_ptr) DynamicMapField(
+                    type_info_->factory->GetPrototype(field->message_type()),
+                    GetArenaForAllocation());
+                if (GetOwningArena() != nullptr) {
+                  // Needs to destroy the mutex member.
+                  GetOwningArena()->OwnDestructor(
+                      static_cast<DynamicMapField*>(field_ptr));
+                }
+              } else {
+                new (field_ptr) DynamicMapField(
+                    type_info_->factory->GetPrototype(field->message_type()));
+              }
+            } else {
+              if (GetArenaForAllocation() != nullptr) {
+                new (field_ptr)
+                    DynamicMapField(type_info_->factory->GetPrototypeNoLock(
+                                        field->message_type()),
+                                    GetArenaForAllocation());
+                if (GetOwningArena() != nullptr) {
+                  // Needs to destroy the mutex member.
+                  GetOwningArena()->OwnDestructor(
+                      static_cast<DynamicMapField*>(field_ptr));
+                }
+              } else {
+                new (field_ptr)
+                    DynamicMapField(type_info_->factory->GetPrototypeNoLock(
+                        field->message_type()));
+              }
+            }
+          } else {
+            new (field_ptr) RepeatedPtrField<Message>(GetArenaForAllocation());
+          }
+        }
+        break;
+      }
+    }
+  }
+}
+
+bool DynamicMessage::is_prototype() const {
+  return type_info_->prototype == this ||
+         // If type_info_->prototype is nullptr, then we must be constructing
+         // the prototype now, which means we must be the prototype.
+         type_info_->prototype == nullptr;
+}
+
+#if defined(__cpp_lib_destroying_delete) && defined(__cpp_sized_deallocation)
+void DynamicMessage::operator delete(DynamicMessage* msg,
+                                     std::destroying_delete_t) {
+  const size_t size = msg->type_info_->size;
+  msg->~DynamicMessage();
+  ::operator delete(msg, size);
+}
+#endif
+
+DynamicMessage::~DynamicMessage() {
+  const Descriptor* descriptor = type_info_->type;
+
+  _internal_metadata_.Delete<UnknownFieldSet>();
+
+  if (type_info_->extensions_offset != -1) {
+    reinterpret_cast<ExtensionSet*>(MutableExtensionsRaw())->~ExtensionSet();
+  }
+
+  // We need to manually run the destructors for repeated fields and strings,
+  // just as we ran their constructors in the DynamicMessage constructor.
+  // We also need to manually delete oneof fields if it is set and is string
+  // or message.
+  // Additionally, if any singular embedded messages have been allocated, we
+  // need to delete them, UNLESS we are the prototype message of this type,
+  // in which case any embedded messages are other prototypes and shouldn't
+  // be touched.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (InRealOneof(field)) {
+      void* field_ptr = MutableOneofCaseRaw(field->containing_oneof()->index());
+      if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) {
+        field_ptr = MutableOneofFieldRaw(field);
+        if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+          switch (field->options().ctype()) {
+            default:
+            case FieldOptions::STRING: {
+              reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
+              break;
+            }
+          }
+        } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+            delete *reinterpret_cast<Message**>(field_ptr);
+        }
+      }
+      continue;
+    }
+    void* field_ptr = MutableRaw(i);
+
+    if (field->is_repeated()) {
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                  \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:               \
+    reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
+        ->~RepeatedField<LOWERCASE>();                     \
+    break
+
+        HANDLE_TYPE(INT32, int32_t);
+        HANDLE_TYPE(INT64, int64_t);
+        HANDLE_TYPE(UINT32, uint32_t);
+        HANDLE_TYPE(UINT64, uint64_t);
+        HANDLE_TYPE(DOUBLE, double);
+        HANDLE_TYPE(FLOAT, float);
+        HANDLE_TYPE(BOOL, bool);
+        HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_STRING:
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              reinterpret_cast<RepeatedPtrField<std::string>*>(field_ptr)
+                  ->~RepeatedPtrField<std::string>();
+              break;
+          }
+          break;
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (IsMapFieldInApi(field)) {
+            reinterpret_cast<DynamicMapField*>(field_ptr)->~DynamicMapField();
+          } else {
+            reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
+                ->~RepeatedPtrField<Message>();
+          }
+          break;
+      }
+
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      switch (field->options().ctype()) {
+        default:  // TODO(kenton):  Support other string reps.
+        case FieldOptions::STRING: {
+          reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
+          break;
+        }
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          if (!is_prototype()) {
+        Message* message = *reinterpret_cast<Message**>(field_ptr);
+        if (message != nullptr) {
+          delete message;
+        }
+      }
+    }
+  }
+}
+
+void DynamicMessage::CrossLinkPrototypes() {
+  // This should only be called on the prototype message.
+  GOOGLE_CHECK(is_prototype());
+
+  DynamicMessageFactory* factory = type_info_->factory;
+  const Descriptor* descriptor = type_info_->type;
+
+  // Cross-link default messages.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !field->options().weak() && !InRealOneof(field) &&
+        !field->is_repeated()) {
+      void* field_ptr = MutableRaw(i);
+      // For fields with message types, we need to cross-link with the
+      // prototype for the field's type.
+      // For singular fields, the field is just a pointer which should
+      // point to the prototype.
+      *reinterpret_cast<const Message**>(field_ptr) =
+          factory->GetPrototypeNoLock(field->message_type());
+    }
+  }
+}
+
+Message* DynamicMessage::New(Arena* arena) const {
+  if (arena != nullptr) {
+    void* new_base = Arena::CreateArray<char>(arena, type_info_->size);
+    memset(new_base, 0, type_info_->size);
+    return new (new_base) DynamicMessage(type_info_, arena);
+  } else {
+    void* new_base = operator new(type_info_->size);
+    memset(new_base, 0, type_info_->size);
+    return new (new_base) DynamicMessage(type_info_);
+  }
+}
+
+int DynamicMessage::GetCachedSize() const {
+  return cached_byte_size_.load(std::memory_order_relaxed);
+}
+
+void DynamicMessage::SetCachedSize(int size) const {
+  cached_byte_size_.store(size, std::memory_order_relaxed);
+}
+
+Metadata DynamicMessage::GetMetadata() const {
+  Metadata metadata;
+  metadata.descriptor = type_info_->type;
+  metadata.reflection = type_info_->reflection.get();
+  return metadata;
+}
+
+// ===================================================================
+
+DynamicMessageFactory::DynamicMessageFactory()
+    : pool_(nullptr), delegate_to_generated_factory_(false) {}
+
+DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
+    : pool_(pool), delegate_to_generated_factory_(false) {}
+
+DynamicMessageFactory::~DynamicMessageFactory() {
+  for (auto iter = prototypes_.begin(); iter != prototypes_.end(); ++iter) {
+    delete iter->second;
+  }
+}
+
+const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
+  MutexLock lock(&prototypes_mutex_);
+  return GetPrototypeNoLock(type);
+}
+
+const Message* DynamicMessageFactory::GetPrototypeNoLock(
+    const Descriptor* type) {
+  if (delegate_to_generated_factory_ &&
+      type->file()->pool() == DescriptorPool::generated_pool()) {
+    return MessageFactory::generated_factory()->GetPrototype(type);
+  }
+
+  const TypeInfo** target = &prototypes_[type];
+  if (*target != nullptr) {
+    // Already exists.
+    return (*target)->prototype;
+  }
+
+  TypeInfo* type_info = new TypeInfo;
+  *target = type_info;
+
+  type_info->type = type;
+  type_info->pool = (pool_ == nullptr) ? type->file()->pool() : pool_;
+  type_info->factory = this;
+
+  // We need to construct all the structures passed to Reflection's constructor.
+  // This includes:
+  // - A block of memory that contains space for all the message's fields.
+  // - An array of integers indicating the byte offset of each field within
+  //   this block.
+  // - A big bitfield containing a bit for each field indicating whether
+  //   or not that field is set.
+  int real_oneof_count = 0;
+  for (int i = 0; i < type->oneof_decl_count(); i++) {
+    if (!type->oneof_decl(i)->is_synthetic()) {
+      real_oneof_count++;
+    }
+  }
+
+  // Compute size and offsets.
+  uint32_t* offsets = new uint32_t[type->field_count() + real_oneof_count];
+  type_info->offsets.reset(offsets);
+
+  // Decide all field offsets by packing in order.
+  // We place the DynamicMessage object itself at the beginning of the allocated
+  // space.
+  int size = sizeof(DynamicMessage);
+  size = AlignOffset(size);
+
+  // Next the has_bits, which is an array of uint32s.
+  type_info->has_bits_offset = -1;
+  int max_hasbit = 0;
+  for (int i = 0; i < type->field_count(); i++) {
+    if (HasHasbit(type->field(i))) {
+      if (type_info->has_bits_offset == -1) {
+        // At least one field in the message requires a hasbit, so allocate
+        // hasbits.
+        type_info->has_bits_offset = size;
+        uint32_t* has_bits_indices = new uint32_t[type->field_count()];
+        for (int j = 0; j < type->field_count(); j++) {
+          // Initialize to -1, fields that need a hasbit will overwrite.
+          has_bits_indices[j] = static_cast<uint32_t>(-1);
+        }
+        type_info->has_bits_indices.reset(has_bits_indices);
+      }
+      type_info->has_bits_indices[i] = max_hasbit++;
+    }
+  }
+
+  if (max_hasbit > 0) {
+    int has_bits_array_size = DivideRoundingUp(max_hasbit, bitsizeof(uint32_t));
+    size += has_bits_array_size * sizeof(uint32_t);
+    size = AlignOffset(size);
+  }
+
+  // The oneof_case, if any. It is an array of uint32s.
+  if (real_oneof_count > 0) {
+    type_info->oneof_case_offset = size;
+    size += real_oneof_count * sizeof(uint32_t);
+    size = AlignOffset(size);
+  }
+
+  // The ExtensionSet, if any.
+  if (type->extension_range_count() > 0) {
+    type_info->extensions_offset = size;
+    size += sizeof(ExtensionSet);
+    size = AlignOffset(size);
+  } else {
+    // No extensions.
+    type_info->extensions_offset = -1;
+  }
+
+  // All the fields.
+  //
+  // TODO(b/31226269):  Optimize the order of fields to minimize padding.
+  for (int i = 0; i < type->field_count(); i++) {
+    // Make sure field is aligned to avoid bus errors.
+    // Oneof fields do not use any space.
+    if (!InRealOneof(type->field(i))) {
+      int field_size = FieldSpaceUsed(type->field(i));
+      size = AlignTo(size, std::min(kSafeAlignment, field_size));
+      offsets[i] = size;
+      size += field_size;
+    }
+  }
+
+  // The oneofs.
+  for (int i = 0; i < type->oneof_decl_count(); i++) {
+    if (!type->oneof_decl(i)->is_synthetic()) {
+      size = AlignTo(size, kSafeAlignment);
+      offsets[type->field_count() + i] = size;
+      size += kMaxOneofUnionSize;
+    }
+  }
+
+  type_info->weak_field_map_offset = -1;
+
+  // Align the final size to make sure no clever allocators think that
+  // alignment is not necessary.
+  type_info->size = size;
+
+  // Construct the reflection object.
+
+  // Compute the size of default oneof instance and offsets of default
+  // oneof fields.
+  for (int i = 0; i < type->oneof_decl_count(); i++) {
+    if (type->oneof_decl(i)->is_synthetic()) continue;
+    for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = type->oneof_decl(i)->field(j);
+      // oneof fields are not accessed through offsets, but we still have the
+      // entry from a legacy implementation. This should be removed at some
+      // point.
+      // Mark the field to prevent unintentional access through reflection.
+      // Don't use the top bit because that is for unused fields.
+      offsets[field->index()] = internal::kInvalidFieldOffsetTag;
+    }
+  }
+
+  // Allocate the prototype fields.
+  void* base = operator new(size);
+  memset(base, 0, size);
+
+  // We have already locked the factory so we should not lock in the constructor
+  // of dynamic message to avoid dead lock.
+  DynamicMessage* prototype = new (base) DynamicMessage(type_info, false);
+
+  internal::ReflectionSchema schema = {
+      type_info->prototype,
+      type_info->offsets.get(),
+      type_info->has_bits_indices.get(),
+      type_info->has_bits_offset,
+      PROTOBUF_FIELD_OFFSET(DynamicMessage, _internal_metadata_),
+      type_info->extensions_offset,
+      type_info->oneof_case_offset,
+      type_info->size,
+      type_info->weak_field_map_offset,
+      nullptr /* inlined_string_indices_ */,
+      0 /* inlined_string_donated_offset_ */};
+
+  type_info->reflection.reset(
+      new Reflection(type_info->type, schema, type_info->pool, this));
+
+  // Cross link prototypes.
+  prototype->CrossLinkPrototypes();
+
+  return prototype;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>  // NOLINT
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/empty.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/empty.pb.cpp
new file mode 100644
index 0000000..3a30776
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/empty.pb.cpp
@@ -0,0 +1,130 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#include <google/protobuf/empty.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Empty::Empty(
+    ::_pbi::ConstantInitialized) {}
+struct EmptyDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EmptyDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EmptyDefaultTypeInternal() {}
+  union {
+    Empty _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EmptyDefaultTypeInternal _Empty_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fempty_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Empty, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Empty)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Empty_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\033google/protobuf/empty.proto\022\017google.pr"
+  "otobuf\"\007\n\005EmptyB}\n\023com.google.protobufB\n"
+  "EmptyProtoP\001Z.google.golang.org/protobuf"
+  "/types/known/emptypb\370\001\001\242\002\003GPB\252\002\036Google.P"
+  "rotobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fempty_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
+    false, false, 190, descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto,
+    "google/protobuf/empty.proto",
+    &descriptor_table_google_2fprotobuf_2fempty_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fempty_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fempty_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fempty_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fempty_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fempty_2eproto(&descriptor_table_google_2fprotobuf_2fempty_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Empty::_Internal {
+ public:
+};
+
+Empty::Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase(arena, is_message_owned) {
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
+}
+Empty::Empty(const Empty& from)
+  : ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase() {
+  Empty* const _this = this; (void)_this;
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Empty)
+}
+
+
+
+
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Empty::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::CopyImpl,
+    ::PROTOBUF_NAMESPACE_ID::internal::ZeroFieldsBase::MergeImpl,
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Empty::GetClassData() const { return &_class_data_; }
+
+
+
+
+
+
+
+::PROTOBUF_NAMESPACE_ID::Metadata Empty::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fempty_2eproto_getter, &descriptor_table_google_2fprotobuf_2fempty_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fempty_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Empty*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Empty >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Empty >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/extension_set.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/extension_set.cpp
new file mode 100644
index 0000000..fada4f5
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/extension_set.cpp
@@ -0,0 +1,1967 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/extension_set.h>
+
+#include <tuple>
+#include <unordered_set>
+#include <utility>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>  // must be last.
+// clang-format on
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+inline WireFormatLite::FieldType real_type(FieldType type) {
+  GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
+  return static_cast<WireFormatLite::FieldType>(type);
+}
+
+inline WireFormatLite::CppType cpp_type(FieldType type) {
+  return WireFormatLite::FieldTypeToCppType(real_type(type));
+}
+
+// Registry stuff.
+
+// Note that we cannot use hetererogeneous lookup for std containers since we
+// need to support C++11.
+struct ExtensionEq {
+  bool operator()(const ExtensionInfo& lhs, const ExtensionInfo& rhs) const {
+    return lhs.message == rhs.message && lhs.number == rhs.number;
+  }
+};
+
+struct ExtensionHasher {
+  std::size_t operator()(const ExtensionInfo& info) const {
+    return std::hash<const MessageLite*>{}(info.message) ^
+           std::hash<int>{}(info.number);
+  }
+};
+
+using ExtensionRegistry =
+    std::unordered_set<ExtensionInfo, ExtensionHasher, ExtensionEq>;
+
+static const ExtensionRegistry* global_registry = nullptr;
+
+// This function is only called at startup, so there is no need for thread-
+// safety.
+void Register(const ExtensionInfo& info) {
+  static auto local_static_registry = OnShutdownDelete(new ExtensionRegistry);
+  global_registry = local_static_registry;
+  if (!InsertIfNotPresent(local_static_registry, info)) {
+    GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
+               << info.message->GetTypeName() << "\", field number "
+               << info.number << ".";
+  }
+}
+
+const ExtensionInfo* FindRegisteredExtension(const MessageLite* extendee,
+                                             int number) {
+  if (!global_registry) return nullptr;
+
+  ExtensionInfo info;
+  info.message = extendee;
+  info.number = number;
+
+  auto it = global_registry->find(info);
+  if (it == global_registry->end()) {
+    return nullptr;
+  } else {
+    return &*it;
+  }
+}
+
+}  // namespace
+
+bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) {
+  const ExtensionInfo* extension = FindRegisteredExtension(extendee_, number);
+  if (extension == nullptr) {
+    return false;
+  } else {
+    *output = *extension;
+    return true;
+  }
+}
+
+void ExtensionSet::RegisterExtension(const MessageLite* extendee, int number,
+                                     FieldType type, bool is_repeated,
+                                     bool is_packed,
+                                     LazyEagerVerifyFnType verify_func) {
+  GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_ENUM);
+  GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_MESSAGE);
+  GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_GROUP);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed,
+                     verify_func);
+  Register(info);
+}
+
+static bool CallNoArgValidityFunc(const void* arg, int number) {
+  // Note:  Must use C-style cast here rather than reinterpret_cast because
+  //   the C++ standard at one point did not allow casts between function and
+  //   data pointers and some compilers enforce this for C++-style casts.  No
+  //   compiler enforces it for C-style casts since lots of C-style code has
+  //   relied on these kinds of casts for a long time, despite being
+  //   technically undefined.  See:
+  //     http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195
+  // Also note:  Some compilers do not allow function pointers to be "const".
+  //   Which makes sense, I suppose, because it's meaningless.
+  return ((EnumValidityFunc*)arg)(number);
+}
+
+void ExtensionSet::RegisterEnumExtension(const MessageLite* extendee,
+                                         int number, FieldType type,
+                                         bool is_repeated, bool is_packed,
+                                         EnumValidityFunc* is_valid) {
+  GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed, nullptr);
+  info.enum_validity_check.func = CallNoArgValidityFunc;
+  // See comment in CallNoArgValidityFunc() about why we use a c-style cast.
+  info.enum_validity_check.arg = (void*)is_valid;
+  Register(info);
+}
+
+void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
+                                            int number, FieldType type,
+                                            bool is_repeated, bool is_packed,
+                                            const MessageLite* prototype,
+                                            LazyEagerVerifyFnType verify_func) {
+  GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
+        type == WireFormatLite::TYPE_GROUP);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed,
+                     verify_func);
+  info.message_info = {prototype};
+  Register(info);
+}
+
+// ===================================================================
+// Constructors and basic methods.
+
+ExtensionSet::ExtensionSet(Arena* arena)
+    : arena_(arena),
+      flat_capacity_(0),
+      flat_size_(0),
+      map_{flat_capacity_ == 0
+               ? nullptr
+               : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {}
+
+ExtensionSet::~ExtensionSet() {
+  // Deletes all allocated extensions.
+  if (arena_ == nullptr) {
+    ForEach([](int /* number */, Extension& ext) { ext.Free(); });
+    if (PROTOBUF_PREDICT_FALSE(is_large())) {
+      delete map_.large;
+    } else {
+      DeleteFlatMap(map_.flat, flat_capacity_);
+    }
+  }
+}
+
+void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat,
+                                 uint16_t flat_capacity) {
+  // Arena::CreateArray already requires a trivially destructible type, but
+  // ensure this constraint is not violated in the future.
+  static_assert(std::is_trivially_destructible<KeyValue>::value,
+                "CreateArray requires a trivially destructible type");
+  // A const-cast is needed, but this is safe as we are about to deallocate the
+  // array.
+  internal::SizedArrayDelete(const_cast<KeyValue*>(flat),
+                             sizeof(*flat) * flat_capacity);
+}
+
+// Defined in extension_set_heavy.cc.
+// void ExtensionSet::AppendToList(const Descriptor* extendee,
+//                                 const DescriptorPool* pool,
+//                                 vector<const FieldDescriptor*>* output) const
+
+bool ExtensionSet::Has(int number) const {
+  const Extension* ext = FindOrNull(number);
+  if (ext == nullptr) return false;
+  GOOGLE_DCHECK(!ext->is_repeated);
+  return !ext->is_cleared;
+}
+
+bool ExtensionSet::HasLazy(int number) const {
+  return Has(number) && FindOrNull(number)->is_lazy;
+}
+
+int ExtensionSet::NumExtensions() const {
+  int result = 0;
+  ForEach([&result](int /* number */, const Extension& ext) {
+    if (!ext.is_cleared) {
+      ++result;
+    }
+  });
+  return result;
+}
+
+int ExtensionSet::ExtensionSize(int number) const {
+  const Extension* ext = FindOrNull(number);
+  return ext == nullptr ? 0 : ext->GetSize();
+}
+
+FieldType ExtensionSet::ExtensionType(int number) const {
+  const Extension* ext = FindOrNull(number);
+  if (ext == nullptr) {
+    GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (1). ";
+    return 0;
+  }
+  if (ext->is_cleared) {
+    GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (2). ";
+  }
+  return ext->type;
+}
+
+void ExtensionSet::ClearExtension(int number) {
+  Extension* ext = FindOrNull(number);
+  if (ext == nullptr) return;
+  ext->Clear();
+}
+
+// ===================================================================
+// Field accessors
+
+namespace {
+
+enum { REPEATED_FIELD, OPTIONAL_FIELD };
+
+}  // namespace
+
+#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                                 \
+  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? REPEATED_FIELD : OPTIONAL_FIELD, LABEL); \
+  GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), WireFormatLite::CPPTYPE_##CPPTYPE)
+
+// -------------------------------------------------------------------
+// Primitives
+
+#define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE)                  \
+                                                                              \
+  LOWERCASE ExtensionSet::Get##CAMELCASE(int number, LOWERCASE default_value) \
+      const {                                                                 \
+    const Extension* extension = FindOrNull(number);                          \
+    if (extension == nullptr || extension->is_cleared) {                      \
+      return default_value;                                                   \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+      return extension->LOWERCASE##_value;                                    \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
+  const LOWERCASE& ExtensionSet::GetRef##CAMELCASE(                           \
+      int number, const LOWERCASE& default_value) const {                     \
+    const Extension* extension = FindOrNull(number);                          \
+    if (extension == nullptr || extension->is_cleared) {                      \
+      return default_value;                                                   \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+      return extension->LOWERCASE##_value;                                    \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
+  void ExtensionSet::Set##CAMELCASE(int number, FieldType type,               \
+                                    LOWERCASE value,                          \
+                                    const FieldDescriptor* descriptor) {      \
+    Extension* extension;                                                     \
+    if (MaybeNewExtension(number, descriptor, &extension)) {                  \
+      extension->type = type;                                                 \
+      GOOGLE_DCHECK_EQ(cpp_type(extension->type),                                    \
+                WireFormatLite::CPPTYPE_##UPPERCASE);                         \
+      extension->is_repeated = false;                                         \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                     \
+    }                                                                         \
+    extension->is_cleared = false;                                            \
+    extension->LOWERCASE##_value = value;                                     \
+  }                                                                           \
+                                                                              \
+  LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index)       \
+      const {                                                                 \
+    const Extension* extension = FindOrNull(number);                          \
+    GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";   \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    return extension->repeated_##LOWERCASE##_value->Get(index);               \
+  }                                                                           \
+                                                                              \
+  const LOWERCASE& ExtensionSet::GetRefRepeated##CAMELCASE(int number,        \
+                                                           int index) const { \
+    const Extension* extension = FindOrNull(number);                          \
+    GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";   \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    return extension->repeated_##LOWERCASE##_value->Get(index);               \
+  }                                                                           \
+                                                                              \
+  void ExtensionSet::SetRepeated##CAMELCASE(int number, int index,            \
+                                            LOWERCASE value) {                \
+    Extension* extension = FindOrNull(number);                                \
+    GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";   \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                       \
+    extension->repeated_##LOWERCASE##_value->Set(index, value);               \
+  }                                                                           \
+                                                                              \
+  void ExtensionSet::Add##CAMELCASE(int number, FieldType type, bool packed,  \
+                                    LOWERCASE value,                          \
+                                    const FieldDescriptor* descriptor) {      \
+    Extension* extension;                                                     \
+    if (MaybeNewExtension(number, descriptor, &extension)) {                  \
+      extension->type = type;                                                 \
+      GOOGLE_DCHECK_EQ(cpp_type(extension->type),                                    \
+                WireFormatLite::CPPTYPE_##UPPERCASE);                         \
+      extension->is_repeated = true;                                          \
+      extension->is_packed = packed;                                          \
+      extension->repeated_##LOWERCASE##_value =                               \
+          Arena::CreateMessage<RepeatedField<LOWERCASE>>(arena_);             \
+    } else {                                                                  \
+      GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                     \
+      GOOGLE_DCHECK_EQ(extension->is_packed, packed);                                \
+    }                                                                         \
+    extension->repeated_##LOWERCASE##_value->Add(value);                      \
+  }
+
+PRIMITIVE_ACCESSORS(INT32, int32_t, Int32)
+PRIMITIVE_ACCESSORS(INT64, int64_t, Int64)
+PRIMITIVE_ACCESSORS(UINT32, uint32_t, UInt32)
+PRIMITIVE_ACCESSORS(UINT64, uint64_t, UInt64)
+PRIMITIVE_ACCESSORS(FLOAT, float, Float)
+PRIMITIVE_ACCESSORS(DOUBLE, double, Double)
+PRIMITIVE_ACCESSORS(BOOL, bool, Bool)
+
+#undef PRIMITIVE_ACCESSORS
+
+const void* ExtensionSet::GetRawRepeatedField(int number,
+                                              const void* default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    return default_value;
+  }
+  // We assume that all the RepeatedField<>* pointers have the same
+  // size and alignment within the anonymous union in Extension.
+  return extension->repeated_int32_t_value;
+}
+
+void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
+                                            bool packed,
+                                            const FieldDescriptor* desc) {
+  Extension* extension;
+
+  // We instantiate an empty Repeated{,Ptr}Field if one doesn't exist for this
+  // extension.
+  if (MaybeNewExtension(number, desc, &extension)) {
+    extension->is_repeated = true;
+    extension->type = field_type;
+    extension->is_packed = packed;
+
+    switch (WireFormatLite::FieldTypeToCppType(
+        static_cast<WireFormatLite::FieldType>(field_type))) {
+      case WireFormatLite::CPPTYPE_INT32:
+        extension->repeated_int32_t_value =
+            Arena::CreateMessage<RepeatedField<int32_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_INT64:
+        extension->repeated_int64_t_value =
+            Arena::CreateMessage<RepeatedField<int64_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_UINT32:
+        extension->repeated_uint32_t_value =
+            Arena::CreateMessage<RepeatedField<uint32_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_UINT64:
+        extension->repeated_uint64_t_value =
+            Arena::CreateMessage<RepeatedField<uint64_t>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_DOUBLE:
+        extension->repeated_double_value =
+            Arena::CreateMessage<RepeatedField<double>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_FLOAT:
+        extension->repeated_float_value =
+            Arena::CreateMessage<RepeatedField<float>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_BOOL:
+        extension->repeated_bool_value =
+            Arena::CreateMessage<RepeatedField<bool>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_ENUM:
+        extension->repeated_enum_value =
+            Arena::CreateMessage<RepeatedField<int>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_STRING:
+        extension->repeated_string_value =
+            Arena::CreateMessage<RepeatedPtrField<std::string>>(arena_);
+        break;
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        extension->repeated_message_value =
+            Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_);
+        break;
+    }
+  }
+
+  // We assume that all the RepeatedField<>* pointers have the same
+  // size and alignment within the anonymous union in Extension.
+  return extension->repeated_int32_t_value;
+}
+
+// Compatible version using old call signature. Does not create extensions when
+// the don't already exist; instead, just GOOGLE_CHECK-fails.
+void* ExtensionSet::MutableRawRepeatedField(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Extension not found.";
+  // We assume that all the RepeatedField<>* pointers have the same
+  // size and alignment within the anonymous union in Extension.
+  return extension->repeated_int32_t_value;
+}
+
+// -------------------------------------------------------------------
+// Enums
+
+int ExtensionSet::GetEnum(int number, int default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+    return extension->enum_value;
+  }
+}
+
+const int& ExtensionSet::GetRefEnum(int number,
+                                    const int& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+    return extension->enum_value;
+  }
+}
+
+void ExtensionSet::SetEnum(int number, FieldType type, int value,
+                           const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
+    extension->is_repeated = false;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
+  }
+  extension->is_cleared = false;
+  extension->enum_value = value;
+}
+
+int ExtensionSet::GetRepeatedEnum(int number, int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  return extension->repeated_enum_value->Get(index);
+}
+
+const int& ExtensionSet::GetRefRepeatedEnum(int number, int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  return extension->repeated_enum_value->Get(index);
+}
+
+void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+  extension->repeated_enum_value->Set(index, value);
+}
+
+void ExtensionSet::AddEnum(int number, FieldType type, bool packed, int value,
+                           const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
+    extension->is_repeated = true;
+    extension->is_packed = packed;
+    extension->repeated_enum_value =
+        Arena::CreateMessage<RepeatedField<int>>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
+    GOOGLE_DCHECK_EQ(extension->is_packed, packed);
+  }
+  extension->repeated_enum_value->Add(value);
+}
+
+// -------------------------------------------------------------------
+// Strings
+
+const std::string& ExtensionSet::GetString(
+    int number, const std::string& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
+    return *extension->string_value;
+  }
+}
+
+std::string* ExtensionSet::MutableString(int number, FieldType type,
+                                         const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
+    extension->is_repeated = false;
+    extension->string_value = Arena::Create<std::string>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
+  }
+  extension->is_cleared = false;
+  return extension->string_value;
+}
+
+const std::string& ExtensionSet::GetRepeatedString(int number,
+                                                   int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
+  return extension->repeated_string_value->Get(index);
+}
+
+std::string* ExtensionSet::MutableRepeatedString(int number, int index) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
+  return extension->repeated_string_value->Mutable(index);
+}
+
+std::string* ExtensionSet::AddString(int number, FieldType type,
+                                     const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
+    extension->is_repeated = true;
+    extension->is_packed = false;
+    extension->repeated_string_value =
+        Arena::CreateMessage<RepeatedPtrField<std::string>>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
+  }
+  return extension->repeated_string_value->Add();
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+const MessageLite& ExtensionSet::GetMessage(
+    int number, const MessageLite& default_value) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    // Not present.  Return the default value.
+    return default_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->GetMessage(default_value, arena_);
+    } else {
+      return *extension->message_value;
+    }
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// const MessageLite& ExtensionSet::GetMessage(int number,
+//                                             const Descriptor* message_type,
+//                                             MessageFactory* factory) const
+
+MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
+                                          const MessageLite& prototype,
+                                          const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    extension->message_value = prototype.New(arena_);
+    extension->is_cleared = false;
+    return extension->message_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    extension->is_cleared = false;
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->MutableMessage(prototype, arena_);
+    } else {
+      return extension->message_value;
+    }
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
+//                                           const Descriptor* message_type,
+//                                           MessageFactory* factory)
+
+void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
+                                       const FieldDescriptor* descriptor,
+                                       MessageLite* message) {
+  if (message == nullptr) {
+    ClearExtension(number);
+    return;
+  }
+  GOOGLE_DCHECK(message->GetOwningArena() == nullptr ||
+         message->GetOwningArena() == arena_);
+  Arena* message_arena = message->GetOwningArena();
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    if (message_arena == arena_) {
+      extension->message_value = message;
+    } else if (message_arena == nullptr) {
+      extension->message_value = message;
+      arena_->Own(message);  // not nullptr because not equal to message_arena
+    } else {
+      extension->message_value = message->New(arena_);
+      extension->message_value->CheckTypeAndMergeFrom(*message);
+    }
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->SetAllocatedMessage(message, arena_);
+    } else {
+      if (arena_ == nullptr) {
+        delete extension->message_value;
+      }
+      if (message_arena == arena_) {
+        extension->message_value = message;
+      } else if (message_arena == nullptr) {
+        extension->message_value = message;
+        arena_->Own(message);  // not nullptr because not equal to message_arena
+      } else {
+        extension->message_value = message->New(arena_);
+        extension->message_value->CheckTypeAndMergeFrom(*message);
+      }
+    }
+  }
+  extension->is_cleared = false;
+}
+
+void ExtensionSet::UnsafeArenaSetAllocatedMessage(
+    int number, FieldType type, const FieldDescriptor* descriptor,
+    MessageLite* message) {
+  if (message == nullptr) {
+    ClearExtension(number);
+    return;
+  }
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    extension->message_value = message;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message,
+                                                                   arena_);
+    } else {
+      if (arena_ == nullptr) {
+        delete extension->message_value;
+      }
+      extension->message_value = message;
+    }
+  }
+  extension->is_cleared = false;
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(int number,
+                                          const MessageLite& prototype) {
+  Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->ReleaseMessage(prototype, arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      if (arena_ == nullptr) {
+        ret = extension->message_value;
+      } else {
+        // ReleaseMessage() always returns a heap-allocated message, and we are
+        // on an arena, so we need to make a copy of this message to return.
+        ret = extension->message_value->New();
+        ret->CheckTypeAndMergeFrom(*extension->message_value);
+      }
+    }
+    Erase(number);
+    return ret;
+  }
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+    int number, const MessageLite& prototype) {
+  Extension* extension = FindOrNull(number);
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(prototype,
+                                                                    arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      ret = extension->message_value;
+    }
+    Erase(number);
+    return ret;
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+//                                           MessageFactory* factory);
+
+const MessageLite& ExtensionSet::GetRepeatedMessage(int number,
+                                                    int index) const {
+  const Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
+  return extension->repeated_message_value->Get(index);
+}
+
+MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
+  return extension->repeated_message_value->Mutable(index);
+}
+
+MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
+                                      const MessageLite& prototype,
+                                      const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = true;
+    extension->repeated_message_value =
+        Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
+  }
+
+  // RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
+  // allocate an abstract object, so we have to be tricky.
+  MessageLite* result = reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+                            extension->repeated_message_value)
+                            ->AddFromCleared<GenericTypeHandler<MessageLite>>();
+  if (result == nullptr) {
+    result = prototype.New(arena_);
+    extension->repeated_message_value->AddAllocated(result);
+  }
+  return result;
+}
+
+// Defined in extension_set_heavy.cc.
+// MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
+//                                       const Descriptor* message_type,
+//                                       MessageFactory* factory)
+
+#undef GOOGLE_DCHECK_TYPE
+
+void ExtensionSet::RemoveLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+
+  switch (cpp_type(extension->type)) {
+    case WireFormatLite::CPPTYPE_INT32:
+      extension->repeated_int32_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_INT64:
+      extension->repeated_int64_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_UINT32:
+      extension->repeated_uint32_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_UINT64:
+      extension->repeated_uint64_t_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_FLOAT:
+      extension->repeated_float_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_DOUBLE:
+      extension->repeated_double_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_BOOL:
+      extension->repeated_bool_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_ENUM:
+      extension->repeated_enum_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_STRING:
+      extension->repeated_string_value->RemoveLast();
+      break;
+    case WireFormatLite::CPPTYPE_MESSAGE:
+      extension->repeated_message_value->RemoveLast();
+      break;
+  }
+}
+
+MessageLite* ExtensionSet::ReleaseLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+  GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+  return extension->repeated_message_value->ReleaseLast();
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseLast(int number) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+  GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
+  return extension->repeated_message_value->UnsafeArenaReleaseLast();
+}
+
+void ExtensionSet::SwapElements(int number, int index1, int index2) {
+  Extension* extension = FindOrNull(number);
+  GOOGLE_CHECK(extension != nullptr) << "Index out-of-bounds (field is empty).";
+  GOOGLE_DCHECK(extension->is_repeated);
+
+  switch (cpp_type(extension->type)) {
+    case WireFormatLite::CPPTYPE_INT32:
+      extension->repeated_int32_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_INT64:
+      extension->repeated_int64_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_UINT32:
+      extension->repeated_uint32_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_UINT64:
+      extension->repeated_uint64_t_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_FLOAT:
+      extension->repeated_float_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_DOUBLE:
+      extension->repeated_double_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_BOOL:
+      extension->repeated_bool_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_ENUM:
+      extension->repeated_enum_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_STRING:
+      extension->repeated_string_value->SwapElements(index1, index2);
+      break;
+    case WireFormatLite::CPPTYPE_MESSAGE:
+      extension->repeated_message_value->SwapElements(index1, index2);
+      break;
+  }
+}
+
+// ===================================================================
+
+void ExtensionSet::Clear() {
+  ForEach([](int /* number */, Extension& ext) { ext.Clear(); });
+}
+
+namespace {
+// Computes the size of an ExtensionSet union without actually constructing the
+// union. Note that we do not count cleared extensions from the source to be
+// part of the total, because there is no need to allocate space for those. We
+// do include cleared extensions in the destination, though, because those are
+// already allocated and will not be going away.
+template <typename ItX, typename ItY>
+size_t SizeOfUnion(ItX it_dest, ItX end_dest, ItY it_source, ItY end_source) {
+  size_t result = 0;
+  while (it_dest != end_dest && it_source != end_source) {
+    if (it_dest->first < it_source->first) {
+      ++result;
+      ++it_dest;
+    } else if (it_dest->first == it_source->first) {
+      ++result;
+      ++it_dest;
+      ++it_source;
+    } else {
+      if (!it_source->second.is_cleared) {
+        ++result;
+      }
+      ++it_source;
+    }
+  }
+  result += std::distance(it_dest, end_dest);
+  for (; it_source != end_source; ++it_source) {
+    if (!it_source->second.is_cleared) {
+      ++result;
+    }
+  }
+  return result;
+}
+}  // namespace
+
+void ExtensionSet::MergeFrom(const MessageLite* extendee,
+                             const ExtensionSet& other) {
+  if (PROTOBUF_PREDICT_TRUE(!is_large())) {
+    if (PROTOBUF_PREDICT_TRUE(!other.is_large())) {
+      GrowCapacity(SizeOfUnion(flat_begin(), flat_end(), other.flat_begin(),
+                               other.flat_end()));
+    } else {
+      GrowCapacity(SizeOfUnion(flat_begin(), flat_end(),
+                               other.map_.large->begin(),
+                               other.map_.large->end()));
+    }
+  }
+  other.ForEach([extendee, this, &other](int number, const Extension& ext) {
+    this->InternalExtensionMergeFrom(extendee, number, ext, other.arena_);
+  });
+}
+
+void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee,
+                                              int number,
+                                              const Extension& other_extension,
+                                              Arena* other_arena) {
+  if (other_extension.is_repeated) {
+    Extension* extension;
+    bool is_new =
+        MaybeNewExtension(number, other_extension.descriptor, &extension);
+    if (is_new) {
+      // Extension did not already exist in set.
+      extension->type = other_extension.type;
+      extension->is_packed = other_extension.is_packed;
+      extension->is_repeated = true;
+    } else {
+      GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+      GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
+      GOOGLE_DCHECK(extension->is_repeated);
+    }
+
+    switch (cpp_type(other_extension.type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \
+  case WireFormatLite::CPPTYPE_##UPPERCASE:              \
+    if (is_new) {                                        \
+      extension->repeated_##LOWERCASE##_value =          \
+          Arena::CreateMessage<REPEATED_TYPE>(arena_);   \
+    }                                                    \
+    extension->repeated_##LOWERCASE##_value->MergeFrom(  \
+        *other_extension.repeated_##LOWERCASE##_value);  \
+    break;
+
+      HANDLE_TYPE(INT32, int32_t, RepeatedField<int32_t>);
+      HANDLE_TYPE(INT64, int64_t, RepeatedField<int64_t>);
+      HANDLE_TYPE(UINT32, uint32_t, RepeatedField<uint32_t>);
+      HANDLE_TYPE(UINT64, uint64_t, RepeatedField<uint64_t>);
+      HANDLE_TYPE(FLOAT, float, RepeatedField<float>);
+      HANDLE_TYPE(DOUBLE, double, RepeatedField<double>);
+      HANDLE_TYPE(BOOL, bool, RepeatedField<bool>);
+      HANDLE_TYPE(ENUM, enum, RepeatedField<int>);
+      HANDLE_TYPE(STRING, string, RepeatedPtrField<std::string>);
+#undef HANDLE_TYPE
+
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        if (is_new) {
+          extension->repeated_message_value =
+              Arena::CreateMessage<RepeatedPtrField<MessageLite>>(arena_);
+        }
+        // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
+        // it would attempt to allocate new objects.
+        RepeatedPtrField<MessageLite>* other_repeated_message =
+            other_extension.repeated_message_value;
+        for (int i = 0; i < other_repeated_message->size(); i++) {
+          const MessageLite& other_message = other_repeated_message->Get(i);
+          MessageLite* target =
+              reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+                  extension->repeated_message_value)
+                  ->AddFromCleared<GenericTypeHandler<MessageLite>>();
+          if (target == nullptr) {
+            target = other_message.New(arena_);
+            extension->repeated_message_value->AddAllocated(target);
+          }
+          target->CheckTypeAndMergeFrom(other_message);
+        }
+        break;
+    }
+  } else {
+    if (!other_extension.is_cleared) {
+      switch (cpp_type(other_extension.type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE)  \
+  case WireFormatLite::CPPTYPE_##UPPERCASE:           \
+    Set##CAMELCASE(number, other_extension.type,      \
+                   other_extension.LOWERCASE##_value, \
+                   other_extension.descriptor);       \
+    break;
+
+        HANDLE_TYPE(INT32, int32_t, Int32);
+        HANDLE_TYPE(INT64, int64_t, Int64);
+        HANDLE_TYPE(UINT32, uint32_t, UInt32);
+        HANDLE_TYPE(UINT64, uint64_t, UInt64);
+        HANDLE_TYPE(FLOAT, float, Float);
+        HANDLE_TYPE(DOUBLE, double, Double);
+        HANDLE_TYPE(BOOL, bool, Bool);
+        HANDLE_TYPE(ENUM, enum, Enum);
+#undef HANDLE_TYPE
+        case WireFormatLite::CPPTYPE_STRING:
+          SetString(number, other_extension.type, *other_extension.string_value,
+                    other_extension.descriptor);
+          break;
+        case WireFormatLite::CPPTYPE_MESSAGE: {
+          Extension* extension;
+          bool is_new =
+              MaybeNewExtension(number, other_extension.descriptor, &extension);
+          if (is_new) {
+            extension->type = other_extension.type;
+            extension->is_packed = other_extension.is_packed;
+            extension->is_repeated = false;
+            if (other_extension.is_lazy) {
+              extension->is_lazy = true;
+              extension->lazymessage_value =
+                  other_extension.lazymessage_value->New(arena_);
+              extension->lazymessage_value->MergeFrom(
+                  GetPrototypeForLazyMessage(extendee, number),
+                  *other_extension.lazymessage_value, arena_);
+            } else {
+              extension->is_lazy = false;
+              extension->message_value =
+                  other_extension.message_value->New(arena_);
+              extension->message_value->CheckTypeAndMergeFrom(
+                  *other_extension.message_value);
+            }
+          } else {
+            GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+            GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
+            GOOGLE_DCHECK(!extension->is_repeated);
+            if (other_extension.is_lazy) {
+              if (extension->is_lazy) {
+                extension->lazymessage_value->MergeFrom(
+                    GetPrototypeForLazyMessage(extendee, number),
+                    *other_extension.lazymessage_value, arena_);
+              } else {
+                extension->message_value->CheckTypeAndMergeFrom(
+                    other_extension.lazymessage_value->GetMessage(
+                        *extension->message_value, other_arena));
+              }
+            } else {
+              if (extension->is_lazy) {
+                extension->lazymessage_value
+                    ->MutableMessage(*other_extension.message_value, arena_)
+                    ->CheckTypeAndMergeFrom(*other_extension.message_value);
+              } else {
+                extension->message_value->CheckTypeAndMergeFrom(
+                    *other_extension.message_value);
+              }
+            }
+          }
+          extension->is_cleared = false;
+          break;
+        }
+      }
+    }
+  }
+}
+
+void ExtensionSet::Swap(const MessageLite* extendee, ExtensionSet* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetArena() != nullptr && GetArena() == other->GetArena()) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (GetArena() == other->GetArena()) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    InternalSwap(other);
+  } else {
+    // TODO(cfallin, rohananil): We maybe able to optimize a case where we are
+    // swapping from heap to arena-allocated extension set, by just Own()'ing
+    // the extensions.
+    ExtensionSet extension_set;
+    extension_set.MergeFrom(extendee, *other);
+    other->Clear();
+    other->MergeFrom(extendee, *this);
+    Clear();
+    MergeFrom(extendee, extension_set);
+  }
+}
+
+void ExtensionSet::InternalSwap(ExtensionSet* other) {
+  using std::swap;
+  swap(arena_, other->arena_);
+  swap(flat_capacity_, other->flat_capacity_);
+  swap(flat_size_, other->flat_size_);
+  swap(map_, other->map_);
+}
+
+void ExtensionSet::SwapExtension(const MessageLite* extendee,
+                                 ExtensionSet* other, int number) {
+  if (this == other) return;
+
+  if (GetArena() == other->GetArena()) {
+    UnsafeShallowSwapExtension(other, number);
+    return;
+  }
+
+  Extension* this_ext = FindOrNull(number);
+  Extension* other_ext = other->FindOrNull(number);
+
+  if (this_ext == other_ext) return;
+
+  if (this_ext != nullptr && other_ext != nullptr) {
+    // TODO(cfallin, rohananil): We could further optimize these cases,
+    // especially avoid creation of ExtensionSet, and move MergeFrom logic
+    // into Extensions itself (which takes arena as an argument).
+    // We do it this way to reuse the copy-across-arenas logic already
+    // implemented in ExtensionSet's MergeFrom.
+    ExtensionSet temp;
+    temp.InternalExtensionMergeFrom(extendee, number, *other_ext,
+                                    other->GetArena());
+    Extension* temp_ext = temp.FindOrNull(number);
+
+    other_ext->Clear();
+    other->InternalExtensionMergeFrom(extendee, number, *this_ext,
+                                      this->GetArena());
+    this_ext->Clear();
+    InternalExtensionMergeFrom(extendee, number, *temp_ext, temp.GetArena());
+  } else if (this_ext == nullptr) {
+    InternalExtensionMergeFrom(extendee, number, *other_ext, other->GetArena());
+    if (other->GetArena() == nullptr) other_ext->Free();
+    other->Erase(number);
+  } else {
+    other->InternalExtensionMergeFrom(extendee, number, *this_ext,
+                                      this->GetArena());
+    if (GetArena() == nullptr) this_ext->Free();
+    Erase(number);
+  }
+}
+
+void ExtensionSet::UnsafeShallowSwapExtension(ExtensionSet* other, int number) {
+  if (this == other) return;
+
+  Extension* this_ext = FindOrNull(number);
+  Extension* other_ext = other->FindOrNull(number);
+
+  if (this_ext == other_ext) return;
+
+  GOOGLE_DCHECK_EQ(GetArena(), other->GetArena());
+
+  if (this_ext != nullptr && other_ext != nullptr) {
+    std::swap(*this_ext, *other_ext);
+  } else if (this_ext == nullptr) {
+    *Insert(number).first = *other_ext;
+    other->Erase(number);
+  } else {
+    *other->Insert(number).first = *this_ext;
+    Erase(number);
+  }
+}
+
+bool ExtensionSet::IsInitialized() const {
+  // Extensions are never required.  However, we need to check that all
+  // embedded messages are initialized.
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    for (const auto& kv : *map_.large) {
+      if (!kv.second.IsInitialized()) return false;
+    }
+    return true;
+  }
+  for (const KeyValue* it = flat_begin(); it != flat_end(); ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
+                                     const MessageLite* extendee,
+                                     internal::InternalMetadata* metadata,
+                                     internal::ParseContext* ctx) {
+  GeneratedExtensionFinder finder(extendee);
+  int number = tag >> 3;
+  bool was_packed_on_wire;
+  ExtensionInfo extension;
+  if (!FindExtensionInfoFromFieldNumber(tag & 7, number, &finder, &extension,
+                                        &was_packed_on_wire)) {
+    return UnknownFieldParse(
+        tag, metadata->mutable_unknown_fields<std::string>(), ptr, ctx);
+  }
+  return ParseFieldWithExtensionInfo<std::string>(
+      number, was_packed_on_wire, extension, metadata, ptr, ctx);
+}
+
+const char* ExtensionSet::ParseMessageSetItem(
+    const char* ptr, const MessageLite* extendee,
+    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+  return ParseMessageSetItemTmpl<MessageLite, std::string>(ptr, extendee,
+                                                           metadata, ctx);
+}
+
+uint8_t* ExtensionSet::_InternalSerializeImpl(
+    const MessageLite* extendee, int start_field_number, int end_field_number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    const auto& end = map_.large->end();
+    for (auto it = map_.large->lower_bound(start_field_number);
+         it != end && it->first < end_field_number; ++it) {
+      target = it->second.InternalSerializeFieldWithCachedSizesToArray(
+          extendee, this, it->first, target, stream);
+    }
+    return target;
+  }
+  const KeyValue* end = flat_end();
+  for (const KeyValue* it = std::lower_bound(
+           flat_begin(), end, start_field_number, KeyValue::FirstComparator());
+       it != end && it->first < end_field_number; ++it) {
+    target = it->second.InternalSerializeFieldWithCachedSizesToArray(
+        extendee, this, it->first, target, stream);
+  }
+  return target;
+}
+
+uint8_t* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
+    const MessageLite* extendee, uint8_t* target,
+    io::EpsCopyOutputStream* stream) const {
+  const ExtensionSet* extension_set = this;
+  ForEach([&target, extendee, stream, extension_set](int number,
+                                                     const Extension& ext) {
+    target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(
+        extendee, extension_set, number, target, stream);
+  });
+  return target;
+}
+
+size_t ExtensionSet::ByteSize() const {
+  size_t total_size = 0;
+  ForEach([&total_size](int number, const Extension& ext) {
+    total_size += ext.ByteSize(number);
+  });
+  return total_size;
+}
+
+// Defined in extension_set_heavy.cc.
+// int ExtensionSet::SpaceUsedExcludingSelf() const
+
+bool ExtensionSet::MaybeNewExtension(int number,
+                                     const FieldDescriptor* descriptor,
+                                     Extension** result) {
+  bool extension_is_new = false;
+  std::tie(*result, extension_is_new) = Insert(number);
+  (*result)->descriptor = descriptor;
+  return extension_is_new;
+}
+
+// ===================================================================
+// Methods of ExtensionSet::Extension
+
+void ExtensionSet::Extension::Clear() {
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
+  case WireFormatLite::CPPTYPE_##UPPERCASE: \
+    repeated_##LOWERCASE##_value->Clear();  \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, enum);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+    }
+  } else {
+    if (!is_cleared) {
+      switch (cpp_type(type)) {
+        case WireFormatLite::CPPTYPE_STRING:
+          string_value->clear();
+          break;
+        case WireFormatLite::CPPTYPE_MESSAGE:
+          if (is_lazy) {
+            lazymessage_value->Clear();
+          } else {
+            message_value->Clear();
+          }
+          break;
+        default:
+          // No need to do anything.  Get*() will return the default value
+          // as long as is_cleared is true and Set*() will overwrite the
+          // previous value.
+          break;
+      }
+
+      is_cleared = true;
+    }
+  }
+}
+
+size_t ExtensionSet::Extension::ByteSize(int number) const {
+  size_t result = 0;
+
+  if (is_repeated) {
+    if (is_packed) {
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      result += WireFormatLite::CAMELCASE##Size(                     \
+          repeated_##LOWERCASE##_value->Get(i));                     \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+
+        // Stuff with fixed size.
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)             \
+  case WireFormatLite::TYPE_##UPPERCASE:                         \
+    result += WireFormatLite::k##CAMELCASE##Size *               \
+              FromIntSize(repeated_##LOWERCASE##_value->size()); \
+    break
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+#undef HANDLE_TYPE
+
+        case WireFormatLite::TYPE_STRING:
+        case WireFormatLite::TYPE_BYTES:
+        case WireFormatLite::TYPE_GROUP:
+        case WireFormatLite::TYPE_MESSAGE:
+          GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+          break;
+      }
+
+      cached_size = ToCachedSize(result);
+      if (result > 0) {
+        result += io::CodedOutputStream::VarintSize32(result);
+        result += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+      }
+    } else {
+      size_t tag_size = WireFormatLite::TagSize(number, real_type(type));
+
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                        \
+  case WireFormatLite::TYPE_##UPPERCASE:                                    \
+    result += tag_size * FromIntSize(repeated_##LOWERCASE##_value->size()); \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) {        \
+      result += WireFormatLite::CAMELCASE##Size(                            \
+          repeated_##LOWERCASE##_value->Get(i));                            \
+    }                                                                       \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(STRING, String, string);
+        HANDLE_TYPE(BYTES, Bytes, string);
+        HANDLE_TYPE(ENUM, Enum, enum);
+        HANDLE_TYPE(GROUP, Group, message);
+        HANDLE_TYPE(MESSAGE, Message, message);
+#undef HANDLE_TYPE
+
+        // Stuff with fixed size.
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)             \
+  case WireFormatLite::TYPE_##UPPERCASE:                         \
+    result += (tag_size + WireFormatLite::k##CAMELCASE##Size) *  \
+              FromIntSize(repeated_##LOWERCASE##_value->size()); \
+    break
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+#undef HANDLE_TYPE
+      }
+    }
+  } else if (!is_cleared) {
+    result += WireFormatLite::TagSize(number, real_type(type));
+    switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)      \
+  case WireFormatLite::TYPE_##UPPERCASE:                  \
+    result += WireFormatLite::CAMELCASE##Size(LOWERCASE); \
+    break
+
+      HANDLE_TYPE(INT32, Int32, int32_t_value);
+      HANDLE_TYPE(INT64, Int64, int64_t_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
+      HANDLE_TYPE(STRING, String, *string_value);
+      HANDLE_TYPE(BYTES, Bytes, *string_value);
+      HANDLE_TYPE(ENUM, Enum, enum_value);
+      HANDLE_TYPE(GROUP, Group, *message_value);
+#undef HANDLE_TYPE
+      case WireFormatLite::TYPE_MESSAGE: {
+        if (is_lazy) {
+          size_t size = lazymessage_value->ByteSizeLong();
+          result += io::CodedOutputStream::VarintSize32(size) + size;
+        } else {
+          result += WireFormatLite::MessageSize(*message_value);
+        }
+        break;
+      }
+
+      // Stuff with fixed size.
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE)         \
+  case WireFormatLite::TYPE_##UPPERCASE:          \
+    result += WireFormatLite::k##CAMELCASE##Size; \
+    break
+        HANDLE_TYPE(FIXED32, Fixed32);
+        HANDLE_TYPE(FIXED64, Fixed64);
+        HANDLE_TYPE(SFIXED32, SFixed32);
+        HANDLE_TYPE(SFIXED64, SFixed64);
+        HANDLE_TYPE(FLOAT, Float);
+        HANDLE_TYPE(DOUBLE, Double);
+        HANDLE_TYPE(BOOL, Bool);
+#undef HANDLE_TYPE
+    }
+  }
+
+  return result;
+}
+
+int ExtensionSet::Extension::GetSize() const {
+  GOOGLE_DCHECK(is_repeated);
+  switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
+  case WireFormatLite::CPPTYPE_##UPPERCASE: \
+    return repeated_##LOWERCASE##_value->size()
+
+    HANDLE_TYPE(INT32, int32_t);
+    HANDLE_TYPE(INT64, int64_t);
+    HANDLE_TYPE(UINT32, uint32_t);
+    HANDLE_TYPE(UINT64, uint64_t);
+    HANDLE_TYPE(FLOAT, float);
+    HANDLE_TYPE(DOUBLE, double);
+    HANDLE_TYPE(BOOL, bool);
+    HANDLE_TYPE(ENUM, enum);
+    HANDLE_TYPE(STRING, string);
+    HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return 0;
+}
+
+// This function deletes all allocated objects. This function should be only
+// called if the Extension was created without an arena.
+void ExtensionSet::Extension::Free() {
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)   \
+  case WireFormatLite::CPPTYPE_##UPPERCASE: \
+    delete repeated_##LOWERCASE##_value;    \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, enum);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+    }
+  } else {
+    switch (cpp_type(type)) {
+      case WireFormatLite::CPPTYPE_STRING:
+        delete string_value;
+        break;
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        if (is_lazy) {
+          delete lazymessage_value;
+        } else {
+          delete message_value;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+// Defined in extension_set_heavy.cc.
+// int ExtensionSet::Extension::SpaceUsedExcludingSelf() const
+
+bool ExtensionSet::Extension::IsInitialized() const {
+  if (cpp_type(type) == WireFormatLite::CPPTYPE_MESSAGE) {
+    if (is_repeated) {
+      for (int i = 0; i < repeated_message_value->size(); i++) {
+        if (!repeated_message_value->Get(i).IsInitialized()) {
+          return false;
+        }
+      }
+    } else {
+      if (!is_cleared) {
+        if (is_lazy) {
+          if (!lazymessage_value->IsInitialized()) return false;
+        } else {
+          if (!message_value->IsInitialized()) return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+// Dummy key method to avoid weak vtable.
+void ExtensionSet::LazyMessageExtension::UnusedKeyMethod() {}
+
+const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
+  if (flat_size_ == 0) {
+    return nullptr;
+  } else if (PROTOBUF_PREDICT_TRUE(!is_large())) {
+    auto it = std::lower_bound(flat_begin(), flat_end() - 1, key,
+                               KeyValue::FirstComparator());
+    return it->first == key ? &it->second : nullptr;
+  } else {
+    return FindOrNullInLargeMap(key);
+  }
+}
+
+const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(
+    int key) const {
+  assert(is_large());
+  LargeMap::const_iterator it = map_.large->find(key);
+  if (it != map_.large->end()) {
+    return &it->second;
+  }
+  return nullptr;
+}
+
+ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) {
+  const auto* const_this = this;
+  return const_cast<ExtensionSet::Extension*>(const_this->FindOrNull(key));
+}
+
+ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(int key) {
+  const auto* const_this = this;
+  return const_cast<ExtensionSet::Extension*>(
+      const_this->FindOrNullInLargeMap(key));
+}
+
+std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(int key) {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    auto maybe = map_.large->insert({key, Extension()});
+    return {&maybe.first->second, maybe.second};
+  }
+  KeyValue* end = flat_end();
+  KeyValue* it =
+      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
+  if (it != end && it->first == key) {
+    return {&it->second, false};
+  }
+  if (flat_size_ < flat_capacity_) {
+    std::copy_backward(it, end, end + 1);
+    ++flat_size_;
+    it->first = key;
+    it->second = Extension();
+    return {&it->second, true};
+  }
+  GrowCapacity(flat_size_ + 1);
+  return Insert(key);
+}
+
+void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    return;  // LargeMap does not have a "reserve" method.
+  }
+  if (flat_capacity_ >= minimum_new_capacity) {
+    return;
+  }
+
+  auto new_flat_capacity = flat_capacity_;
+  do {
+    new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 4;
+  } while (new_flat_capacity < minimum_new_capacity);
+
+  const KeyValue* begin = flat_begin();
+  const KeyValue* end = flat_end();
+  AllocatedData new_map;
+  if (new_flat_capacity > kMaximumFlatCapacity) {
+    new_map.large = Arena::Create<LargeMap>(arena_);
+    LargeMap::iterator hint = new_map.large->begin();
+    for (const KeyValue* it = begin; it != end; ++it) {
+      hint = new_map.large->insert(hint, {it->first, it->second});
+    }
+    flat_size_ = static_cast<uint16_t>(-1);
+    GOOGLE_DCHECK(is_large());
+  } else {
+    new_map.flat = Arena::CreateArray<KeyValue>(arena_, new_flat_capacity);
+    std::copy(begin, end, new_map.flat);
+  }
+
+  if (arena_ == nullptr) {
+    DeleteFlatMap(begin, flat_capacity_);
+  }
+  flat_capacity_ = new_flat_capacity;
+  map_ = new_map;
+}
+
+#if (__cplusplus < 201703) && \
+    (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+// static
+constexpr uint16_t ExtensionSet::kMaximumFlatCapacity;
+#endif  //  (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900
+        //  && _MSC_VER < 1912))
+
+void ExtensionSet::Erase(int key) {
+  if (PROTOBUF_PREDICT_FALSE(is_large())) {
+    map_.large->erase(key);
+    return;
+  }
+  KeyValue* end = flat_end();
+  KeyValue* it =
+      std::lower_bound(flat_begin(), end, key, KeyValue::FirstComparator());
+  if (it != end && it->first == key) {
+    std::copy(it + 1, end, it);
+    --flat_size_;
+  }
+}
+
+// ==================================================================
+// Default repeated field instances for iterator-compatible accessors
+
+const RepeatedPrimitiveDefaults* RepeatedPrimitiveDefaults::default_instance() {
+  static auto instance = OnShutdownDelete(new RepeatedPrimitiveDefaults);
+  return instance;
+}
+
+const RepeatedStringTypeTraits::RepeatedFieldType*
+RepeatedStringTypeTraits::GetDefaultRepeatedField() {
+  static auto instance = OnShutdownDelete(new RepeatedFieldType);
+  return instance;
+}
+
+uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
+    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (is_repeated) {
+    if (is_packed) {
+      if (cached_size == 0) return target;
+
+      target = stream->EnsureSpace(target);
+      target = WireFormatLite::WriteTagToArray(
+          number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
+      target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
+
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      target = stream->EnsureSpace(target);                          \
+      target = WireFormatLite::Write##CAMELCASE##NoTagToArray(       \
+          repeated_##LOWERCASE##_value->Get(i), target);             \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+
+        case WireFormatLite::TYPE_STRING:
+        case WireFormatLite::TYPE_BYTES:
+        case WireFormatLite::TYPE_GROUP:
+        case WireFormatLite::TYPE_MESSAGE:
+          GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+          break;
+      }
+    } else {
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      target = stream->EnsureSpace(target);                          \
+      target = WireFormatLite::Write##CAMELCASE##ToArray(            \
+          number, repeated_##LOWERCASE##_value->Get(i), target);     \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32_t);
+        HANDLE_TYPE(INT64, Int64, int64_t);
+        HANDLE_TYPE(UINT32, UInt32, uint32_t);
+        HANDLE_TYPE(UINT64, UInt64, uint64_t);
+        HANDLE_TYPE(SINT32, SInt32, int32_t);
+        HANDLE_TYPE(SINT64, SInt64, int64_t);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32_t);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64_t);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32_t);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64_t);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      target = stream->EnsureSpace(target);                          \
+      target = stream->WriteString(                                  \
+          number, repeated_##LOWERCASE##_value->Get(i), target);     \
+    }                                                                \
+    break
+        HANDLE_TYPE(STRING, String, string);
+        HANDLE_TYPE(BYTES, Bytes, string);
+#undef HANDLE_TYPE
+        case WireFormatLite::TYPE_GROUP:
+          for (int i = 0; i < repeated_message_value->size(); i++) {
+            target = stream->EnsureSpace(target);
+            target = WireFormatLite::InternalWriteGroup(
+                number, repeated_message_value->Get(i), target, stream);
+          }
+          break;
+        case WireFormatLite::TYPE_MESSAGE:
+          for (int i = 0; i < repeated_message_value->size(); i++) {
+            auto& msg = repeated_message_value->Get(i);
+            target = WireFormatLite::InternalWriteMessage(
+                number, msg, msg.GetCachedSize(), target, stream);
+          }
+          break;
+      }
+    }
+  } else if (!is_cleared) {
+    switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)                               \
+  case WireFormatLite::TYPE_##UPPERCASE:                                       \
+    target = stream->EnsureSpace(target);                                      \
+    target = WireFormatLite::Write##CAMELCASE##ToArray(number, VALUE, target); \
+    break
+
+      HANDLE_TYPE(INT32, Int32, int32_t_value);
+      HANDLE_TYPE(INT64, Int64, int64_t_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_t_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_t_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_t_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_t_value);
+      HANDLE_TYPE(FIXED32, Fixed32, uint32_t_value);
+      HANDLE_TYPE(FIXED64, Fixed64, uint64_t_value);
+      HANDLE_TYPE(SFIXED32, SFixed32, int32_t_value);
+      HANDLE_TYPE(SFIXED64, SFixed64, int64_t_value);
+      HANDLE_TYPE(FLOAT, Float, float_value);
+      HANDLE_TYPE(DOUBLE, Double, double_value);
+      HANDLE_TYPE(BOOL, Bool, bool_value);
+      HANDLE_TYPE(ENUM, Enum, enum_value);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)         \
+  case WireFormatLite::TYPE_##UPPERCASE:                 \
+    target = stream->EnsureSpace(target);                \
+    target = stream->WriteString(number, VALUE, target); \
+    break
+      HANDLE_TYPE(STRING, String, *string_value);
+      HANDLE_TYPE(BYTES, Bytes, *string_value);
+#undef HANDLE_TYPE
+      case WireFormatLite::TYPE_GROUP:
+        target = stream->EnsureSpace(target);
+        target = WireFormatLite::InternalWriteGroup(number, *message_value,
+                                                    target, stream);
+        break;
+      case WireFormatLite::TYPE_MESSAGE:
+        if (is_lazy) {
+          const auto* prototype =
+              extension_set->GetPrototypeForLazyMessage(extendee, number);
+          target = lazymessage_value->WriteMessageToArray(prototype, number,
+                                                          target, stream);
+        } else {
+          target = WireFormatLite::InternalWriteMessage(
+              number, *message_value, message_value->GetCachedSize(), target,
+              stream);
+        }
+        break;
+    }
+  }
+  return target;
+}
+
+const MessageLite* ExtensionSet::GetPrototypeForLazyMessage(
+    const MessageLite* extendee, int number) const {
+  GeneratedExtensionFinder finder(extendee);
+  bool was_packed_on_wire = false;
+  ExtensionInfo extension_info;
+  if (!FindExtensionInfoFromFieldNumber(
+          WireFormatLite::WireType::WIRETYPE_LENGTH_DELIMITED, number, &finder,
+          &extension_info, &was_packed_on_wire)) {
+    return nullptr;
+  }
+  return extension_info.message_info.prototype;
+}
+
+uint8_t*
+ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
+    const MessageLite* extendee, const ExtensionSet* extension_set, int number,
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+    // Not a valid MessageSet extension, but serialize it the normal way.
+    GOOGLE_LOG(WARNING) << "Invalid message set extension.";
+    return InternalSerializeFieldWithCachedSizesToArray(extendee, extension_set,
+                                                        number, target, stream);
+  }
+
+  if (is_cleared) return target;
+
+  target = stream->EnsureSpace(target);
+  // Start group.
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemStartTag, target);
+  // Write type ID.
+  target = WireFormatLite::WriteUInt32ToArray(
+      WireFormatLite::kMessageSetTypeIdNumber, number, target);
+  // Write message.
+  if (is_lazy) {
+    const auto* prototype =
+        extension_set->GetPrototypeForLazyMessage(extendee, number);
+    target = lazymessage_value->WriteMessageToArray(
+        prototype, WireFormatLite::kMessageSetMessageNumber, target, stream);
+  } else {
+    target = WireFormatLite::InternalWriteMessage(
+        WireFormatLite::kMessageSetMessageNumber, *message_value,
+        message_value->GetCachedSize(), target, stream);
+  }
+  // End group.
+  target = stream->EnsureSpace(target);
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemEndTag, target);
+  return target;
+}
+
+size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
+  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
+    // Not a valid MessageSet extension, but compute the byte size for it the
+    // normal way.
+    return ByteSize(number);
+  }
+
+  if (is_cleared) return 0;
+
+  size_t our_size = WireFormatLite::kMessageSetItemTagsSize;
+
+  // type_id
+  our_size += io::CodedOutputStream::VarintSize32(number);
+
+  // message
+  size_t message_size = 0;
+  if (is_lazy) {
+    message_size = lazymessage_value->ByteSizeLong();
+  } else {
+    message_size = message_value->ByteSizeLong();
+  }
+
+  our_size += io::CodedOutputStream::VarintSize32(message_size);
+  our_size += message_size;
+
+  return our_size;
+}
+
+size_t ExtensionSet::MessageSetByteSize() const {
+  size_t total_size = 0;
+  ForEach([&total_size](int number, const Extension& ext) {
+    total_size += ext.MessageSetItemByteSize(number);
+  });
+  return total_size;
+}
+
+LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
+    const MessageLite* extendee, int number) {
+  const ExtensionInfo* registered = FindRegisteredExtension(extendee, number);
+  if (registered != nullptr) {
+    return registered->lazy_eager_verify_func;
+  }
+  return nullptr;
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/extension_set_heavy.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/extension_set_heavy.cpp
new file mode 100644
index 0000000..a4bb948
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/extension_set_heavy.cpp
@@ -0,0 +1,440 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Contains methods defined in extension_set.h which cannot be part of the
+// lite library because they use descriptors or reflection.
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Implementation of ExtensionFinder which finds extensions in a given
+// DescriptorPool, using the given MessageFactory to construct sub-objects.
+// This class is implemented in extension_set_heavy.cc.
+class DescriptorPoolExtensionFinder {
+ public:
+  DescriptorPoolExtensionFinder(const DescriptorPool* pool,
+                                MessageFactory* factory,
+                                const Descriptor* containing_type)
+      : pool_(pool), factory_(factory), containing_type_(containing_type) {}
+
+  bool Find(int number, ExtensionInfo* output);
+
+ private:
+  const DescriptorPool* pool_;
+  MessageFactory* factory_;
+  const Descriptor* containing_type_;
+};
+
+void ExtensionSet::AppendToList(
+    const Descriptor* containing_type, const DescriptorPool* pool,
+    std::vector<const FieldDescriptor*>* output) const {
+  ForEach([containing_type, pool, &output](int number, const Extension& ext) {
+    bool has = false;
+    if (ext.is_repeated) {
+      has = ext.GetSize() > 0;
+    } else {
+      has = !ext.is_cleared;
+    }
+
+    if (has) {
+      // TODO(kenton): Looking up each field by number is somewhat unfortunate.
+      //   Is there a better way?  The problem is that descriptors are lazily-
+      //   initialized, so they might not even be constructed until
+      //   AppendToList() is called.
+
+      if (ext.descriptor == nullptr) {
+        output->push_back(pool->FindExtensionByNumber(containing_type, number));
+      } else {
+        output->push_back(ext.descriptor);
+      }
+    }
+  });
+}
+
+inline FieldDescriptor::Type real_type(FieldType type) {
+  GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE);
+  return static_cast<FieldDescriptor::Type>(type);
+}
+
+inline FieldDescriptor::CppType cpp_type(FieldType type) {
+  return FieldDescriptor::TypeToCppType(
+      static_cast<FieldDescriptor::Type>(type));
+}
+
+inline WireFormatLite::FieldType field_type(FieldType type) {
+  GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
+  return static_cast<WireFormatLite::FieldType>(type);
+}
+
+#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                         \
+  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED  \
+                                    : FieldDescriptor::LABEL_OPTIONAL, \
+            FieldDescriptor::LABEL_##LABEL);                           \
+  GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+const MessageLite& ExtensionSet::GetMessage(int number,
+                                            const Descriptor* message_type,
+                                            MessageFactory* factory) const {
+  const Extension* extension = FindOrNull(number);
+  if (extension == nullptr || extension->is_cleared) {
+    // Not present.  Return the default value.
+    return *factory->GetPrototype(message_type);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->GetMessage(
+          *factory->GetPrototype(message_type), arena_);
+    } else {
+      return *extension->message_value;
+    }
+  }
+}
+
+MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
+                                          MessageFactory* factory) {
+  Extension* extension;
+  if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
+    extension->type = descriptor->type();
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_packed = false;
+    const MessageLite* prototype =
+        factory->GetPrototype(descriptor->message_type());
+    extension->is_lazy = false;
+    extension->message_value = prototype->New(arena_);
+    extension->is_cleared = false;
+    return extension->message_value;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    extension->is_cleared = false;
+    if (extension->is_lazy) {
+      return extension->lazymessage_value->MutableMessage(
+          *factory->GetPrototype(descriptor->message_type()), arena_);
+    } else {
+      return extension->message_value;
+    }
+  }
+}
+
+MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
+                                          MessageFactory* factory) {
+  Extension* extension = FindOrNull(descriptor->number());
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->ReleaseMessage(
+          *factory->GetPrototype(descriptor->message_type()), arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      if (arena_ != nullptr) {
+        ret = extension->message_value->New();
+        ret->CheckTypeAndMergeFrom(*extension->message_value);
+      } else {
+        ret = extension->message_value;
+      }
+    }
+    Erase(descriptor->number());
+    return ret;
+  }
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+    const FieldDescriptor* descriptor, MessageFactory* factory) {
+  Extension* extension = FindOrNull(descriptor->number());
+  if (extension == nullptr) {
+    // Not present.  Return nullptr.
+    return nullptr;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    MessageLite* ret = nullptr;
+    if (extension->is_lazy) {
+      ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(
+          *factory->GetPrototype(descriptor->message_type()), arena_);
+      if (arena_ == nullptr) {
+        delete extension->lazymessage_value;
+      }
+    } else {
+      ret = extension->message_value;
+    }
+    Erase(descriptor->number());
+    return ret;
+  }
+}
+
+ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(
+    const FieldDescriptor* descriptor) {
+  Extension* extension;
+  if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
+    extension->type = descriptor->type();
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
+    extension->is_repeated = true;
+    extension->repeated_message_value =
+        Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
+  }
+  return extension;
+}
+
+MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
+                                      MessageFactory* factory) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  // RepeatedPtrField<Message> does not know how to Add() since it cannot
+  // allocate an abstract object, so we have to be tricky.
+  MessageLite* result =
+      reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+          extension->repeated_message_value)
+          ->AddFromCleared<GenericTypeHandler<MessageLite> >();
+  if (result == nullptr) {
+    const MessageLite* prototype;
+    if (extension->repeated_message_value->empty()) {
+      prototype = factory->GetPrototype(descriptor->message_type());
+      GOOGLE_CHECK(prototype != nullptr);
+    } else {
+      prototype = &extension->repeated_message_value->Get(0);
+    }
+    result = prototype->New(arena_);
+    extension->repeated_message_value->AddAllocated(result);
+  }
+  return result;
+}
+
+void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor,
+                                       MessageLite* new_entry) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  extension->repeated_message_value->AddAllocated(new_entry);
+}
+
+void ExtensionSet::UnsafeArenaAddAllocatedMessage(
+    const FieldDescriptor* descriptor, MessageLite* new_entry) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  extension->repeated_message_value->UnsafeArenaAddAllocated(new_entry);
+}
+
+static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
+  return reinterpret_cast<const EnumDescriptor*>(arg)->FindValueByNumber(
+             number) != nullptr;
+}
+
+bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
+  const FieldDescriptor* extension =
+      pool_->FindExtensionByNumber(containing_type_, number);
+  if (extension == nullptr) {
+    return false;
+  } else {
+    output->type = extension->type();
+    output->is_repeated = extension->is_repeated();
+    output->is_packed = extension->options().packed();
+    output->descriptor = extension;
+    if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      output->message_info.prototype =
+          factory_->GetPrototype(extension->message_type());
+      GOOGLE_CHECK(output->message_info.prototype != nullptr)
+          << "Extension factory's GetPrototype() returned nullptr; extension: "
+          << extension->full_name();
+    } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      output->enum_validity_check.func = ValidateEnumUsingDescriptor;
+      output->enum_validity_check.arg = extension->enum_type();
+    }
+
+    return true;
+  }
+}
+
+
+bool ExtensionSet::FindExtension(int wire_type, uint32_t field,
+                                 const Message* containing_type,
+                                 const internal::ParseContext* ctx,
+                                 ExtensionInfo* extension,
+                                 bool* was_packed_on_wire) {
+  if (ctx->data().pool == nullptr) {
+    GeneratedExtensionFinder finder(containing_type);
+    if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
+                                          was_packed_on_wire)) {
+      return false;
+    }
+  } else {
+    DescriptorPoolExtensionFinder finder(ctx->data().pool, ctx->data().factory,
+                                         containing_type->GetDescriptor());
+    if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
+                                          was_packed_on_wire)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
+                                     const Message* containing_type,
+                                     internal::InternalMetadata* metadata,
+                                     internal::ParseContext* ctx) {
+  int number = tag >> 3;
+  bool was_packed_on_wire;
+  ExtensionInfo extension;
+  if (!FindExtension(tag & 7, number, containing_type, ctx, &extension,
+                     &was_packed_on_wire)) {
+    return UnknownFieldParse(
+        tag, metadata->mutable_unknown_fields<UnknownFieldSet>(), ptr, ctx);
+  }
+  return ParseFieldWithExtensionInfo<UnknownFieldSet>(
+      number, was_packed_on_wire, extension, metadata, ptr, ctx);
+}
+
+const char* ExtensionSet::ParseFieldMaybeLazily(
+    uint64_t tag, const char* ptr, const Message* containing_type,
+    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+  return ParseField(tag, ptr, containing_type, metadata, ctx);
+}
+
+const char* ExtensionSet::ParseMessageSetItem(
+    const char* ptr, const Message* containing_type,
+    internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
+  return ParseMessageSetItemTmpl<Message, UnknownFieldSet>(ptr, containing_type,
+                                                           metadata, ctx);
+}
+
+int ExtensionSet::SpaceUsedExcludingSelf() const {
+  return internal::FromIntSize(SpaceUsedExcludingSelfLong());
+}
+
+size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
+  size_t total_size =
+      (is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue);
+  ForEach([&total_size](int /* number */, const Extension& ext) {
+    total_size += ext.SpaceUsedExcludingSelfLong();
+  });
+  return total_size;
+}
+
+inline size_t ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelfLong(
+    RepeatedPtrFieldBase* field) {
+  return field->SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >();
+}
+
+size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
+  size_t total_size = 0;
+  if (is_repeated) {
+    switch (cpp_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                     \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                                  \
+    total_size += sizeof(*repeated_##LOWERCASE##_value) +                     \
+                  repeated_##LOWERCASE##_value->SpaceUsedExcludingSelfLong(); \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, enum);
+      HANDLE_TYPE(STRING, string);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        // repeated_message_value is actually a RepeatedPtrField<MessageLite>,
+        // but MessageLite has no SpaceUsedLong(), so we must directly call
+        // RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() with a different
+        // type handler.
+        total_size += sizeof(*repeated_message_value) +
+                      RepeatedMessage_SpaceUsedExcludingSelfLong(
+                          reinterpret_cast<internal::RepeatedPtrFieldBase*>(
+                              repeated_message_value));
+        break;
+    }
+  } else {
+    switch (cpp_type(type)) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        total_size += sizeof(*string_value) +
+                      StringSpaceUsedExcludingSelfLong(*string_value);
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (is_lazy) {
+          total_size += lazymessage_value->SpaceUsedLong();
+        } else {
+          total_size += down_cast<Message*>(message_value)->SpaceUsedLong();
+        }
+        break;
+      default:
+        // No extra storage costs for primitive types.
+        break;
+    }
+  }
+  return total_size;
+}
+
+uint8_t* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
+    const MessageLite* extendee, uint8_t* target) const {
+  io::EpsCopyOutputStream stream(
+      target, MessageSetByteSize(),
+      io::CodedOutputStream::IsDefaultSerializationDeterministic());
+  return InternalSerializeMessageSetWithCachedSizesToArray(extendee, target,
+                                                           &stream);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/field_mask.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/field_mask.pb.cpp
new file mode 100644
index 0000000..7860bfb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/field_mask.pb.cpp
@@ -0,0 +1,284 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#include <google/protobuf/field_mask.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR FieldMask::FieldMask(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.paths_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FieldMaskDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldMaskDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldMaskDefaultTypeInternal() {}
+  union {
+    FieldMask _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldMask, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldMask, _impl_.paths_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldMask)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_FieldMask_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n google/protobuf/field_mask.proto\022\017goog"
+  "le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB"
+  "\205\001\n\023com.google.protobufB\016FieldMaskProtoP"
+  "\001Z2google.golang.org/protobuf/types/know"
+  "n/fieldmaskpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
+  ".WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+    false, false, 223, descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto,
+    "google/protobuf/field_mask.proto",
+    &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ffield_5fmask_2eproto(&descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class FieldMask::_Internal {
+ public:
+};
+
+FieldMask::FieldMask(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldMask)
+}
+FieldMask::FieldMask(const FieldMask& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FieldMask* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.paths_){from._impl_.paths_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldMask)
+}
+
+inline void FieldMask::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.paths_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+FieldMask::~FieldMask() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldMask)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FieldMask::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.paths_.~RepeatedPtrField();
+}
+
+void FieldMask::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FieldMask::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.paths_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FieldMask::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated string paths = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_paths();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.FieldMask.paths"));
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FieldMask::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated string paths = 1;
+  for (int i = 0, n = this->_internal_paths_size(); i < n; i++) {
+    const auto& s = this->_internal_paths(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.FieldMask.paths");
+    target = stream->WriteString(1, s, target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldMask)
+  return target;
+}
+
+size_t FieldMask::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated string paths = 1;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.paths_.size());
+  for (int i = 0, n = _impl_.paths_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.paths_.Get(i));
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FieldMask::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FieldMask::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldMask::GetClassData() const { return &_class_data_; }
+
+
+void FieldMask::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FieldMask*>(&to_msg);
+  auto& from = static_cast<const FieldMask&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.paths_.MergeFrom(from._impl_.paths_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FieldMask::CopyFrom(const FieldMask& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldMask)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldMask::IsInitialized() const {
+  return true;
+}
+
+void FieldMask::InternalSwap(FieldMask* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.paths_.InternalSwap(&other->_impl_.paths_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FieldMask::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter, &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldMask*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldMask >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldMask >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/generated_enum_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_enum_util.cpp
new file mode 100644
index 0000000..df7583e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_enum_util.cpp
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/generated_enum_util.h>
+
+#include <algorithm>
+
+#include <google/protobuf/generated_message_util.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+
+bool EnumCompareByName(const EnumEntry& a, const EnumEntry& b) {
+  return StringPiece(a.name) < StringPiece(b.name);
+}
+
+// Gets the numeric value of the EnumEntry at the given index, but returns a
+// special value for the index -1. This gives a way to use std::lower_bound on a
+// sorted array of indices while searching for value that we associate with -1.
+int GetValue(const EnumEntry* enums, int i, int target) {
+  if (i == -1) {
+    return target;
+  } else {
+    return enums[i].value;
+  }
+}
+
+}  // namespace
+
+bool LookUpEnumValue(const EnumEntry* enums, size_t size,
+                     StringPiece name, int* value) {
+  EnumEntry target{name, 0};
+  auto it = std::lower_bound(enums, enums + size, target, EnumCompareByName);
+  if (it != enums + size && it->name == name) {
+    *value = it->value;
+    return true;
+  }
+  return false;
+}
+
+int LookUpEnumName(const EnumEntry* enums, const int* sorted_indices,
+                   size_t size, int value) {
+  auto comparator = [enums, value](int a, int b) {
+    return GetValue(enums, a, value) < GetValue(enums, b, value);
+  };
+  auto it =
+      std::lower_bound(sorted_indices, sorted_indices + size, -1, comparator);
+  if (it != sorted_indices + size && enums[*it].value == value) {
+    return it - sorted_indices;
+  }
+  return -1;
+}
+
+bool InitializeEnumStrings(
+    const EnumEntry* enums, const int* sorted_indices, size_t size,
+    internal::ExplicitlyConstructed<std::string>* enum_strings) {
+  for (size_t i = 0; i < size; ++i) {
+    enum_strings[i].Construct(enums[sorted_indices[i]].name);
+    internal::OnShutdownDestroyString(enum_strings[i].get_mutable());
+  }
+  return true;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_bases.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_bases.cpp
new file mode 100644
index 0000000..306a38e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_bases.cpp
@@ -0,0 +1,124 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/generated_message_bases.h>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be last:
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// =============================================================================
+// ZeroFieldsBase
+
+void ZeroFieldsBase::Clear() {
+  _internal_metadata_.Clear<UnknownFieldSet>();  //
+}
+
+ZeroFieldsBase::~ZeroFieldsBase() {
+  (void)_internal_metadata_.DeleteReturnArena<UnknownFieldSet>();
+}
+
+size_t ZeroFieldsBase::ByteSizeLong() const {
+  return MaybeComputeUnknownFieldsSize(0, &_cached_size_);
+}
+
+const char* ZeroFieldsBase::_InternalParse(const char* ptr,
+                                           internal::ParseContext* ctx) {
+#define CHK_(x)                       \
+  if (PROTOBUF_PREDICT_FALSE(!(x))) { \
+    goto failure;                     \
+  }
+
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = internal::ReadTag(ptr, &tag);
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag, _internal_metadata_.mutable_unknown_fields<UnknownFieldSet>(), ptr,
+        ctx);
+    CHK_(ptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+::uint8_t* ZeroFieldsBase::_InternalSerialize(
+    ::uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<UnknownFieldSet>(
+            UnknownFieldSet::default_instance),
+        target, stream);
+  }
+  return target;
+}
+
+void ZeroFieldsBase::MergeImpl(Message& to_param, const Message& from_param) {
+  auto* to = static_cast<ZeroFieldsBase*>(&to_param);
+  const auto* from = static_cast<const ZeroFieldsBase*>(&from_param);
+  GOOGLE_DCHECK_NE(from, to);
+  to->_internal_metadata_.MergeFrom<UnknownFieldSet>(from->_internal_metadata_);
+}
+
+void ZeroFieldsBase::CopyImpl(Message& to_param, const Message& from_param) {
+  auto* to = static_cast<ZeroFieldsBase*>(&to_param);
+  const auto* from = static_cast<const ZeroFieldsBase*>(&from_param);
+  if (from == to) return;
+  to->_internal_metadata_.Clear<UnknownFieldSet>();
+  to->_internal_metadata_.MergeFrom<UnknownFieldSet>(from->_internal_metadata_);
+}
+
+void ZeroFieldsBase::InternalSwap(ZeroFieldsBase* other) {
+  _internal_metadata_.Swap<UnknownFieldSet>(&other->_internal_metadata_);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_reflection.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_reflection.cpp
new file mode 100644
index 0000000..aaed219
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_reflection.cpp
@@ -0,0 +1,3174 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/generated_message_reflection.h>
+
+#include <algorithm>
+#include <set>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/inlined_string_field.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+#define GOOGLE_PROTOBUF_HAS_ONEOF
+
+using google::protobuf::internal::ArenaStringPtr;
+using google::protobuf::internal::DescriptorTable;
+using google::protobuf::internal::ExtensionSet;
+using google::protobuf::internal::GenericTypeHandler;
+using google::protobuf::internal::GetEmptyString;
+using google::protobuf::internal::InlinedStringField;
+using google::protobuf::internal::InternalMetadata;
+using google::protobuf::internal::LazyField;
+using google::protobuf::internal::MapFieldBase;
+using google::protobuf::internal::MigrationSchema;
+using google::protobuf::internal::OnShutdownDelete;
+using google::protobuf::internal::ReflectionSchema;
+using google::protobuf::internal::RepeatedPtrFieldBase;
+using google::protobuf::internal::StringSpaceUsedExcludingSelfLong;
+using google::protobuf::internal::WrappedMutex;
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4065)
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
+namespace google {
+namespace protobuf {
+
+namespace {
+bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); }
+
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+Message* MaybeForceCopy(Arena* arena, Message* msg) {
+  if (arena != nullptr || msg == nullptr) return msg;
+
+  Message* copy = msg->New();
+  copy->MergeFrom(*msg);
+  delete msg;
+  return copy;
+}
+#endif  // PROTOBUF_FORCE_COPY_IN_RELEASE
+}  // anonymous namespace
+
+namespace internal {
+
+bool ParseNamedEnum(const EnumDescriptor* descriptor, ConstStringParam name,
+                    int* value) {
+  const EnumValueDescriptor* d = descriptor->FindValueByName(name);
+  if (d == nullptr) return false;
+  *value = d->number();
+  return true;
+}
+
+const std::string& NameOfEnum(const EnumDescriptor* descriptor, int value) {
+  const EnumValueDescriptor* d = descriptor->FindValueByNumber(value);
+  return (d == nullptr ? GetEmptyString() : d->name());
+}
+
+}  // namespace internal
+
+// ===================================================================
+// Helpers for reporting usage errors (e.g. trying to use GetInt32() on
+// a string field).
+
+namespace {
+
+using internal::GetConstPointerAtOffset;
+using internal::GetConstRefAtOffset;
+using internal::GetPointerAtOffset;
+
+void ReportReflectionUsageError(const Descriptor* descriptor,
+                                const FieldDescriptor* field,
+                                const char* method, const char* description) {
+  GOOGLE_LOG(FATAL) << "Protocol Buffer reflection usage error:\n"
+                "  Method      : google::protobuf::Reflection::"
+             << method
+             << "\n"
+                "  Message type: "
+             << descriptor->full_name()
+             << "\n"
+                "  Field       : "
+             << field->full_name()
+             << "\n"
+                "  Problem     : "
+             << description;
+}
+
+const char* cpptype_names_[FieldDescriptor::MAX_CPPTYPE + 1] = {
+    "INVALID_CPPTYPE", "CPPTYPE_INT32",  "CPPTYPE_INT64",  "CPPTYPE_UINT32",
+    "CPPTYPE_UINT64",  "CPPTYPE_DOUBLE", "CPPTYPE_FLOAT",  "CPPTYPE_BOOL",
+    "CPPTYPE_ENUM",    "CPPTYPE_STRING", "CPPTYPE_MESSAGE"};
+
+static void ReportReflectionUsageTypeError(
+    const Descriptor* descriptor, const FieldDescriptor* field,
+    const char* method, FieldDescriptor::CppType expected_type) {
+  GOOGLE_LOG(FATAL)
+      << "Protocol Buffer reflection usage error:\n"
+         "  Method      : google::protobuf::Reflection::"
+      << method
+      << "\n"
+         "  Message type: "
+      << descriptor->full_name()
+      << "\n"
+         "  Field       : "
+      << field->full_name()
+      << "\n"
+         "  Problem     : Field is not the right type for this message:\n"
+         "    Expected  : "
+      << cpptype_names_[expected_type]
+      << "\n"
+         "    Field type: "
+      << cpptype_names_[field->cpp_type()];
+}
+
+static void ReportReflectionUsageEnumTypeError(
+    const Descriptor* descriptor, const FieldDescriptor* field,
+    const char* method, const EnumValueDescriptor* value) {
+  GOOGLE_LOG(FATAL) << "Protocol Buffer reflection usage error:\n"
+                "  Method      : google::protobuf::Reflection::"
+             << method
+             << "\n"
+                "  Message type: "
+             << descriptor->full_name()
+             << "\n"
+                "  Field       : "
+             << field->full_name()
+             << "\n"
+                "  Problem     : Enum value did not match field type:\n"
+                "    Expected  : "
+             << field->enum_type()->full_name()
+             << "\n"
+                "    Actual    : "
+             << value->full_name();
+}
+
+inline void CheckInvalidAccess(const internal::ReflectionSchema& schema,
+                               const FieldDescriptor* field) {
+  GOOGLE_CHECK(!schema.IsFieldStripped(field))
+      << "invalid access to a stripped field " << field->full_name();
+}
+
+#define USAGE_CHECK(CONDITION, METHOD, ERROR_DESCRIPTION) \
+  if (!(CONDITION))                                       \
+  ReportReflectionUsageError(descriptor_, field, #METHOD, ERROR_DESCRIPTION)
+#define USAGE_CHECK_EQ(A, B, METHOD, ERROR_DESCRIPTION) \
+  USAGE_CHECK((A) == (B), METHOD, ERROR_DESCRIPTION)
+#define USAGE_CHECK_NE(A, B, METHOD, ERROR_DESCRIPTION) \
+  USAGE_CHECK((A) != (B), METHOD, ERROR_DESCRIPTION)
+
+#define USAGE_CHECK_TYPE(METHOD, CPPTYPE)                      \
+  if (field->cpp_type() != FieldDescriptor::CPPTYPE_##CPPTYPE) \
+  ReportReflectionUsageTypeError(descriptor_, field, #METHOD,  \
+                                 FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+#define USAGE_CHECK_ENUM_VALUE(METHOD)     \
+  if (value->type() != field->enum_type()) \
+  ReportReflectionUsageEnumTypeError(descriptor_, field, #METHOD, value)
+
+#define USAGE_CHECK_MESSAGE_TYPE(METHOD)                        \
+  USAGE_CHECK_EQ(field->containing_type(), descriptor_, METHOD, \
+                 "Field does not match message type.");
+#define USAGE_CHECK_SINGULAR(METHOD)                                      \
+  USAGE_CHECK_NE(field->label(), FieldDescriptor::LABEL_REPEATED, METHOD, \
+                 "Field is repeated; the method requires a singular field.")
+#define USAGE_CHECK_REPEATED(METHOD)                                      \
+  USAGE_CHECK_EQ(field->label(), FieldDescriptor::LABEL_REPEATED, METHOD, \
+                 "Field is singular; the method requires a repeated field.")
+
+#define USAGE_CHECK_ALL(METHOD, LABEL, CPPTYPE) \
+  USAGE_CHECK_MESSAGE_TYPE(METHOD);             \
+  USAGE_CHECK_##LABEL(METHOD);                  \
+  USAGE_CHECK_TYPE(METHOD, CPPTYPE)
+
+}  // namespace
+
+// ===================================================================
+
+Reflection::Reflection(const Descriptor* descriptor,
+                       const internal::ReflectionSchema& schema,
+                       const DescriptorPool* pool, MessageFactory* factory)
+    : descriptor_(descriptor),
+      schema_(schema),
+      descriptor_pool_(
+          (pool == nullptr) ? DescriptorPool::internal_generated_pool() : pool),
+      message_factory_(factory),
+      last_non_weak_field_index_(-1) {
+  last_non_weak_field_index_ = descriptor_->field_count() - 1;
+}
+
+const UnknownFieldSet& Reflection::GetUnknownFields(
+    const Message& message) const {
+  return GetInternalMetadata(message).unknown_fields<UnknownFieldSet>(
+      UnknownFieldSet::default_instance);
+}
+
+UnknownFieldSet* Reflection::MutableUnknownFields(Message* message) const {
+  return MutableInternalMetadata(message)
+      ->mutable_unknown_fields<UnknownFieldSet>();
+}
+
+bool Reflection::IsLazyExtension(const Message& message,
+                                 const FieldDescriptor* field) const {
+  return field->is_extension() &&
+         GetExtensionSet(message).HasLazy(field->number());
+}
+
+bool Reflection::IsLazilyVerifiedLazyField(const FieldDescriptor* field) const {
+  if (field->options().unverified_lazy()) return true;
+
+  // Message fields with [lazy=true] will be eagerly verified
+  // (go/verified-lazy).
+  return field->options().lazy() && !IsEagerlyVerifiedLazyField(field);
+}
+
+bool Reflection::IsEagerlyVerifiedLazyField(
+    const FieldDescriptor* field) const {
+  return (field->type() == FieldDescriptor::TYPE_MESSAGE &&
+          schema_.IsEagerlyVerifiedLazyField(field));
+}
+
+bool Reflection::IsInlined(const FieldDescriptor* field) const {
+  return schema_.IsFieldInlined(field);
+}
+
+size_t Reflection::SpaceUsedLong(const Message& message) const {
+  // object_size_ already includes the in-memory representation of each field
+  // in the message, so we only need to account for additional memory used by
+  // the fields.
+  size_t total_size = schema_.GetObjectSize();
+
+  total_size += GetUnknownFields(message).SpaceUsedExcludingSelfLong();
+
+  // If this message owns an arena, add any unused space that's been allocated.
+  auto* arena = Arena::InternalGetArenaForAllocation(&message);
+  if (arena != nullptr && Arena::InternalGetOwningArena(&message) == nullptr &&
+      arena->InternalIsMessageOwnedArena()) {
+    total_size += arena->SpaceAllocated() - arena->SpaceUsed();
+  }
+
+  if (schema_.HasExtensionSet()) {
+    total_size += GetExtensionSet(message).SpaceUsedExcludingSelfLong();
+  }
+  for (int i = 0; i <= last_non_weak_field_index_; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->is_repeated()) {
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                           \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                        \
+    total_size += GetRaw<RepeatedField<LOWERCASE> >(message, field) \
+                      .SpaceUsedExcludingSelfLong();                \
+    break
+
+        HANDLE_TYPE(INT32, int32_t);
+        HANDLE_TYPE(INT64, int64_t);
+        HANDLE_TYPE(UINT32, uint32_t);
+        HANDLE_TYPE(UINT64, uint64_t);
+        HANDLE_TYPE(DOUBLE, double);
+        HANDLE_TYPE(FLOAT, float);
+        HANDLE_TYPE(BOOL, bool);
+        HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_STRING:
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              total_size +=
+                  GetRaw<RepeatedPtrField<std::string> >(message, field)
+                      .SpaceUsedExcludingSelfLong();
+              break;
+          }
+          break;
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (IsMapFieldInApi(field)) {
+            total_size += GetRaw<internal::MapFieldBase>(message, field)
+                              .SpaceUsedExcludingSelfLong();
+          } else {
+            // We don't know which subclass of RepeatedPtrFieldBase the type is,
+            // so we use RepeatedPtrFieldBase directly.
+            total_size +=
+                GetRaw<RepeatedPtrFieldBase>(message, field)
+                    .SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >();
+          }
+
+          break;
+      }
+    } else {
+      if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+        continue;
+      }
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+        case FieldDescriptor::CPPTYPE_INT64:
+        case FieldDescriptor::CPPTYPE_UINT32:
+        case FieldDescriptor::CPPTYPE_UINT64:
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+        case FieldDescriptor::CPPTYPE_FLOAT:
+        case FieldDescriptor::CPPTYPE_BOOL:
+        case FieldDescriptor::CPPTYPE_ENUM:
+          // Field is inline, so we've already counted it.
+          break;
+
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              if (IsInlined(field)) {
+                const std::string* ptr =
+                    &GetField<InlinedStringField>(message, field).GetNoArena();
+                total_size += StringSpaceUsedExcludingSelfLong(*ptr);
+              } else {
+                // Initially, the string points to the default value stored
+                // in the prototype. Only count the string if it has been
+                // changed from the default value.
+                // Except oneof fields, those never point to a default instance,
+                // and there is no default instance to point to.
+                const auto& str = GetField<ArenaStringPtr>(message, field);
+                if (!str.IsDefault() || schema_.InRealOneof(field)) {
+                  // string fields are represented by just a pointer, so also
+                  // include sizeof(string) as well.
+                  total_size += sizeof(std::string) +
+                                StringSpaceUsedExcludingSelfLong(str.Get());
+                }
+              }
+              break;
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (schema_.IsDefaultInstance(message)) {
+            // For singular fields, the prototype just stores a pointer to the
+            // external type's prototype, so there is no extra memory usage.
+          } else {
+            const Message* sub_message = GetRaw<const Message*>(message, field);
+            if (sub_message != nullptr) {
+              total_size += sub_message->SpaceUsedLong();
+            }
+          }
+          break;
+      }
+    }
+  }
+  return total_size;
+}
+
+namespace {
+
+template <bool unsafe_shallow_swap>
+struct OneofFieldMover {
+  template <typename FromType, typename ToType>
+  void operator()(const FieldDescriptor* field, FromType* from, ToType* to) {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        to->SetInt32(from->GetInt32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        to->SetInt64(from->GetInt64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        to->SetUint32(from->GetUint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        to->SetUint64(from->GetUint64());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        to->SetFloat(from->GetFloat());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        to->SetDouble(from->GetDouble());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        to->SetBool(from->GetBool());
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        to->SetEnum(from->GetEnum());
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (!unsafe_shallow_swap) {
+          to->SetMessage(from->GetMessage());
+        } else {
+          to->UnsafeSetMessage(from->UnsafeGetMessage());
+        }
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        if (!unsafe_shallow_swap) {
+          to->SetString(from->GetString());
+          break;
+        }
+        switch (field->options().ctype()) {
+          default:
+          case FieldOptions::STRING: {
+            to->SetArenaStringPtr(from->GetArenaStringPtr());
+            break;
+          }
+        }
+        break;
+      default:
+        GOOGLE_LOG(FATAL) << "unimplemented type: " << field->cpp_type();
+    }
+    if (unsafe_shallow_swap) {
+      // Not clearing oneof case after move may cause unwanted "ClearOneof"
+      // where the residual message or string value is deleted and causes
+      // use-after-free (only for unsafe swap).
+      from->ClearOneofCase();
+    }
+  }
+};
+
+}  // namespace
+
+namespace internal {
+
+class SwapFieldHelper {
+ public:
+  template <bool unsafe_shallow_swap>
+  static void SwapRepeatedStringField(const Reflection* r, Message* lhs,
+                                      Message* rhs,
+                                      const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapInlinedStrings(const Reflection* r, Message* lhs,
+                                 Message* rhs, const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapNonInlinedStrings(const Reflection* r, Message* lhs,
+                                    Message* rhs, const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapStringField(const Reflection* r, Message* lhs, Message* rhs,
+                              const FieldDescriptor* field);
+
+  static void SwapArenaStringPtr(ArenaStringPtr* lhs, Arena* lhs_arena,
+                                 ArenaStringPtr* rhs, Arena* rhs_arena);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapRepeatedMessageField(const Reflection* r, Message* lhs,
+                                       Message* rhs,
+                                       const FieldDescriptor* field);
+
+  template <bool unsafe_shallow_swap>
+  static void SwapMessageField(const Reflection* r, Message* lhs, Message* rhs,
+                               const FieldDescriptor* field);
+
+  static void SwapMessage(const Reflection* r, Message* lhs, Arena* lhs_arena,
+                          Message* rhs, Arena* rhs_arena,
+                          const FieldDescriptor* field);
+
+  static void SwapNonMessageNonStringField(const Reflection* r, Message* lhs,
+                                           Message* rhs,
+                                           const FieldDescriptor* field);
+};
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs,
+                                              Message* rhs,
+                                              const FieldDescriptor* field) {
+  switch (field->options().ctype()) {
+    default:
+    case FieldOptions::STRING: {
+      auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field);
+      auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field);
+      if (unsafe_shallow_swap) {
+        lhs_string->InternalSwap(rhs_string);
+      } else {
+        lhs_string->Swap<GenericTypeHandler<std::string>>(rhs_string);
+      }
+      break;
+    }
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapInlinedStrings(const Reflection* r, Message* lhs,
+                                         Message* rhs,
+                                         const FieldDescriptor* field) {
+  // Inlined string field.
+  Arena* lhs_arena = lhs->GetArenaForAllocation();
+  Arena* rhs_arena = rhs->GetArenaForAllocation();
+  auto* lhs_string = r->MutableRaw<InlinedStringField>(lhs, field);
+  auto* rhs_string = r->MutableRaw<InlinedStringField>(rhs, field);
+  uint32_t index = r->schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  uint32_t* lhs_array = r->MutableInlinedStringDonatedArray(lhs);
+  uint32_t* rhs_array = r->MutableInlinedStringDonatedArray(rhs);
+  uint32_t* lhs_state = &lhs_array[index / 32];
+  uint32_t* rhs_state = &rhs_array[index / 32];
+  bool lhs_arena_dtor_registered = (lhs_array[0] & 0x1u) == 0;
+  bool rhs_arena_dtor_registered = (rhs_array[0] & 0x1u) == 0;
+  const uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
+  if (unsafe_shallow_swap || lhs_arena == rhs_arena) {
+    InlinedStringField::InternalSwap(lhs_string, lhs_arena,
+                                     lhs_arena_dtor_registered, lhs, rhs_string,
+                                     rhs_arena, rhs_arena_dtor_registered, rhs);
+  } else {
+    const std::string temp = lhs_string->Get();
+    lhs_string->Set(rhs_string->Get(), lhs_arena,
+                    r->IsInlinedStringDonated(*lhs, field), lhs_state, mask,
+                    lhs);
+    rhs_string->Set(temp, rhs_arena, r->IsInlinedStringDonated(*rhs, field),
+                    rhs_state, mask, rhs);
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapNonInlinedStrings(const Reflection* r, Message* lhs,
+                                            Message* rhs,
+                                            const FieldDescriptor* field) {
+  ArenaStringPtr* lhs_string = r->MutableRaw<ArenaStringPtr>(lhs, field);
+  ArenaStringPtr* rhs_string = r->MutableRaw<ArenaStringPtr>(rhs, field);
+  if (unsafe_shallow_swap) {
+    ArenaStringPtr::UnsafeShallowSwap(lhs_string, rhs_string);
+  } else {
+    SwapFieldHelper::SwapArenaStringPtr(
+        lhs_string, lhs->GetArenaForAllocation(),  //
+        rhs_string, rhs->GetArenaForAllocation());
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
+                                      Message* rhs,
+                                      const FieldDescriptor* field) {
+  switch (field->options().ctype()) {
+    default:
+    case FieldOptions::STRING: {
+      if (r->IsInlined(field)) {
+        SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
+                                                                 field);
+      } else {
+        SwapFieldHelper::SwapNonInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
+                                                                    field);
+      }
+      break;
+    }
+  }
+}
+
+void SwapFieldHelper::SwapArenaStringPtr(ArenaStringPtr* lhs, Arena* lhs_arena,
+                                         ArenaStringPtr* rhs,
+                                         Arena* rhs_arena) {
+  if (lhs_arena == rhs_arena) {
+    ArenaStringPtr::InternalSwap(lhs, lhs_arena, rhs, rhs_arena);
+  } else if (lhs->IsDefault() && rhs->IsDefault()) {
+    // Nothing to do.
+  } else if (lhs->IsDefault()) {
+    lhs->Set(rhs->Get(), lhs_arena);
+    // rhs needs to be destroyed before overwritten.
+    rhs->Destroy();
+    rhs->InitDefault();
+  } else if (rhs->IsDefault()) {
+    rhs->Set(lhs->Get(), rhs_arena);
+    // lhs needs to be destroyed before overwritten.
+    lhs->Destroy();
+    lhs->InitDefault();
+  } else {
+    std::string temp = lhs->Get();
+    lhs->Set(rhs->Get(), lhs_arena);
+    rhs->Set(std::move(temp), rhs_arena);
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapRepeatedMessageField(const Reflection* r,
+                                               Message* lhs, Message* rhs,
+                                               const FieldDescriptor* field) {
+  if (IsMapFieldInApi(field)) {
+    auto* lhs_map = r->MutableRaw<MapFieldBase>(lhs, field);
+    auto* rhs_map = r->MutableRaw<MapFieldBase>(rhs, field);
+    if (unsafe_shallow_swap) {
+      lhs_map->UnsafeShallowSwap(rhs_map);
+    } else {
+      lhs_map->Swap(rhs_map);
+    }
+  } else {
+    auto* lhs_rm = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field);
+    auto* rhs_rm = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field);
+    if (unsafe_shallow_swap) {
+      lhs_rm->InternalSwap(rhs_rm);
+    } else {
+      lhs_rm->Swap<GenericTypeHandler<Message>>(rhs_rm);
+    }
+  }
+}
+
+template <bool unsafe_shallow_swap>
+void SwapFieldHelper::SwapMessageField(const Reflection* r, Message* lhs,
+                                       Message* rhs,
+                                       const FieldDescriptor* field) {
+  if (unsafe_shallow_swap) {
+    std::swap(*r->MutableRaw<Message*>(lhs, field),
+              *r->MutableRaw<Message*>(rhs, field));
+  } else {
+    SwapMessage(r, lhs, lhs->GetArenaForAllocation(), rhs,
+                rhs->GetArenaForAllocation(), field);
+  }
+}
+
+void SwapFieldHelper::SwapMessage(const Reflection* r, Message* lhs,
+                                  Arena* lhs_arena, Message* rhs,
+                                  Arena* rhs_arena,
+                                  const FieldDescriptor* field) {
+  Message** lhs_sub = r->MutableRaw<Message*>(lhs, field);
+  Message** rhs_sub = r->MutableRaw<Message*>(rhs, field);
+
+  if (*lhs_sub == *rhs_sub) return;
+
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (lhs_arena != nullptr && lhs_arena == rhs_arena) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (lhs_arena == rhs_arena) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    std::swap(*lhs_sub, *rhs_sub);
+    return;
+  }
+
+  if (*lhs_sub != nullptr && *rhs_sub != nullptr) {
+    (*lhs_sub)->GetReflection()->Swap(*lhs_sub, *rhs_sub);
+  } else if (*lhs_sub == nullptr && r->HasBit(*rhs, field)) {
+    *lhs_sub = (*rhs_sub)->New(lhs_arena);
+    (*lhs_sub)->CopyFrom(**rhs_sub);
+    r->ClearField(rhs, field);
+    // Ensures has bit is unchanged after ClearField.
+    r->SetBit(rhs, field);
+  } else if (*rhs_sub == nullptr && r->HasBit(*lhs, field)) {
+    *rhs_sub = (*lhs_sub)->New(rhs_arena);
+    (*rhs_sub)->CopyFrom(**lhs_sub);
+    r->ClearField(lhs, field);
+    // Ensures has bit is unchanged after ClearField.
+    r->SetBit(lhs, field);
+  }
+}
+
+void SwapFieldHelper::SwapNonMessageNonStringField(
+    const Reflection* r, Message* lhs, Message* rhs,
+    const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+#define SWAP_VALUES(CPPTYPE, TYPE)               \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:       \
+    std::swap(*r->MutableRaw<TYPE>(lhs, field),  \
+              *r->MutableRaw<TYPE>(rhs, field)); \
+    break;
+
+    SWAP_VALUES(INT32, int32_t);
+    SWAP_VALUES(INT64, int64_t);
+    SWAP_VALUES(UINT32, uint32_t);
+    SWAP_VALUES(UINT64, uint64_t);
+    SWAP_VALUES(FLOAT, float);
+    SWAP_VALUES(DOUBLE, double);
+    SWAP_VALUES(BOOL, bool);
+    SWAP_VALUES(ENUM, int);
+#undef SWAP_VALUES
+    default:
+      GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+  }
+}
+
+}  // namespace internal
+
+void Reflection::SwapField(Message* message1, Message* message2,
+                           const FieldDescriptor* field) const {
+  if (field->is_repeated()) {
+    switch (field->cpp_type()) {
+#define SWAP_ARRAYS(CPPTYPE, TYPE)                                 \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                         \
+    MutableRaw<RepeatedField<TYPE> >(message1, field)              \
+        ->Swap(MutableRaw<RepeatedField<TYPE> >(message2, field)); \
+    break;
+
+      SWAP_ARRAYS(INT32, int32_t);
+      SWAP_ARRAYS(INT64, int64_t);
+      SWAP_ARRAYS(UINT32, uint32_t);
+      SWAP_ARRAYS(UINT64, uint64_t);
+      SWAP_ARRAYS(FLOAT, float);
+      SWAP_ARRAYS(DOUBLE, double);
+      SWAP_ARRAYS(BOOL, bool);
+      SWAP_ARRAYS(ENUM, int);
+#undef SWAP_ARRAYS
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        internal::SwapFieldHelper::SwapRepeatedStringField<false>(
+            this, message1, message2, field);
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        internal::SwapFieldHelper::SwapRepeatedMessageField<false>(
+            this, message1, message2, field);
+        break;
+
+      default:
+        GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+    }
+  } else {
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        internal::SwapFieldHelper::SwapMessageField<false>(this, message1,
+                                                           message2, field);
+        break;
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        internal::SwapFieldHelper::SwapStringField<false>(this, message1,
+                                                          message2, field);
+        break;
+      default:
+        internal::SwapFieldHelper::SwapNonMessageNonStringField(
+            this, message1, message2, field);
+    }
+  }
+}
+
+void Reflection::UnsafeShallowSwapField(Message* message1, Message* message2,
+                                        const FieldDescriptor* field) const {
+  if (!field->is_repeated()) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      internal::SwapFieldHelper::SwapMessageField<true>(this, message1,
+                                                        message2, field);
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      internal::SwapFieldHelper::SwapStringField<true>(this, message1, message2,
+                                                       field);
+    } else {
+      internal::SwapFieldHelper::SwapNonMessageNonStringField(this, message1,
+                                                              message2, field);
+    }
+    return;
+  }
+
+  switch (field->cpp_type()) {
+#define SHALLOW_SWAP_ARRAYS(CPPTYPE, TYPE)                                \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                                \
+    MutableRaw<RepeatedField<TYPE>>(message1, field)                      \
+        ->InternalSwap(MutableRaw<RepeatedField<TYPE>>(message2, field)); \
+    break;
+
+    SHALLOW_SWAP_ARRAYS(INT32, int32_t);
+    SHALLOW_SWAP_ARRAYS(INT64, int64_t);
+    SHALLOW_SWAP_ARRAYS(UINT32, uint32_t);
+    SHALLOW_SWAP_ARRAYS(UINT64, uint64_t);
+    SHALLOW_SWAP_ARRAYS(FLOAT, float);
+    SHALLOW_SWAP_ARRAYS(DOUBLE, double);
+    SHALLOW_SWAP_ARRAYS(BOOL, bool);
+    SHALLOW_SWAP_ARRAYS(ENUM, int);
+#undef SHALLOW_SWAP_ARRAYS
+
+    case FieldDescriptor::CPPTYPE_STRING:
+      internal::SwapFieldHelper::SwapRepeatedStringField<true>(this, message1,
+                                                               message2, field);
+      break;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      internal::SwapFieldHelper::SwapRepeatedMessageField<true>(
+          this, message1, message2, field);
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+  }
+}
+
+// Swaps oneof field between lhs and rhs. If unsafe_shallow_swap is true, it
+// directly swaps oneof values; otherwise, it may involve copy/delete. Note that
+// two messages may have different oneof cases. So, it has to be done in three
+// steps (i.e. lhs -> temp, rhs -> lhs, temp -> rhs).
+template <bool unsafe_shallow_swap>
+void Reflection::SwapOneofField(Message* lhs, Message* rhs,
+                                const OneofDescriptor* oneof_descriptor) const {
+  // Wraps a local variable to temporarily store oneof value.
+  struct LocalVarWrapper {
+#define LOCAL_VAR_ACCESSOR(type, var, name)               \
+  type Get##name() const { return oneof_val.type_##var; } \
+  void Set##name(type v) { oneof_val.type_##var = v; }
+
+    LOCAL_VAR_ACCESSOR(int32_t, int32, Int32);
+    LOCAL_VAR_ACCESSOR(int64_t, int64, Int64);
+    LOCAL_VAR_ACCESSOR(uint32_t, uint32, Uint32);
+    LOCAL_VAR_ACCESSOR(uint64_t, uint64, Uint64);
+    LOCAL_VAR_ACCESSOR(float, float, Float);
+    LOCAL_VAR_ACCESSOR(double, double, Double);
+    LOCAL_VAR_ACCESSOR(bool, bool, Bool);
+    LOCAL_VAR_ACCESSOR(int, enum, Enum);
+    LOCAL_VAR_ACCESSOR(Message*, message, Message);
+    LOCAL_VAR_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
+    const std::string& GetString() const { return string_val; }
+    void SetString(const std::string& v) { string_val = v; }
+    Message* UnsafeGetMessage() const { return GetMessage(); }
+    void UnsafeSetMessage(Message* v) { SetMessage(v); }
+    void ClearOneofCase() {}
+
+    union {
+      int32_t type_int32;
+      int64_t type_int64;
+      uint32_t type_uint32;
+      uint64_t type_uint64;
+      float type_float;
+      double type_double;
+      bool type_bool;
+      int type_enum;
+      Message* type_message;
+      internal::ArenaStringPtr type_arena_string_ptr;
+    } oneof_val;
+
+    // std::string cannot be in union.
+    std::string string_val;
+  };
+
+  // Wraps a message pointer to read and write a field.
+  struct MessageWrapper {
+#define MESSAGE_FIELD_ACCESSOR(type, var, name)         \
+  type Get##name() const {                              \
+    return reflection->GetField<type>(*message, field); \
+  }                                                     \
+  void Set##name(type v) { reflection->SetField<type>(message, field, v); }
+
+    MESSAGE_FIELD_ACCESSOR(int32_t, int32, Int32);
+    MESSAGE_FIELD_ACCESSOR(int64_t, int64, Int64);
+    MESSAGE_FIELD_ACCESSOR(uint32_t, uint32, Uint32);
+    MESSAGE_FIELD_ACCESSOR(uint64_t, uint64, Uint64);
+    MESSAGE_FIELD_ACCESSOR(float, float, Float);
+    MESSAGE_FIELD_ACCESSOR(double, double, Double);
+    MESSAGE_FIELD_ACCESSOR(bool, bool, Bool);
+    MESSAGE_FIELD_ACCESSOR(int, enum, Enum);
+    MESSAGE_FIELD_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
+    std::string GetString() const {
+      return reflection->GetString(*message, field);
+    }
+    void SetString(const std::string& v) {
+      reflection->SetString(message, field, v);
+    }
+    Message* GetMessage() const {
+      return reflection->ReleaseMessage(message, field);
+    }
+    void SetMessage(Message* v) {
+      reflection->SetAllocatedMessage(message, v, field);
+    }
+    Message* UnsafeGetMessage() const {
+      return reflection->UnsafeArenaReleaseMessage(message, field);
+    }
+    void UnsafeSetMessage(Message* v) {
+      reflection->UnsafeArenaSetAllocatedMessage(message, v, field);
+    }
+    void ClearOneofCase() {
+      *reflection->MutableOneofCase(message, field->containing_oneof()) = 0;
+    }
+
+    const Reflection* reflection;
+    Message* message;
+    const FieldDescriptor* field;
+  };
+
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  uint32_t oneof_case_lhs = GetOneofCase(*lhs, oneof_descriptor);
+  uint32_t oneof_case_rhs = GetOneofCase(*rhs, oneof_descriptor);
+
+  LocalVarWrapper temp;
+  MessageWrapper lhs_wrapper, rhs_wrapper;
+  const FieldDescriptor* field_lhs = nullptr;
+  OneofFieldMover<unsafe_shallow_swap> mover;
+  // lhs --> temp
+  if (oneof_case_lhs > 0) {
+    field_lhs = descriptor_->FindFieldByNumber(oneof_case_lhs);
+    lhs_wrapper = {this, lhs, field_lhs};
+    mover(field_lhs, &lhs_wrapper, &temp);
+  }
+  // rhs --> lhs
+  if (oneof_case_rhs > 0) {
+    const FieldDescriptor* f = descriptor_->FindFieldByNumber(oneof_case_rhs);
+    lhs_wrapper = {this, lhs, f};
+    rhs_wrapper = {this, rhs, f};
+    mover(f, &rhs_wrapper, &lhs_wrapper);
+  } else if (!unsafe_shallow_swap) {
+    ClearOneof(lhs, oneof_descriptor);
+  }
+  // temp --> rhs
+  if (oneof_case_lhs > 0) {
+    rhs_wrapper = {this, rhs, field_lhs};
+    mover(field_lhs, &temp, &rhs_wrapper);
+  } else if (!unsafe_shallow_swap) {
+    ClearOneof(rhs, oneof_descriptor);
+  }
+
+  if (unsafe_shallow_swap) {
+    *MutableOneofCase(lhs, oneof_descriptor) = oneof_case_rhs;
+    *MutableOneofCase(rhs, oneof_descriptor) = oneof_case_lhs;
+  }
+}
+
+void Reflection::Swap(Message* message1, Message* message2) const {
+  if (message1 == message2) return;
+
+  // TODO(kenton):  Other Reflection methods should probably check this too.
+  GOOGLE_CHECK_EQ(message1->GetReflection(), this)
+      << "First argument to Swap() (of type \""
+      << message1->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+  GOOGLE_CHECK_EQ(message2->GetReflection(), this)
+      << "Second argument to Swap() (of type \""
+      << message2->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+
+  // Check that both messages are in the same arena (or both on the heap). We
+  // need to copy all data if not, due to ownership semantics.
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  if (message1->GetOwningArena() == nullptr ||
+      message1->GetOwningArena() != message2->GetOwningArena()) {
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  if (message1->GetOwningArena() != message2->GetOwningArena()) {
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    // One of the two is guaranteed to have an arena.  Switch things around
+    // to guarantee that message1 has an arena.
+    Arena* arena = message1->GetOwningArena();
+    if (arena == nullptr) {
+      arena = message2->GetOwningArena();
+      std::swap(message1, message2);  // Swapping names for pointers!
+    }
+
+    Message* temp = message1->New(arena);
+    temp->MergeFrom(*message2);
+    message2->CopyFrom(*message1);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    message1->CopyFrom(*temp);
+    if (arena == nullptr) delete temp;
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    Swap(message1, temp);
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    return;
+  }
+
+  GOOGLE_DCHECK_EQ(message1->GetOwningArena(), message2->GetOwningArena());
+
+  UnsafeArenaSwap(message1, message2);
+}
+
+template <bool unsafe_shallow_swap>
+void Reflection::SwapFieldsImpl(
+    Message* message1, Message* message2,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  if (message1 == message2) return;
+
+  // TODO(kenton):  Other Reflection methods should probably check this too.
+  GOOGLE_CHECK_EQ(message1->GetReflection(), this)
+      << "First argument to SwapFields() (of type \""
+      << message1->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+  GOOGLE_CHECK_EQ(message2->GetReflection(), this)
+      << "Second argument to SwapFields() (of type \""
+      << message2->GetDescriptor()->full_name()
+      << "\") is not compatible with this reflection object (which is for type "
+         "\""
+      << descriptor_->full_name()
+      << "\").  Note that the exact same class is required; not just the same "
+         "descriptor.";
+
+  std::set<int> swapped_oneof;
+
+  GOOGLE_DCHECK(!unsafe_shallow_swap || message1->GetArenaForAllocation() ==
+                                     message2->GetArenaForAllocation());
+
+  const Message* prototype =
+      message_factory_->GetPrototype(message1->GetDescriptor());
+  for (const auto* field : fields) {
+    CheckInvalidAccess(schema_, field);
+    if (field->is_extension()) {
+      if (unsafe_shallow_swap) {
+        MutableExtensionSet(message1)->UnsafeShallowSwapExtension(
+            MutableExtensionSet(message2), field->number());
+      } else {
+        MutableExtensionSet(message1)->SwapExtension(
+            prototype, MutableExtensionSet(message2), field->number());
+      }
+    } else {
+      if (schema_.InRealOneof(field)) {
+        int oneof_index = field->containing_oneof()->index();
+        // Only swap the oneof field once.
+        if (swapped_oneof.find(oneof_index) != swapped_oneof.end()) {
+          continue;
+        }
+        swapped_oneof.insert(oneof_index);
+        SwapOneofField<unsafe_shallow_swap>(message1, message2,
+                                            field->containing_oneof());
+      } else {
+        // Swap field.
+        if (unsafe_shallow_swap) {
+          UnsafeShallowSwapField(message1, message2, field);
+        } else {
+          SwapField(message1, message2, field);
+        }
+        // Swap has bit for non-repeated fields.  We have already checked for
+        // oneof already. This has to be done after SwapField, because SwapField
+        // may depend on the information in has bits.
+        if (!field->is_repeated()) {
+          SwapBit(message1, message2, field);
+          if (field->options().ctype() == FieldOptions::STRING &&
+              IsInlined(field)) {
+            GOOGLE_DCHECK(!unsafe_shallow_swap ||
+                   message1->GetArenaForAllocation() ==
+                       message2->GetArenaForAllocation());
+            SwapInlinedStringDonated(message1, message2, field);
+          }
+        }
+      }
+    }
+  }
+}
+
+void Reflection::SwapFields(
+    Message* message1, Message* message2,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  SwapFieldsImpl<false>(message1, message2, fields);
+}
+
+void Reflection::UnsafeShallowSwapFields(
+    Message* message1, Message* message2,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  SwapFieldsImpl<true>(message1, message2, fields);
+}
+
+void Reflection::UnsafeArenaSwapFields(
+    Message* lhs, Message* rhs,
+    const std::vector<const FieldDescriptor*>& fields) const {
+  GOOGLE_DCHECK_EQ(lhs->GetArenaForAllocation(), rhs->GetArenaForAllocation());
+  UnsafeShallowSwapFields(lhs, rhs, fields);
+}
+
+// -------------------------------------------------------------------
+
+bool Reflection::HasField(const Message& message,
+                          const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(HasField);
+  USAGE_CHECK_SINGULAR(HasField);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return GetExtensionSet(message).Has(field->number());
+  } else {
+    if (schema_.InRealOneof(field)) {
+      return HasOneofField(message, field);
+    } else {
+      return HasBit(message, field);
+    }
+  }
+}
+
+void Reflection::UnsafeArenaSwap(Message* lhs, Message* rhs) const {
+  if (lhs == rhs) return;
+
+  MutableInternalMetadata(lhs)->InternalSwap(MutableInternalMetadata(rhs));
+
+  for (int i = 0; i <= last_non_weak_field_index_; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (schema_.InRealOneof(field)) continue;
+    if (schema_.IsFieldStripped(field)) continue;
+    UnsafeShallowSwapField(lhs, rhs, field);
+  }
+  const int oneof_decl_count = descriptor_->oneof_decl_count();
+  for (int i = 0; i < oneof_decl_count; i++) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    if (!oneof->is_synthetic()) {
+      SwapOneofField<true>(lhs, rhs, oneof);
+    }
+  }
+
+  // Swapping bits need to happen after swapping fields, because the latter may
+  // depend on the has bit information.
+  if (schema_.HasHasbits()) {
+    uint32_t* lhs_has_bits = MutableHasBits(lhs);
+    uint32_t* rhs_has_bits = MutableHasBits(rhs);
+
+    int fields_with_has_bits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_repeated() || schema_.InRealOneof(field)) {
+        continue;
+      }
+      fields_with_has_bits++;
+    }
+
+    int has_bits_size = (fields_with_has_bits + 31) / 32;
+
+    for (int i = 0; i < has_bits_size; i++) {
+      std::swap(lhs_has_bits[i], rhs_has_bits[i]);
+    }
+  }
+
+  if (schema_.HasInlinedString()) {
+    uint32_t* lhs_donated_array = MutableInlinedStringDonatedArray(lhs);
+    uint32_t* rhs_donated_array = MutableInlinedStringDonatedArray(rhs);
+    int inlined_string_count = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_extension() || field->is_repeated() ||
+          schema_.InRealOneof(field) ||
+          field->options().ctype() != FieldOptions::STRING ||
+          !IsInlined(field)) {
+        continue;
+      }
+      inlined_string_count++;
+    }
+
+    int donated_array_size = inlined_string_count == 0
+                                 ? 0
+                                 // One extra bit for the arena dtor tracking.
+                                 : (inlined_string_count + 1 + 31) / 32;
+    GOOGLE_CHECK_EQ((lhs_donated_array[0] & 0x1u) == 0,
+             (rhs_donated_array[0] & 0x1u) == 0);
+    for (int i = 0; i < donated_array_size; i++) {
+      std::swap(lhs_donated_array[i], rhs_donated_array[i]);
+    }
+  }
+
+  if (schema_.HasExtensionSet()) {
+    MutableExtensionSet(lhs)->InternalSwap(MutableExtensionSet(rhs));
+  }
+}
+
+int Reflection::FieldSize(const Message& message,
+                          const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(FieldSize);
+  USAGE_CHECK_REPEATED(FieldSize);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return GetExtensionSet(message).ExtensionSize(field->number());
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)    \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+    return GetRaw<RepeatedField<LOWERCASE> >(message, field).size()
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          const internal::MapFieldBase& map =
+              GetRaw<MapFieldBase>(message, field);
+          if (map.IsRepeatedFieldValid()) {
+            return map.GetRepeatedField().size();
+          } else {
+            // No need to materialize the repeated field if it is out of sync:
+            // its size will be the same as the map's size.
+            return map.size();
+          }
+        } else {
+          return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+        }
+    }
+
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
+  }
+}
+
+void Reflection::ClearField(Message* message,
+                            const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(ClearField);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->ClearExtension(field->number());
+  } else if (!field->is_repeated()) {
+    if (schema_.InRealOneof(field)) {
+      ClearOneofField(message, field);
+      return;
+    }
+    if (HasBit(*message, field)) {
+      ClearBit(message, field);
+
+      // We need to set the field back to its default value.
+      switch (field->cpp_type()) {
+#define CLEAR_TYPE(CPPTYPE, TYPE)                                      \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                             \
+    *MutableRaw<TYPE>(message, field) = field->default_value_##TYPE(); \
+    break;
+
+        CLEAR_TYPE(INT32, int32_t);
+        CLEAR_TYPE(INT64, int64_t);
+        CLEAR_TYPE(UINT32, uint32_t);
+        CLEAR_TYPE(UINT64, uint64_t);
+        CLEAR_TYPE(FLOAT, float);
+        CLEAR_TYPE(DOUBLE, double);
+        CLEAR_TYPE(BOOL, bool);
+#undef CLEAR_TYPE
+
+        case FieldDescriptor::CPPTYPE_ENUM:
+          *MutableRaw<int>(message, field) =
+              field->default_value_enum()->number();
+          break;
+
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING:
+              if (IsInlined(field)) {
+                // Currently, string with default value can't be inlined. So we
+                // don't have to handle default value here.
+                MutableRaw<InlinedStringField>(message, field)->ClearToEmpty();
+              } else {
+                auto* str = MutableRaw<ArenaStringPtr>(message, field);
+                str->Destroy();
+                str->InitDefault();
+              }
+              break;
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          if (schema_.HasBitIndex(field) == static_cast<uint32_t>(-1)) {
+            // Proto3 does not have has-bits and we need to set a message field
+            // to nullptr in order to indicate its un-presence.
+            if (message->GetArenaForAllocation() == nullptr) {
+              delete *MutableRaw<Message*>(message, field);
+            }
+            *MutableRaw<Message*>(message, field) = nullptr;
+          } else {
+            (*MutableRaw<Message*>(message, field))->Clear();
+          }
+          break;
+      }
+    }
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                           \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                        \
+    MutableRaw<RepeatedField<LOWERCASE> >(message, field)->Clear(); \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING: {
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            MutableRaw<RepeatedPtrField<std::string> >(message, field)->Clear();
+            break;
+        }
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)->Clear();
+        } else {
+          // We don't know which subclass of RepeatedPtrFieldBase the type is,
+          // so we use RepeatedPtrFieldBase directly.
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->Clear<GenericTypeHandler<Message> >();
+        }
+        break;
+      }
+    }
+  }
+}
+
+void Reflection::RemoveLast(Message* message,
+                            const FieldDescriptor* field) const {
+  USAGE_CHECK_MESSAGE_TYPE(RemoveLast);
+  USAGE_CHECK_REPEATED(RemoveLast);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->RemoveLast(field->number());
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                                \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:                             \
+    MutableRaw<RepeatedField<LOWERCASE> >(message, field)->RemoveLast(); \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            MutableRaw<RepeatedPtrField<std::string> >(message, field)
+                ->RemoveLast();
+            break;
+        }
+        break;
+
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->RemoveLast<GenericTypeHandler<Message> >();
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->RemoveLast<GenericTypeHandler<Message> >();
+        }
+        break;
+    }
+  }
+}
+
+Message* Reflection::ReleaseLast(Message* message,
+                                 const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(ReleaseLast, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  Message* released;
+  if (field->is_extension()) {
+    released = static_cast<Message*>(
+        MutableExtensionSet(message)->ReleaseLast(field->number()));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      released = MutableRaw<MapFieldBase>(message, field)
+                     ->MutableRepeatedField()
+                     ->ReleaseLast<GenericTypeHandler<Message>>();
+    } else {
+      released = MutableRaw<RepeatedPtrFieldBase>(message, field)
+                     ->ReleaseLast<GenericTypeHandler<Message>>();
+    }
+  }
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  return MaybeForceCopy(message->GetArenaForAllocation(), released);
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+  return released;
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+}
+
+Message* Reflection::UnsafeArenaReleaseLast(
+    Message* message, const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(UnsafeArenaReleaseLast, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->UnsafeArenaReleaseLast(field->number()));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>();
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
+          ->UnsafeArenaReleaseLast<GenericTypeHandler<Message>>();
+    }
+  }
+}
+
+void Reflection::SwapElements(Message* message, const FieldDescriptor* field,
+                              int index1, int index2) const {
+  USAGE_CHECK_MESSAGE_TYPE(Swap);
+  USAGE_CHECK_REPEATED(Swap);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SwapElements(field->number(), index1, index2);
+  } else {
+    switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE)                 \
+  case FieldDescriptor::CPPTYPE_##UPPERCASE:              \
+    MutableRaw<RepeatedField<LOWERCASE> >(message, field) \
+        ->SwapElements(index1, index2);                   \
+    break
+
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(ENUM, int);
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::CPPTYPE_STRING:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->SwapElements(index1, index2);
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->SwapElements(index1, index2);
+        }
+        break;
+    }
+  }
+}
+
+namespace {
+// Comparison functor for sorting FieldDescriptors by field number.
+struct FieldNumberSorter {
+  bool operator()(const FieldDescriptor* left,
+                  const FieldDescriptor* right) const {
+    return left->number() < right->number();
+  }
+};
+
+bool IsIndexInHasBitSet(const uint32_t* has_bit_set, uint32_t has_bit_index) {
+  GOOGLE_DCHECK_NE(has_bit_index, ~0u);
+  return ((has_bit_set[has_bit_index / 32] >> (has_bit_index % 32)) &
+          static_cast<uint32_t>(1)) != 0;
+}
+
+bool CreateUnknownEnumValues(const FileDescriptor* file) {
+  return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+}  // namespace
+
+namespace internal {
+bool CreateUnknownEnumValues(const FieldDescriptor* field) {
+  bool open_enum = false;
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 || open_enum;
+}
+}  // namespace internal
+using internal::CreateUnknownEnumValues;
+
+void Reflection::ListFieldsMayFailOnStripped(
+    const Message& message, bool should_fail,
+    std::vector<const FieldDescriptor*>* output) const {
+  output->clear();
+
+  // Optimization:  The default instance never has any fields set.
+  if (schema_.IsDefaultInstance(message)) return;
+
+  // Optimization: Avoid calling GetHasBits() and HasOneofField() many times
+  // within the field loop.  We allow this violation of ReflectionSchema
+  // encapsulation because this function takes a noticeable about of CPU
+  // fleetwide and properly allowing this optimization through public interfaces
+  // seems more trouble than it is worth.
+  const uint32_t* const has_bits =
+      schema_.HasHasbits() ? GetHasBits(message) : nullptr;
+  const uint32_t* const has_bits_indices = schema_.has_bit_indices_;
+  output->reserve(descriptor_->field_count());
+  const int last_non_weak_field_index = last_non_weak_field_index_;
+  for (int i = 0; i <= last_non_weak_field_index; i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!should_fail && schema_.IsFieldStripped(field)) {
+      continue;
+    }
+    if (field->is_repeated()) {
+      if (FieldSize(message, field) > 0) {
+        output->push_back(field);
+      }
+    } else {
+      const OneofDescriptor* containing_oneof = field->containing_oneof();
+      if (schema_.InRealOneof(field)) {
+        const uint32_t* const oneof_case_array =
+            GetConstPointerAtOffset<uint32_t>(&message,
+                                              schema_.oneof_case_offset_);
+        // Equivalent to: HasOneofField(message, field)
+        if (static_cast<int64_t>(oneof_case_array[containing_oneof->index()]) ==
+            field->number()) {
+          output->push_back(field);
+        }
+      } else if (has_bits && has_bits_indices[i] != static_cast<uint32_t>(-1)) {
+        CheckInvalidAccess(schema_, field);
+        // Equivalent to: HasBit(message, field)
+        if (IsIndexInHasBitSet(has_bits, has_bits_indices[i])) {
+          output->push_back(field);
+        }
+      } else if (HasBit(message, field)) {  // Fall back on proto3-style HasBit.
+        output->push_back(field);
+      }
+    }
+  }
+  if (schema_.HasExtensionSet()) {
+    GetExtensionSet(message).AppendToList(descriptor_, descriptor_pool_,
+                                          output);
+  }
+
+  // ListFields() must sort output by field number.
+  std::sort(output->begin(), output->end(), FieldNumberSorter());
+}
+
+void Reflection::ListFields(const Message& message,
+                            std::vector<const FieldDescriptor*>* output) const {
+  ListFieldsMayFailOnStripped(message, true, output);
+}
+
+void Reflection::ListFieldsOmitStripped(
+    const Message& message, std::vector<const FieldDescriptor*>* output) const {
+  ListFieldsMayFailOnStripped(message, false, output);
+}
+
+// -------------------------------------------------------------------
+
+#undef DEFINE_PRIMITIVE_ACCESSORS
+#define DEFINE_PRIMITIVE_ACCESSORS(TYPENAME, TYPE, PASSTYPE, CPPTYPE)          \
+  PASSTYPE Reflection::Get##TYPENAME(const Message& message,                   \
+                                     const FieldDescriptor* field) const {     \
+    USAGE_CHECK_ALL(Get##TYPENAME, SINGULAR, CPPTYPE);                         \
+    if (field->is_extension()) {                                               \
+      return GetExtensionSet(message).Get##TYPENAME(                           \
+          field->number(), field->default_value_##PASSTYPE());                 \
+    } else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { \
+      return field->default_value_##PASSTYPE();                                \
+    } else {                                                                   \
+      return GetField<TYPE>(message, field);                                   \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  void Reflection::Set##TYPENAME(                                              \
+      Message* message, const FieldDescriptor* field, PASSTYPE value) const {  \
+    USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE);                         \
+    if (field->is_extension()) {                                               \
+      return MutableExtensionSet(message)->Set##TYPENAME(                      \
+          field->number(), field->type(), value, field);                       \
+    } else {                                                                   \
+      SetField<TYPE>(message, field, value);                                   \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  PASSTYPE Reflection::GetRepeated##TYPENAME(                                  \
+      const Message& message, const FieldDescriptor* field, int index) const { \
+    USAGE_CHECK_ALL(GetRepeated##TYPENAME, REPEATED, CPPTYPE);                 \
+    if (field->is_extension()) {                                               \
+      return GetExtensionSet(message).GetRepeated##TYPENAME(field->number(),   \
+                                                            index);            \
+    } else {                                                                   \
+      return GetRepeatedField<TYPE>(message, field, index);                    \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  void Reflection::SetRepeated##TYPENAME(Message* message,                     \
+                                         const FieldDescriptor* field,         \
+                                         int index, PASSTYPE value) const {    \
+    USAGE_CHECK_ALL(SetRepeated##TYPENAME, REPEATED, CPPTYPE);                 \
+    if (field->is_extension()) {                                               \
+      MutableExtensionSet(message)->SetRepeated##TYPENAME(field->number(),     \
+                                                          index, value);       \
+    } else {                                                                   \
+      SetRepeatedField<TYPE>(message, field, index, value);                    \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  void Reflection::Add##TYPENAME(                                              \
+      Message* message, const FieldDescriptor* field, PASSTYPE value) const {  \
+    USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE);                         \
+    if (field->is_extension()) {                                               \
+      MutableExtensionSet(message)->Add##TYPENAME(                             \
+          field->number(), field->type(), field->options().packed(), value,    \
+          field);                                                              \
+    } else {                                                                   \
+      AddField<TYPE>(message, field, value);                                   \
+    }                                                                          \
+  }
+
+DEFINE_PRIMITIVE_ACCESSORS(Int32, int32_t, int32_t, INT32)
+DEFINE_PRIMITIVE_ACCESSORS(Int64, int64_t, int64_t, INT64)
+DEFINE_PRIMITIVE_ACCESSORS(UInt32, uint32_t, uint32_t, UINT32)
+DEFINE_PRIMITIVE_ACCESSORS(UInt64, uint64_t, uint64_t, UINT64)
+DEFINE_PRIMITIVE_ACCESSORS(Float, float, float, FLOAT)
+DEFINE_PRIMITIVE_ACCESSORS(Double, double, double, DOUBLE)
+DEFINE_PRIMITIVE_ACCESSORS(Bool, bool, bool, BOOL)
+#undef DEFINE_PRIMITIVE_ACCESSORS
+
+// -------------------------------------------------------------------
+
+std::string Reflection::GetString(const Message& message,
+                                  const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(GetString, SINGULAR, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetString(field->number(),
+                                              field->default_value_string());
+  } else {
+    if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+      return field->default_value_string();
+    }
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        if (IsInlined(field)) {
+          return GetField<InlinedStringField>(message, field).GetNoArena();
+        } else {
+          const auto& str = GetField<ArenaStringPtr>(message, field);
+          return str.IsDefault() ? field->default_value_string() : str.Get();
+        }
+    }
+  }
+}
+
+const std::string& Reflection::GetStringReference(const Message& message,
+                                                  const FieldDescriptor* field,
+                                                  std::string* scratch) const {
+  (void)scratch;  // Parameter is used by Google-internal code.
+  USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetString(field->number(),
+                                              field->default_value_string());
+  } else {
+    if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+      return field->default_value_string();
+    }
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        if (IsInlined(field)) {
+          return GetField<InlinedStringField>(message, field).GetNoArena();
+        } else {
+          const auto& str = GetField<ArenaStringPtr>(message, field);
+          return str.IsDefault() ? field->default_value_string() : str.Get();
+        }
+    }
+  }
+}
+
+
+void Reflection::SetString(Message* message, const FieldDescriptor* field,
+                           std::string value) const {
+  USAGE_CHECK_ALL(SetString, SINGULAR, STRING);
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->SetString(
+        field->number(), field->type(), std::move(value), field);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING: {
+        if (IsInlined(field)) {
+          const uint32_t index = schema_.InlinedStringIndex(field);
+          GOOGLE_DCHECK_GT(index, 0);
+          uint32_t* states =
+              &MutableInlinedStringDonatedArray(message)[index / 32];
+          uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
+          MutableField<InlinedStringField>(message, field)
+              ->Set(value, message->GetArenaForAllocation(),
+                    IsInlinedStringDonated(*message, field), states, mask,
+                    message);
+          break;
+        }
+
+        // Oneof string fields are never set as a default instance.
+        // We just need to pass some arbitrary default string to make it work.
+        // This allows us to not have the real default accessible from
+        // reflection.
+        if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) {
+          ClearOneof(message, field->containing_oneof());
+          MutableField<ArenaStringPtr>(message, field)->InitDefault();
+        }
+        MutableField<ArenaStringPtr>(message, field)
+            ->Set(std::move(value), message->GetArenaForAllocation());
+        break;
+      }
+    }
+  }
+}
+
+
+std::string Reflection::GetRepeatedString(const Message& message,
+                                          const FieldDescriptor* field,
+                                          int index) const {
+  USAGE_CHECK_ALL(GetRepeatedString, REPEATED, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetRepeatedString(field->number(), index);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        return GetRepeatedPtrField<std::string>(message, field, index);
+    }
+  }
+}
+
+const std::string& Reflection::GetRepeatedStringReference(
+    const Message& message, const FieldDescriptor* field, int index,
+    std::string* scratch) const {
+  (void)scratch;  // Parameter is used by Google-internal code.
+  USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING);
+  if (field->is_extension()) {
+    return GetExtensionSet(message).GetRepeatedString(field->number(), index);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        return GetRepeatedPtrField<std::string>(message, field, index);
+    }
+  }
+}
+
+
+void Reflection::SetRepeatedString(Message* message,
+                                   const FieldDescriptor* field, int index,
+                                   std::string value) const {
+  USAGE_CHECK_ALL(SetRepeatedString, REPEATED, STRING);
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SetRepeatedString(field->number(), index,
+                                                    std::move(value));
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        MutableRepeatedField<std::string>(message, field, index)
+            ->assign(std::move(value));
+        break;
+    }
+  }
+}
+
+
+void Reflection::AddString(Message* message, const FieldDescriptor* field,
+                           std::string value) const {
+  USAGE_CHECK_ALL(AddString, REPEATED, STRING);
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddString(field->number(), field->type(),
+                                            std::move(value), field);
+  } else {
+    switch (field->options().ctype()) {
+      default:  // TODO(kenton):  Support other string reps.
+      case FieldOptions::STRING:
+        AddField<std::string>(message, field)->assign(std::move(value));
+        break;
+    }
+  }
+}
+
+
+// -------------------------------------------------------------------
+
+const EnumValueDescriptor* Reflection::GetEnum(
+    const Message& message, const FieldDescriptor* field) const {
+  // Usage checked by GetEnumValue.
+  int value = GetEnumValue(message, field);
+  return field->enum_type()->FindValueByNumberCreatingIfUnknown(value);
+}
+
+int Reflection::GetEnumValue(const Message& message,
+                             const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM);
+
+  int32_t value;
+  if (field->is_extension()) {
+    value = GetExtensionSet(message).GetEnum(
+        field->number(), field->default_value_enum()->number());
+  } else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+    value = field->default_value_enum()->number();
+  } else {
+    value = GetField<int>(message, field);
+  }
+  return value;
+}
+
+void Reflection::SetEnum(Message* message, const FieldDescriptor* field,
+                         const EnumValueDescriptor* value) const {
+  // Usage checked by SetEnumValue.
+  USAGE_CHECK_ENUM_VALUE(SetEnum);
+  SetEnumValueInternal(message, field, value->number());
+}
+
+void Reflection::SetEnumValue(Message* message, const FieldDescriptor* field,
+                              int value) const {
+  USAGE_CHECK_ALL(SetEnumValue, SINGULAR, ENUM);
+  if (!CreateUnknownEnumValues(field)) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == nullptr) {
+      MutableUnknownFields(message)->AddVarint(field->number(), value);
+      return;
+    }
+  }
+  SetEnumValueInternal(message, field, value);
+}
+
+void Reflection::SetEnumValueInternal(Message* message,
+                                      const FieldDescriptor* field,
+                                      int value) const {
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SetEnum(field->number(), field->type(), value,
+                                          field);
+  } else {
+    SetField<int>(message, field, value);
+  }
+}
+
+const EnumValueDescriptor* Reflection::GetRepeatedEnum(
+    const Message& message, const FieldDescriptor* field, int index) const {
+  // Usage checked by GetRepeatedEnumValue.
+  int value = GetRepeatedEnumValue(message, field, index);
+  return field->enum_type()->FindValueByNumberCreatingIfUnknown(value);
+}
+
+int Reflection::GetRepeatedEnumValue(const Message& message,
+                                     const FieldDescriptor* field,
+                                     int index) const {
+  USAGE_CHECK_ALL(GetRepeatedEnumValue, REPEATED, ENUM);
+
+  int value;
+  if (field->is_extension()) {
+    value = GetExtensionSet(message).GetRepeatedEnum(field->number(), index);
+  } else {
+    value = GetRepeatedField<int>(message, field, index);
+  }
+  return value;
+}
+
+void Reflection::SetRepeatedEnum(Message* message, const FieldDescriptor* field,
+                                 int index,
+                                 const EnumValueDescriptor* value) const {
+  // Usage checked by SetRepeatedEnumValue.
+  USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum);
+  SetRepeatedEnumValueInternal(message, field, index, value->number());
+}
+
+void Reflection::SetRepeatedEnumValue(Message* message,
+                                      const FieldDescriptor* field, int index,
+                                      int value) const {
+  USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM);
+  if (!CreateUnknownEnumValues(field)) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == nullptr) {
+      MutableUnknownFields(message)->AddVarint(field->number(), value);
+      return;
+    }
+  }
+  SetRepeatedEnumValueInternal(message, field, index, value);
+}
+
+void Reflection::SetRepeatedEnumValueInternal(Message* message,
+                                              const FieldDescriptor* field,
+                                              int index, int value) const {
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->SetRepeatedEnum(field->number(), index,
+                                                  value);
+  } else {
+    SetRepeatedField<int>(message, field, index, value);
+  }
+}
+
+void Reflection::AddEnum(Message* message, const FieldDescriptor* field,
+                         const EnumValueDescriptor* value) const {
+  // Usage checked by AddEnumValue.
+  USAGE_CHECK_ENUM_VALUE(AddEnum);
+  AddEnumValueInternal(message, field, value->number());
+}
+
+void Reflection::AddEnumValue(Message* message, const FieldDescriptor* field,
+                              int value) const {
+  USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM);
+  if (!CreateUnknownEnumValues(field)) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == nullptr) {
+      MutableUnknownFields(message)->AddVarint(field->number(), value);
+      return;
+    }
+  }
+  AddEnumValueInternal(message, field, value);
+}
+
+void Reflection::AddEnumValueInternal(Message* message,
+                                      const FieldDescriptor* field,
+                                      int value) const {
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddEnum(field->number(), field->type(),
+                                          field->options().packed(), value,
+                                          field);
+  } else {
+    AddField<int>(message, field, value);
+  }
+}
+
+// -------------------------------------------------------------------
+
+const Message* Reflection::GetDefaultMessageInstance(
+    const FieldDescriptor* field) const {
+  // If we are using the generated factory, we cache the prototype in the field
+  // descriptor for faster access.
+  // The default instances of generated messages are not cross-linked, which
+  // means they contain null pointers on their message fields and can't be used
+  // to get the default of submessages.
+  if (message_factory_ == MessageFactory::generated_factory()) {
+    auto& ptr = field->default_generated_instance_;
+    auto* res = ptr.load(std::memory_order_acquire);
+    if (res == nullptr) {
+      // First time asking for this field's default. Load it and cache it.
+      res = message_factory_->GetPrototype(field->message_type());
+      ptr.store(res, std::memory_order_release);
+    }
+    return res;
+  }
+
+  // For other factories, we try the default's object field.
+  // In particular, the DynamicMessageFactory will cross link the default
+  // instances to allow for this. But only do this for real fields.
+  // This is an optimization to avoid going to GetPrototype() below, as that
+  // requires a lock and a map lookup.
+  if (!field->is_extension() && !field->options().weak() &&
+      !IsLazyField(field) && !schema_.InRealOneof(field)) {
+    auto* res = DefaultRaw<const Message*>(field);
+    if (res != nullptr) {
+      return res;
+    }
+  }
+  // Otherwise, just go to the factory.
+  return message_factory_->GetPrototype(field->message_type());
+}
+
+const Message& Reflection::GetMessage(const Message& message,
+                                      const FieldDescriptor* field,
+                                      MessageFactory* factory) const {
+  USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<const Message&>(GetExtensionSet(message).GetMessage(
+        field->number(), field->message_type(), factory));
+  } else {
+    if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
+      return *GetDefaultMessageInstance(field);
+    }
+    const Message* result = GetRaw<const Message*>(message, field);
+    if (result == nullptr) {
+      result = GetDefaultMessageInstance(field);
+    }
+    return *result;
+  }
+}
+
+Message* Reflection::MutableMessage(Message* message,
+                                    const FieldDescriptor* field,
+                                    MessageFactory* factory) const {
+  USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->MutableMessage(field, factory));
+  } else {
+    Message* result;
+
+    Message** result_holder = MutableRaw<Message*>(message, field);
+
+    if (schema_.InRealOneof(field)) {
+      if (!HasOneofField(*message, field)) {
+        ClearOneof(message, field->containing_oneof());
+        result_holder = MutableField<Message*>(message, field);
+        const Message* default_message = GetDefaultMessageInstance(field);
+        *result_holder = default_message->New(message->GetArenaForAllocation());
+      }
+    } else {
+      SetBit(message, field);
+    }
+
+    if (*result_holder == nullptr) {
+      const Message* default_message = GetDefaultMessageInstance(field);
+      *result_holder = default_message->New(message->GetArenaForAllocation());
+    }
+    result = *result_holder;
+    return result;
+  }
+}
+
+void Reflection::UnsafeArenaSetAllocatedMessage(
+    Message* message, Message* sub_message,
+    const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(SetAllocatedMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->UnsafeArenaSetAllocatedMessage(
+        field->number(), field->type(), field, sub_message);
+  } else {
+    if (schema_.InRealOneof(field)) {
+      if (sub_message == nullptr) {
+        ClearOneof(message, field->containing_oneof());
+        return;
+      }
+        ClearOneof(message, field->containing_oneof());
+        *MutableRaw<Message*>(message, field) = sub_message;
+      SetOneofCase(message, field);
+      return;
+    }
+
+    if (sub_message == nullptr) {
+      ClearBit(message, field);
+    } else {
+      SetBit(message, field);
+    }
+    Message** sub_message_holder = MutableRaw<Message*>(message, field);
+    if (message->GetArenaForAllocation() == nullptr) {
+      delete *sub_message_holder;
+    }
+    *sub_message_holder = sub_message;
+  }
+}
+
+void Reflection::SetAllocatedMessage(Message* message, Message* sub_message,
+                                     const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(sub_message == nullptr || sub_message->GetOwningArena() == nullptr ||
+         sub_message->GetOwningArena() == message->GetArenaForAllocation());
+  CheckInvalidAccess(schema_, field);
+
+  // If message and sub-message are in different memory ownership domains
+  // (different arenas, or one is on heap and one is not), then we may need to
+  // do a copy.
+  if (sub_message != nullptr &&
+      sub_message->GetOwningArena() != message->GetArenaForAllocation()) {
+    if (sub_message->GetOwningArena() == nullptr &&
+        message->GetArenaForAllocation() != nullptr) {
+      // Case 1: parent is on an arena and child is heap-allocated. We can add
+      // the child to the arena's Own() list to free on arena destruction, then
+      // set our pointer.
+      message->GetArenaForAllocation()->Own(sub_message);
+      UnsafeArenaSetAllocatedMessage(message, sub_message, field);
+    } else {
+      // Case 2: all other cases. We need to make a copy. MutableMessage() will
+      // either get the existing message object, or instantiate a new one as
+      // appropriate w.r.t. our arena.
+      Message* sub_message_copy = MutableMessage(message, field);
+      sub_message_copy->CopyFrom(*sub_message);
+    }
+  } else {
+    // Same memory ownership domains.
+    UnsafeArenaSetAllocatedMessage(message, sub_message, field);
+  }
+}
+
+Message* Reflection::UnsafeArenaReleaseMessage(Message* message,
+                                               const FieldDescriptor* field,
+                                               MessageFactory* factory) const {
+  USAGE_CHECK_ALL(ReleaseMessage, SINGULAR, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->UnsafeArenaReleaseMessage(field,
+                                                                factory));
+  } else {
+    if (!(field->is_repeated() || schema_.InRealOneof(field))) {
+      ClearBit(message, field);
+    }
+    if (schema_.InRealOneof(field)) {
+      if (HasOneofField(*message, field)) {
+        *MutableOneofCase(message, field->containing_oneof()) = 0;
+      } else {
+        return nullptr;
+      }
+    }
+    Message** result = MutableRaw<Message*>(message, field);
+    Message* ret = *result;
+    *result = nullptr;
+    return ret;
+  }
+}
+
+Message* Reflection::ReleaseMessage(Message* message,
+                                    const FieldDescriptor* field,
+                                    MessageFactory* factory) const {
+  CheckInvalidAccess(schema_, field);
+
+  Message* released = UnsafeArenaReleaseMessage(message, field, factory);
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+  released = MaybeForceCopy(message->GetArenaForAllocation(), released);
+#endif  // PROTOBUF_FORCE_COPY_IN_RELEASE
+  if (message->GetArenaForAllocation() != nullptr && released != nullptr) {
+    Message* copy_from_arena = released->New();
+    copy_from_arena->CopyFrom(*released);
+    released = copy_from_arena;
+  }
+  return released;
+}
+
+const Message& Reflection::GetRepeatedMessage(const Message& message,
+                                              const FieldDescriptor* field,
+                                              int index) const {
+  USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<const Message&>(
+        GetExtensionSet(message).GetRepeatedMessage(field->number(), index));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return GetRaw<MapFieldBase>(message, field)
+          .GetRepeatedField()
+          .Get<GenericTypeHandler<Message> >(index);
+    } else {
+      return GetRaw<RepeatedPtrFieldBase>(message, field)
+          .Get<GenericTypeHandler<Message> >(index);
+    }
+  }
+}
+
+Message* Reflection::MutableRepeatedMessage(Message* message,
+                                            const FieldDescriptor* field,
+                                            int index) const {
+  USAGE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->MutableRepeatedMessage(field->number(),
+                                                             index));
+  } else {
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->Mutable<GenericTypeHandler<Message> >(index);
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
+          ->Mutable<GenericTypeHandler<Message> >(index);
+    }
+  }
+}
+
+Message* Reflection::AddMessage(Message* message, const FieldDescriptor* field,
+                                MessageFactory* factory) const {
+  USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (factory == nullptr) factory = message_factory_;
+
+  if (field->is_extension()) {
+    return static_cast<Message*>(
+        MutableExtensionSet(message)->AddMessage(field, factory));
+  } else {
+    Message* result = nullptr;
+
+    // We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
+    // know how to allocate one.
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
+    if (result == nullptr) {
+      // We must allocate a new object.
+      const Message* prototype;
+      if (repeated->size() == 0) {
+        prototype = factory->GetPrototype(field->message_type());
+      } else {
+        prototype = &repeated->Get<GenericTypeHandler<Message> >(0);
+      }
+      result = prototype->New(message->GetArenaForAllocation());
+      // We can guarantee here that repeated and result are either both heap
+      // allocated or arena owned. So it is safe to call the unsafe version
+      // of AddAllocated.
+      repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message> >(result);
+    }
+
+    return result;
+  }
+}
+
+void Reflection::AddAllocatedMessage(Message* message,
+                                     const FieldDescriptor* field,
+                                     Message* new_entry) const {
+  USAGE_CHECK_ALL(AddAllocatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddAllocatedMessage(field, new_entry);
+  } else {
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    repeated->AddAllocated<GenericTypeHandler<Message> >(new_entry);
+  }
+}
+
+void Reflection::UnsafeArenaAddAllocatedMessage(Message* message,
+                                                const FieldDescriptor* field,
+                                                Message* new_entry) const {
+  USAGE_CHECK_ALL(UnsafeArenaAddAllocatedMessage, REPEATED, MESSAGE);
+  CheckInvalidAccess(schema_, field);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->UnsafeArenaAddAllocatedMessage(field,
+                                                                 new_entry);
+  } else {
+    RepeatedPtrFieldBase* repeated = nullptr;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message>>(new_entry);
+  }
+}
+
+void* Reflection::MutableRawRepeatedField(Message* message,
+                                          const FieldDescriptor* field,
+                                          FieldDescriptor::CppType cpptype,
+                                          int ctype,
+                                          const Descriptor* desc) const {
+  (void)ctype;  // Parameter is used by Google-internal code.
+  USAGE_CHECK_REPEATED("MutableRawRepeatedField");
+  CheckInvalidAccess(schema_, field);
+
+  if (field->cpp_type() != cpptype &&
+      (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM ||
+       cpptype != FieldDescriptor::CPPTYPE_INT32))
+    ReportReflectionUsageTypeError(descriptor_, field,
+                                   "MutableRawRepeatedField", cpptype);
+  if (desc != nullptr)
+    GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->MutableRawRepeatedField(
+        field->number(), field->type(), field->is_packed(), field);
+  } else {
+    // Trigger transform for MapField
+    if (IsMapFieldInApi(field)) {
+      return MutableRawNonOneof<MapFieldBase>(message, field)
+          ->MutableRepeatedField();
+    }
+    return MutableRawNonOneof<void>(message, field);
+  }
+}
+
+const void* Reflection::GetRawRepeatedField(const Message& message,
+                                            const FieldDescriptor* field,
+                                            FieldDescriptor::CppType cpptype,
+                                            int ctype,
+                                            const Descriptor* desc) const {
+  USAGE_CHECK_REPEATED("GetRawRepeatedField");
+  if (field->cpp_type() != cpptype)
+    ReportReflectionUsageTypeError(descriptor_, field, "GetRawRepeatedField",
+                                   cpptype);
+  if (ctype >= 0)
+    GOOGLE_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch";
+  if (desc != nullptr)
+    GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
+  if (field->is_extension()) {
+    // Should use extension_set::GetRawRepeatedField. However, the required
+    // parameter "default repeated value" is not very easy to get here.
+    // Map is not supported in extensions, it is acceptable to use
+    // extension_set::MutableRawRepeatedField which does not change the message.
+    return MutableExtensionSet(const_cast<Message*>(&message))
+        ->MutableRawRepeatedField(field->number(), field->type(),
+                                  field->is_packed(), field);
+  } else {
+    // Trigger transform for MapField
+    if (IsMapFieldInApi(field)) {
+      return &(GetRawNonOneof<MapFieldBase>(message, field).GetRepeatedField());
+    }
+    return &GetRawNonOneof<char>(message, field);
+  }
+}
+
+const FieldDescriptor* Reflection::GetOneofFieldDescriptor(
+    const Message& message, const OneofDescriptor* oneof_descriptor) const {
+  if (oneof_descriptor->is_synthetic()) {
+    const FieldDescriptor* field = oneof_descriptor->field(0);
+    return HasField(message, field) ? field : nullptr;
+  }
+  uint32_t field_number = GetOneofCase(message, oneof_descriptor);
+  if (field_number == 0) {
+    return nullptr;
+  }
+  return descriptor_->FindFieldByNumber(field_number);
+}
+
+bool Reflection::ContainsMapKey(const Message& message,
+                                const FieldDescriptor* field,
+                                const MapKey& key) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "LookupMapValue",
+              "Field is not a map field.");
+  return GetRaw<MapFieldBase>(message, field).ContainsMapKey(key);
+}
+
+bool Reflection::InsertOrLookupMapValue(Message* message,
+                                        const FieldDescriptor* field,
+                                        const MapKey& key,
+                                        MapValueRef* val) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "InsertOrLookupMapValue",
+              "Field is not a map field.");
+  val->SetType(field->message_type()->map_value()->cpp_type());
+  return MutableRaw<MapFieldBase>(message, field)
+      ->InsertOrLookupMapValue(key, val);
+}
+
+bool Reflection::LookupMapValue(const Message& message,
+                                const FieldDescriptor* field, const MapKey& key,
+                                MapValueConstRef* val) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "LookupMapValue",
+              "Field is not a map field.");
+  val->SetType(field->message_type()->map_value()->cpp_type());
+  return GetRaw<MapFieldBase>(message, field).LookupMapValue(key, val);
+}
+
+bool Reflection::DeleteMapValue(Message* message, const FieldDescriptor* field,
+                                const MapKey& key) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "DeleteMapValue",
+              "Field is not a map field.");
+  return MutableRaw<MapFieldBase>(message, field)->DeleteMapValue(key);
+}
+
+MapIterator Reflection::MapBegin(Message* message,
+                                 const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "MapBegin", "Field is not a map field.");
+  MapIterator iter(message, field);
+  GetRaw<MapFieldBase>(*message, field).MapBegin(&iter);
+  return iter;
+}
+
+MapIterator Reflection::MapEnd(Message* message,
+                               const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "MapEnd", "Field is not a map field.");
+  MapIterator iter(message, field);
+  GetRaw<MapFieldBase>(*message, field).MapEnd(&iter);
+  return iter;
+}
+
+int Reflection::MapSize(const Message& message,
+                        const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "MapSize", "Field is not a map field.");
+  return GetRaw<MapFieldBase>(message, field).size();
+}
+
+// -----------------------------------------------------------------------------
+
+const FieldDescriptor* Reflection::FindKnownExtensionByName(
+    const std::string& name) const {
+  if (!schema_.HasExtensionSet()) return nullptr;
+  return descriptor_pool_->FindExtensionByPrintableName(descriptor_, name);
+}
+
+const FieldDescriptor* Reflection::FindKnownExtensionByNumber(
+    int number) const {
+  if (!schema_.HasExtensionSet()) return nullptr;
+  return descriptor_pool_->FindExtensionByNumber(descriptor_, number);
+}
+
+bool Reflection::SupportsUnknownEnumValues() const {
+  return CreateUnknownEnumValues(descriptor_->file());
+}
+
+// ===================================================================
+// Some private helpers.
+
+// These simple template accessors obtain pointers (or references) to
+// the given field.
+
+template <class Type>
+const Type& Reflection::GetRawNonOneof(const Message& message,
+                                       const FieldDescriptor* field) const {
+  return GetConstRefAtOffset<Type>(message,
+                                   schema_.GetFieldOffsetNonOneof(field));
+}
+
+template <class Type>
+Type* Reflection::MutableRawNonOneof(Message* message,
+                                     const FieldDescriptor* field) const {
+  return GetPointerAtOffset<Type>(message,
+                                  schema_.GetFieldOffsetNonOneof(field));
+}
+
+template <typename Type>
+Type* Reflection::MutableRaw(Message* message,
+                             const FieldDescriptor* field) const {
+  return GetPointerAtOffset<Type>(message, schema_.GetFieldOffset(field));
+}
+
+const uint32_t* Reflection::GetHasBits(const Message& message) const {
+  GOOGLE_DCHECK(schema_.HasHasbits());
+  return &GetConstRefAtOffset<uint32_t>(message, schema_.HasBitsOffset());
+}
+
+uint32_t* Reflection::MutableHasBits(Message* message) const {
+  GOOGLE_DCHECK(schema_.HasHasbits());
+  return GetPointerAtOffset<uint32_t>(message, schema_.HasBitsOffset());
+}
+
+uint32_t* Reflection::MutableOneofCase(
+    Message* message, const OneofDescriptor* oneof_descriptor) const {
+  GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
+  return GetPointerAtOffset<uint32_t>(
+      message, schema_.GetOneofCaseOffset(oneof_descriptor));
+}
+
+const ExtensionSet& Reflection::GetExtensionSet(const Message& message) const {
+  return GetConstRefAtOffset<ExtensionSet>(message,
+                                           schema_.GetExtensionSetOffset());
+}
+
+ExtensionSet* Reflection::MutableExtensionSet(Message* message) const {
+  return GetPointerAtOffset<ExtensionSet>(message,
+                                          schema_.GetExtensionSetOffset());
+}
+
+const InternalMetadata& Reflection::GetInternalMetadata(
+    const Message& message) const {
+  return GetConstRefAtOffset<InternalMetadata>(message,
+                                               schema_.GetMetadataOffset());
+}
+
+InternalMetadata* Reflection::MutableInternalMetadata(Message* message) const {
+  return GetPointerAtOffset<InternalMetadata>(message,
+                                              schema_.GetMetadataOffset());
+}
+
+const uint32_t* Reflection::GetInlinedStringDonatedArray(
+    const Message& message) const {
+  GOOGLE_DCHECK(schema_.HasInlinedString());
+  return &GetConstRefAtOffset<uint32_t>(message,
+                                        schema_.InlinedStringDonatedOffset());
+}
+
+uint32_t* Reflection::MutableInlinedStringDonatedArray(Message* message) const {
+  GOOGLE_DCHECK(schema_.HasInlinedString());
+  return GetPointerAtOffset<uint32_t>(message,
+                                      schema_.InlinedStringDonatedOffset());
+}
+
+// Simple accessors for manipulating _inlined_string_donated_;
+bool Reflection::IsInlinedStringDonated(const Message& message,
+                                        const FieldDescriptor* field) const {
+  uint32_t index = schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  return IsIndexInHasBitSet(GetInlinedStringDonatedArray(message), index);
+}
+
+inline void SetInlinedStringDonated(uint32_t index, uint32_t* array) {
+  array[index / 32] |= (static_cast<uint32_t>(1) << (index % 32));
+}
+
+inline void ClearInlinedStringDonated(uint32_t index, uint32_t* array) {
+  array[index / 32] &= ~(static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::SwapInlinedStringDonated(Message* lhs, Message* rhs,
+                                          const FieldDescriptor* field) const {
+  Arena* lhs_arena = lhs->GetArenaForAllocation();
+  Arena* rhs_arena = rhs->GetArenaForAllocation();
+  // If arenas differ, inined string fields are swapped by copying values.
+  // Donation status should not be swapped.
+  if (lhs_arena != rhs_arena) {
+    return;
+  }
+  bool lhs_donated = IsInlinedStringDonated(*lhs, field);
+  bool rhs_donated = IsInlinedStringDonated(*rhs, field);
+  if (lhs_donated == rhs_donated) {
+    return;
+  }
+  // If one is undonated, both must have already registered ArenaDtor.
+  uint32_t* lhs_array = MutableInlinedStringDonatedArray(lhs);
+  uint32_t* rhs_array = MutableInlinedStringDonatedArray(rhs);
+  GOOGLE_CHECK_EQ(lhs_array[0] & 0x1u, 0u);
+  GOOGLE_CHECK_EQ(rhs_array[0] & 0x1u, 0u);
+  // Swap donation status bit.
+  uint32_t index = schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  if (rhs_donated) {
+    SetInlinedStringDonated(index, lhs_array);
+    ClearInlinedStringDonated(index, rhs_array);
+  } else {  // lhs_donated
+    ClearInlinedStringDonated(index, lhs_array);
+    SetInlinedStringDonated(index, rhs_array);
+  }
+}
+
+// Simple accessors for manipulating has_bits_.
+bool Reflection::HasBit(const Message& message,
+                        const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  if (schema_.HasBitIndex(field) != static_cast<uint32_t>(-1)) {
+    return IsIndexInHasBitSet(GetHasBits(message), schema_.HasBitIndex(field));
+  }
+
+  // Intentionally check here because HasBitIndex(field) != -1 means valid.
+  CheckInvalidAccess(schema_, field);
+
+  // proto3: no has-bits. All fields present except messages, which are
+  // present only if their message-field pointer is non-null.
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    return !schema_.IsDefaultInstance(message) &&
+           GetRaw<const Message*>(message, field) != nullptr;
+  } else {
+    // Non-message field (and non-oneof, since that was handled in HasField()
+    // before calling us), and singular (again, checked in HasField). So, this
+    // field must be a scalar.
+
+    // Scalar primitive (numeric or string/bytes) fields are present if
+    // their value is non-zero (numeric) or non-empty (string/bytes). N.B.:
+    // we must use this definition here, rather than the "scalar fields
+    // always present" in the proto3 docs, because MergeFrom() semantics
+    // require presence as "present on wire", and reflection-based merge
+    // (which uses HasField()) needs to be consistent with this.
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default: {
+            if (IsInlined(field)) {
+              return !GetField<InlinedStringField>(message, field)
+                          .GetNoArena()
+                          .empty();
+            }
+
+            return GetField<ArenaStringPtr>(message, field).Get().size() > 0;
+          }
+        }
+        return false;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return GetRaw<bool>(message, field) != false;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return GetRaw<int32_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return GetRaw<int64_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return GetRaw<uint32_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return GetRaw<uint64_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        static_assert(sizeof(uint32_t) == sizeof(float),
+                      "Code assumes uint32_t and float are the same size.");
+        return GetRaw<uint32_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        static_assert(sizeof(uint64_t) == sizeof(double),
+                      "Code assumes uint64_t and double are the same size.");
+        return GetRaw<uint64_t>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return GetRaw<int>(message, field) != 0;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        // handled above; avoid warning
+        break;
+    }
+    GOOGLE_LOG(FATAL) << "Reached impossible case in HasBit().";
+    return false;
+  }
+}
+
+void Reflection::SetBit(Message* message, const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  const uint32_t index = schema_.HasBitIndex(field);
+  if (index == static_cast<uint32_t>(-1)) return;
+  MutableHasBits(message)[index / 32] |=
+      (static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::ClearBit(Message* message,
+                          const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  const uint32_t index = schema_.HasBitIndex(field);
+  if (index == static_cast<uint32_t>(-1)) return;
+  MutableHasBits(message)[index / 32] &=
+      ~(static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::SwapBit(Message* message1, Message* message2,
+                         const FieldDescriptor* field) const {
+  GOOGLE_DCHECK(!field->options().weak());
+  if (!schema_.HasHasbits()) {
+    return;
+  }
+  bool temp_has_bit = HasBit(*message1, field);
+  if (HasBit(*message2, field)) {
+    SetBit(message1, field);
+  } else {
+    ClearBit(message1, field);
+  }
+  if (temp_has_bit) {
+    SetBit(message2, field);
+  } else {
+    ClearBit(message2, field);
+  }
+}
+
+bool Reflection::HasOneof(const Message& message,
+                          const OneofDescriptor* oneof_descriptor) const {
+  if (oneof_descriptor->is_synthetic()) {
+    return HasField(message, oneof_descriptor->field(0));
+  }
+  return (GetOneofCase(message, oneof_descriptor) > 0);
+}
+
+void Reflection::SetOneofCase(Message* message,
+                              const FieldDescriptor* field) const {
+  *MutableOneofCase(message, field->containing_oneof()) = field->number();
+}
+
+void Reflection::ClearOneofField(Message* message,
+                                 const FieldDescriptor* field) const {
+  if (HasOneofField(*message, field)) {
+    ClearOneof(message, field->containing_oneof());
+  }
+}
+
+void Reflection::ClearOneof(Message* message,
+                            const OneofDescriptor* oneof_descriptor) const {
+  if (oneof_descriptor->is_synthetic()) {
+    ClearField(message, oneof_descriptor->field(0));
+    return;
+  }
+  // TODO(jieluo): Consider to cache the unused object instead of deleting
+  // it. It will be much faster if an application switches a lot from
+  // a few oneof fields.  Time/space tradeoff
+  uint32_t oneof_case = GetOneofCase(*message, oneof_descriptor);
+  if (oneof_case > 0) {
+    const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
+    if (message->GetArenaForAllocation() == nullptr) {
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING: {
+              // Oneof string fields are never set as a default instance.
+              // We just need to pass some arbitrary default string to make it
+              // work. This allows us to not have the real default accessible
+              // from reflection.
+              MutableField<ArenaStringPtr>(message, field)->Destroy();
+              break;
+            }
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          delete *MutableRaw<Message*>(message, field);
+          break;
+        default:
+          break;
+      }
+    } else {
+    }
+
+    *MutableOneofCase(message, oneof_descriptor) = 0;
+  }
+}
+
+#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE)                                  \
+  template <>                                                              \
+  const RepeatedField<TYPE>& Reflection::GetRepeatedFieldInternal<TYPE>(   \
+      const Message& message, const FieldDescriptor* field) const {        \
+    return *static_cast<RepeatedField<TYPE>*>(MutableRawRepeatedField(     \
+        const_cast<Message*>(&message), field, CPPTYPE, CTYPE, nullptr));  \
+  }                                                                        \
+                                                                           \
+  template <>                                                              \
+  RepeatedField<TYPE>* Reflection::MutableRepeatedFieldInternal<TYPE>(     \
+      Message * message, const FieldDescriptor* field) const {             \
+    return static_cast<RepeatedField<TYPE>*>(                              \
+        MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, nullptr)); \
+  }
+
+HANDLE_TYPE(int32_t, FieldDescriptor::CPPTYPE_INT32, -1);
+HANDLE_TYPE(int64_t, FieldDescriptor::CPPTYPE_INT64, -1);
+HANDLE_TYPE(uint32_t, FieldDescriptor::CPPTYPE_UINT32, -1);
+HANDLE_TYPE(uint64_t, FieldDescriptor::CPPTYPE_UINT64, -1);
+HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1);
+HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1);
+HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
+
+
+#undef HANDLE_TYPE
+
+void* Reflection::MutableRawRepeatedString(Message* message,
+                                           const FieldDescriptor* field,
+                                           bool is_string) const {
+  (void)is_string;  // Parameter is used by Google-internal code.
+  return MutableRawRepeatedField(message, field,
+                                 FieldDescriptor::CPPTYPE_STRING,
+                                 FieldOptions::STRING, nullptr);
+}
+
+// Template implementations of basic accessors.  Inline because each
+// template instance is only called from one location.  These are
+// used for all types except messages.
+template <typename Type>
+const Type& Reflection::GetField(const Message& message,
+                                 const FieldDescriptor* field) const {
+  return GetRaw<Type>(message, field);
+}
+
+template <typename Type>
+void Reflection::SetField(Message* message, const FieldDescriptor* field,
+                          const Type& value) const {
+  bool real_oneof = schema_.InRealOneof(field);
+  if (real_oneof && !HasOneofField(*message, field)) {
+    ClearOneof(message, field->containing_oneof());
+  }
+  *MutableRaw<Type>(message, field) = value;
+  real_oneof ? SetOneofCase(message, field) : SetBit(message, field);
+}
+
+template <typename Type>
+Type* Reflection::MutableField(Message* message,
+                               const FieldDescriptor* field) const {
+  schema_.InRealOneof(field) ? SetOneofCase(message, field)
+                             : SetBit(message, field);
+  return MutableRaw<Type>(message, field);
+}
+
+template <typename Type>
+const Type& Reflection::GetRepeatedField(const Message& message,
+                                         const FieldDescriptor* field,
+                                         int index) const {
+  return GetRaw<RepeatedField<Type> >(message, field).Get(index);
+}
+
+template <typename Type>
+const Type& Reflection::GetRepeatedPtrField(const Message& message,
+                                            const FieldDescriptor* field,
+                                            int index) const {
+  return GetRaw<RepeatedPtrField<Type> >(message, field).Get(index);
+}
+
+template <typename Type>
+void Reflection::SetRepeatedField(Message* message,
+                                  const FieldDescriptor* field, int index,
+                                  Type value) const {
+  MutableRaw<RepeatedField<Type> >(message, field)->Set(index, value);
+}
+
+template <typename Type>
+Type* Reflection::MutableRepeatedField(Message* message,
+                                       const FieldDescriptor* field,
+                                       int index) const {
+  RepeatedPtrField<Type>* repeated =
+      MutableRaw<RepeatedPtrField<Type> >(message, field);
+  return repeated->Mutable(index);
+}
+
+template <typename Type>
+void Reflection::AddField(Message* message, const FieldDescriptor* field,
+                          const Type& value) const {
+  MutableRaw<RepeatedField<Type> >(message, field)->Add(value);
+}
+
+template <typename Type>
+Type* Reflection::AddField(Message* message,
+                           const FieldDescriptor* field) const {
+  RepeatedPtrField<Type>* repeated =
+      MutableRaw<RepeatedPtrField<Type> >(message, field);
+  return repeated->Add();
+}
+
+MessageFactory* Reflection::GetMessageFactory() const {
+  return message_factory_;
+}
+
+void* Reflection::RepeatedFieldData(Message* message,
+                                    const FieldDescriptor* field,
+                                    FieldDescriptor::CppType cpp_type,
+                                    const Descriptor* message_type) const {
+  GOOGLE_CHECK(field->is_repeated());
+  GOOGLE_CHECK(field->cpp_type() == cpp_type ||
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+         cpp_type == FieldDescriptor::CPPTYPE_INT32))
+      << "The type parameter T in RepeatedFieldRef<T> API doesn't match "
+      << "the actual field type (for enums T should be the generated enum "
+      << "type or int32_t).";
+  if (message_type != nullptr) {
+    GOOGLE_CHECK_EQ(message_type, field->message_type());
+  }
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->MutableRawRepeatedField(
+        field->number(), field->type(), field->is_packed(), field);
+  } else {
+    return MutableRawNonOneof<char>(message, field);
+  }
+}
+
+MapFieldBase* Reflection::MutableMapData(Message* message,
+                                         const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "GetMapData",
+              "Field is not a map field.");
+  return MutableRaw<MapFieldBase>(message, field);
+}
+
+const MapFieldBase* Reflection::GetMapData(const Message& message,
+                                           const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field), "GetMapData",
+              "Field is not a map field.");
+  return &(GetRaw<MapFieldBase>(message, field));
+}
+
+namespace {
+
+// Helper function to transform migration schema into reflection schema.
+ReflectionSchema MigrationToReflectionSchema(
+    const Message* const* default_instance, const uint32_t* offsets,
+    MigrationSchema migration_schema) {
+  ReflectionSchema result;
+  result.default_instance_ = *default_instance;
+  // First 7 offsets are offsets to the special fields. The following offsets
+  // are the proto fields.
+  result.offsets_ = offsets + migration_schema.offsets_index + 6;
+  result.has_bit_indices_ = offsets + migration_schema.has_bit_indices_index;
+  result.has_bits_offset_ = offsets[migration_schema.offsets_index + 0];
+  result.metadata_offset_ = offsets[migration_schema.offsets_index + 1];
+  result.extensions_offset_ = offsets[migration_schema.offsets_index + 2];
+  result.oneof_case_offset_ = offsets[migration_schema.offsets_index + 3];
+  result.object_size_ = migration_schema.object_size;
+  result.weak_field_map_offset_ = offsets[migration_schema.offsets_index + 4];
+  result.inlined_string_donated_offset_ =
+      offsets[migration_schema.offsets_index + 5];
+  result.inlined_string_indices_ =
+      offsets + migration_schema.inlined_string_indices_index;
+  return result;
+}
+
+}  // namespace
+
+class AssignDescriptorsHelper {
+ public:
+  AssignDescriptorsHelper(MessageFactory* factory,
+                          Metadata* file_level_metadata,
+                          const EnumDescriptor** file_level_enum_descriptors,
+                          const MigrationSchema* schemas,
+                          const Message* const* default_instance_data,
+                          const uint32_t* offsets)
+      : factory_(factory),
+        file_level_metadata_(file_level_metadata),
+        file_level_enum_descriptors_(file_level_enum_descriptors),
+        schemas_(schemas),
+        default_instance_data_(default_instance_data),
+        offsets_(offsets) {}
+
+  void AssignMessageDescriptor(const Descriptor* descriptor) {
+    for (int i = 0; i < descriptor->nested_type_count(); i++) {
+      AssignMessageDescriptor(descriptor->nested_type(i));
+    }
+
+    file_level_metadata_->descriptor = descriptor;
+
+    file_level_metadata_->reflection =
+        new Reflection(descriptor,
+                       MigrationToReflectionSchema(default_instance_data_,
+                                                   offsets_, *schemas_),
+                       DescriptorPool::internal_generated_pool(), factory_);
+    for (int i = 0; i < descriptor->enum_type_count(); i++) {
+      AssignEnumDescriptor(descriptor->enum_type(i));
+    }
+    schemas_++;
+    default_instance_data_++;
+    file_level_metadata_++;
+  }
+
+  void AssignEnumDescriptor(const EnumDescriptor* descriptor) {
+    *file_level_enum_descriptors_ = descriptor;
+    file_level_enum_descriptors_++;
+  }
+
+  const Metadata* GetCurrentMetadataPtr() const { return file_level_metadata_; }
+
+ private:
+  MessageFactory* factory_;
+  Metadata* file_level_metadata_;
+  const EnumDescriptor** file_level_enum_descriptors_;
+  const MigrationSchema* schemas_;
+  const Message* const* default_instance_data_;
+  const uint32_t* offsets_;
+};
+
+namespace {
+
+// We have the routines that assign descriptors and build reflection
+// automatically delete the allocated reflection. MetadataOwner owns
+// all the allocated reflection instances.
+struct MetadataOwner {
+  ~MetadataOwner() {
+    for (auto range : metadata_arrays_) {
+      for (const Metadata* m = range.first; m < range.second; m++) {
+        delete m->reflection;
+      }
+    }
+  }
+
+  void AddArray(const Metadata* begin, const Metadata* end) {
+    mu_.Lock();
+    metadata_arrays_.push_back(std::make_pair(begin, end));
+    mu_.Unlock();
+  }
+
+  static MetadataOwner* Instance() {
+    static MetadataOwner* res = OnShutdownDelete(new MetadataOwner);
+    return res;
+  }
+
+ private:
+  MetadataOwner() = default;  // private because singleton
+
+  WrappedMutex mu_;
+  std::vector<std::pair<const Metadata*, const Metadata*> > metadata_arrays_;
+};
+
+void AddDescriptors(const DescriptorTable* table);
+
+void AssignDescriptorsImpl(const DescriptorTable* table, bool eager) {
+  // Ensure the file descriptor is added to the pool.
+  {
+    // This only happens once per proto file. So a global mutex to serialize
+    // calls to AddDescriptors.
+    static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
+    mu.Lock();
+    AddDescriptors(table);
+    mu.Unlock();
+  }
+  if (eager) {
+    // Normally we do not want to eagerly build descriptors of our deps.
+    // However if this proto is optimized for code size (ie using reflection)
+    // and it has a message extending a custom option of a descriptor with that
+    // message being optimized for code size as well. Building the descriptors
+    // in this file requires parsing the serialized file descriptor, which now
+    // requires parsing the message extension, which potentially requires
+    // building the descriptor of the message extending one of the options.
+    // However we are already updating descriptor pool under a lock. To prevent
+    // this the compiler statically looks for this case and we just make sure we
+    // first build the descriptors of all our dependencies, preventing the
+    // deadlock.
+    int num_deps = table->num_deps;
+    for (int i = 0; i < num_deps; i++) {
+      // In case of weak fields deps[i] could be null.
+      if (table->deps[i]) AssignDescriptors(table->deps[i], true);
+    }
+  }
+
+  // Fill the arrays with pointers to descriptors and reflection classes.
+  const FileDescriptor* file =
+      DescriptorPool::internal_generated_pool()->FindFileByName(
+          table->filename);
+  GOOGLE_CHECK(file != nullptr);
+
+  MessageFactory* factory = MessageFactory::generated_factory();
+
+  AssignDescriptorsHelper helper(
+      factory, table->file_level_metadata, table->file_level_enum_descriptors,
+      table->schemas, table->default_instances, table->offsets);
+
+  for (int i = 0; i < file->message_type_count(); i++) {
+    helper.AssignMessageDescriptor(file->message_type(i));
+  }
+
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    helper.AssignEnumDescriptor(file->enum_type(i));
+  }
+  if (file->options().cc_generic_services()) {
+    for (int i = 0; i < file->service_count(); i++) {
+      table->file_level_service_descriptors[i] = file->service(i);
+    }
+  }
+  MetadataOwner::Instance()->AddArray(table->file_level_metadata,
+                                      helper.GetCurrentMetadataPtr());
+}
+
+void AddDescriptorsImpl(const DescriptorTable* table) {
+  // Reflection refers to the default fields so make sure they are initialized.
+  internal::InitProtobufDefaults();
+
+  // Ensure all dependent descriptors are registered to the generated descriptor
+  // pool and message factory.
+  int num_deps = table->num_deps;
+  for (int i = 0; i < num_deps; i++) {
+    // In case of weak fields deps[i] could be null.
+    if (table->deps[i]) AddDescriptors(table->deps[i]);
+  }
+
+  // Register the descriptor of this file.
+  DescriptorPool::InternalAddGeneratedFile(table->descriptor, table->size);
+  MessageFactory::InternalRegisterGeneratedFile(table);
+}
+
+void AddDescriptors(const DescriptorTable* table) {
+  // AddDescriptors is not thread safe. Callers need to ensure calls are
+  // properly serialized. This function is only called pre-main by global
+  // descriptors and we can assume single threaded access or it's called
+  // by AssignDescriptorImpl which uses a mutex to sequence calls.
+  if (table->is_initialized) return;
+  table->is_initialized = true;
+  AddDescriptorsImpl(table);
+}
+
+}  // namespace
+
+// Separate function because it needs to be a friend of
+// Reflection
+void RegisterAllTypesInternal(const Metadata* file_level_metadata, int size) {
+  for (int i = 0; i < size; i++) {
+    const Reflection* reflection = file_level_metadata[i].reflection;
+    MessageFactory::InternalRegisterGeneratedMessage(
+        file_level_metadata[i].descriptor,
+        reflection->schema_.default_instance_);
+  }
+}
+
+namespace internal {
+
+Metadata AssignDescriptors(const DescriptorTable* (*table)(),
+                           internal::once_flag* once,
+                           const Metadata& metadata) {
+  call_once(*once, [=] {
+    auto* t = table();
+    AssignDescriptorsImpl(t, t->is_eager);
+  });
+
+  return metadata;
+}
+
+void AssignDescriptors(const DescriptorTable* table, bool eager) {
+  if (!eager) eager = table->is_eager;
+  call_once(*table->once, AssignDescriptorsImpl, table, eager);
+}
+
+AddDescriptorsRunner::AddDescriptorsRunner(const DescriptorTable* table) {
+  AddDescriptors(table);
+}
+
+void RegisterFileLevelMetadata(const DescriptorTable* table) {
+  AssignDescriptors(table);
+  RegisterAllTypesInternal(table->file_level_metadata, table->num_messages);
+}
+
+void UnknownFieldSetSerializer(const uint8_t* base, uint32_t offset,
+                               uint32_t /*tag*/, uint32_t /*has_offset*/,
+                               io::CodedOutputStream* output) {
+  const void* ptr = base + offset;
+  const InternalMetadata* metadata = static_cast<const InternalMetadata*>(ptr);
+  if (metadata->have_unknown_fields()) {
+    metadata->unknown_fields<UnknownFieldSet>(UnknownFieldSet::default_instance)
+        .SerializeToCodedStream(output);
+  }
+}
+
+bool IsDescendant(Message& root, const Message& message) {
+  const Reflection* reflection = root.GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFieldsOmitStripped(root, &fields);
+
+  for (const auto* field : fields) {
+    // Skip non-message fields.
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    // Optional messages.
+    if (!field->is_repeated()) {
+      Message* sub_message = reflection->MutableMessage(&root, field);
+      if (sub_message == &message || IsDescendant(*sub_message, message)) {
+        return true;
+      }
+      continue;
+    }
+
+    // Repeated messages.
+    if (!IsMapFieldInApi(field)) {
+      int count = reflection->FieldSize(root, field);
+      for (int i = 0; i < count; i++) {
+        Message* sub_message =
+            reflection->MutableRepeatedMessage(&root, field, i);
+        if (sub_message == &message || IsDescendant(*sub_message, message)) {
+          return true;
+        }
+      }
+      continue;
+    }
+
+    // Map field: if accessed as repeated fields, messages are *copied* and
+    // matching pointer won't work. Must directly access map.
+    constexpr int kValIdx = 1;
+    const FieldDescriptor* val_field = field->message_type()->field(kValIdx);
+    // Skip map fields whose value type is not message.
+    if (val_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    MapIterator end = reflection->MapEnd(&root, field);
+    for (auto iter = reflection->MapBegin(&root, field); iter != end; ++iter) {
+      Message* sub_message = iter.MutableValueRef()->MutableMessageValue();
+      if (sub_message == &message || IsDescendant(*sub_message, message)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_tctable_full.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_tctable_full.cpp
new file mode 100644
index 0000000..b77bb8d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_tctable_full.cpp
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cstdint>
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/unknown_field_set.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+const char* TcParser::GenericFallback(PROTOBUF_TC_PARAM_DECL) {
+  return GenericFallbackImpl<Message, UnknownFieldSet>(PROTOBUF_TC_PARAM_PASS);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_tctable_lite.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_tctable_lite.cpp
new file mode 100644
index 0000000..23557a6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_tctable_lite.cpp
@@ -0,0 +1,1863 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cstdint>
+#include <numeric>
+
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_decl.h>
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/inlined_string_field.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+using FieldEntry = TcParseTableBase::FieldEntry;
+
+//////////////////////////////////////////////////////////////////////////////
+// Template instantiations:
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef NDEBUG
+template void AlignFail<4>(uintptr_t);
+template void AlignFail<8>(uintptr_t);
+#endif
+
+const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) {
+  return GenericFallbackImpl<MessageLite, std::string>(PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Core fast parsing implementation:
+//////////////////////////////////////////////////////////////////////////////
+
+class TcParser::ScopedArenaSwap final {
+ public:
+  ScopedArenaSwap(MessageLite* msg, ParseContext* ctx)
+      : ctx_(ctx), saved_(ctx->data().arena) {
+    ctx_->data().arena = msg->GetArenaForAllocation();
+  }
+  ScopedArenaSwap(const ScopedArenaSwap&) = delete;
+  ~ScopedArenaSwap() { ctx_->data().arena = saved_; }
+
+ private:
+  ParseContext* const ctx_;
+  Arena* const saved_;
+};
+
+PROTOBUF_NOINLINE const char* TcParser::ParseLoop(
+    MessageLite* msg, const char* ptr, ParseContext* ctx,
+    const TcParseTableBase* table) {
+  ScopedArenaSwap saved(msg, ctx);
+  while (!ctx->Done(&ptr)) {
+    // Unconditionally read has bits, even if we don't have has bits.
+    // has_bits_offset will be 0 and we will just read something valid.
+    uint64_t hasbits = ReadAt<uint32_t>(msg, table->has_bits_offset);
+    ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
+    if (ptr == nullptr) break;
+    if (ctx->LastTag() != 1) break;  // Ended on terminating tag
+  }
+  return ptr;
+}
+
+  // Dispatch to the designated parse function
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
+    PROTOBUF_TC_PARAM_DECL) {
+  const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
+  const size_t idx = coded_tag & table->fast_idx_mask;
+  PROTOBUF_ASSUME((idx & 7) == 0);
+  auto* fast_entry = table->fast_entry(idx >> 3);
+  data = fast_entry->bits;
+  data.data ^= coded_tag;
+  PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
+}
+
+// We can only safely call from field to next field if the call is optimized
+// to a proper tail call. Otherwise we blow through stack. Clang and gcc
+// reliably do this optimization in opt mode, but do not perform this in debug
+// mode. Luckily the structure of the algorithm is such that it's always
+// possible to just return and use the enclosing parse loop as a trampoline.
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
+    PROTOBUF_TC_PARAM_DECL) {
+  constexpr bool always_return = !PROTOBUF_TAILCALL;
+  if (always_return || !ctx->DataAvailable(ptr)) {
+    PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  }
+  PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)data;
+  (void)ctx;
+  SyncHasbits(msg, hasbits, table);
+  return ptr;
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)data;
+  (void)ctx;
+  (void)ptr;
+  SyncHasbits(msg, hasbits, table);
+  return nullptr;
+}
+
+// On the fast path, a (matching) 1-byte tag already has the decoded value.
+static uint32_t FastDecodeTag(uint8_t coded_tag) {
+  return coded_tag;
+}
+
+// On the fast path, a (matching) 2-byte tag always needs to be decoded.
+static uint32_t FastDecodeTag(uint16_t coded_tag) {
+  uint32_t result = coded_tag;
+  result += static_cast<int8_t>(coded_tag);
+  return result >> 1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Core mini parsing implementation:
+//////////////////////////////////////////////////////////////////////////////
+
+// Field lookup table layout:
+//
+// Because it consists of a series of variable-length segments, the lookuup
+// table is organized within an array of uint16_t, and each element is either
+// a uint16_t or a uint32_t stored little-endian as a pair of uint16_t.
+//
+// Its fundamental building block maps 16 contiguously ascending field numbers
+// to their locations within the field entry table:
+
+struct SkipEntry16 {
+  uint16_t skipmap;
+  uint16_t field_entry_offset;
+};
+
+// The skipmap is a bitfield of which of those field numbers do NOT have a
+// field entry.  The lowest bit of the skipmap corresponds to the lowest of
+// the 16 field numbers, so if a proto had only fields 1, 2, 3, and 7, the
+// skipmap would contain 0b11111111'10111000.
+//
+// The field lookup table begins with a single 32-bit skipmap that maps the
+// field numbers 1 through 32.  This is because the majority of proto
+// messages only contain fields numbered 1 to 32.
+//
+// The rest of the lookup table is a repeated series of
+// { 32-bit field #,  #SkipEntry16s,  {SkipEntry16...} }
+// That is, the next thing is a pair of uint16_t that form the next
+// lowest field number that the lookup table handles.  If this number is -1,
+// that is the end of the table.  Then there is a uint16_t that is
+// the number of contiguous SkipEntry16 entries that follow, and then of
+// course the SkipEntry16s themselves.
+
+// Originally developed and tested at https://godbolt.org/z/vbc7enYcf
+
+// Returns the address of the field for `tag` in the table's field entries.
+// Returns nullptr if the field was not found.
+const TcParseTableBase::FieldEntry* TcParser::FindFieldEntry(
+    const TcParseTableBase* table, uint32_t field_num) {
+  const FieldEntry* const field_entries = table->field_entries_begin();
+
+  uint32_t fstart = 1;
+  uint32_t adj_fnum = field_num - fstart;
+
+  if (PROTOBUF_PREDICT_TRUE(adj_fnum < 32)) {
+    uint32_t skipmap = table->skipmap32;
+    uint32_t skipbit = 1 << adj_fnum;
+    if (PROTOBUF_PREDICT_FALSE(skipmap & skipbit)) return nullptr;
+    skipmap &= skipbit - 1;
+#if (__GNUC__ || __clang__) && __POPCNT__
+    // Note: here and below, skipmap typically has very few set bits
+    // (31 in the worst case, but usually zero) so a loop isn't that
+    // bad, and a compiler-generated popcount is typically only
+    // worthwhile if the processor itself has hardware popcount support.
+    adj_fnum -= __builtin_popcount(skipmap);
+#else
+    while (skipmap) {
+      --adj_fnum;
+      skipmap &= skipmap - 1;
+    }
+#endif
+    auto* entry = field_entries + adj_fnum;
+    PROTOBUF_ASSUME(entry != nullptr);
+    return entry;
+  }
+  const uint16_t* lookup_table = table->field_lookup_begin();
+  for (;;) {
+#ifdef PROTOBUF_LITTLE_ENDIAN
+    memcpy(&fstart, lookup_table, sizeof(fstart));
+#else
+    fstart = lookup_table[0] | (lookup_table[1] << 16);
+#endif
+    lookup_table += sizeof(fstart) / sizeof(*lookup_table);
+    uint32_t num_skip_entries = *lookup_table++;
+    if (field_num < fstart) return nullptr;
+    adj_fnum = field_num - fstart;
+    uint32_t skip_num = adj_fnum / 16;
+    if (PROTOBUF_PREDICT_TRUE(skip_num < num_skip_entries)) {
+      // for each group of 16 fields we have:
+      // a bitmap of 16 bits
+      // a 16-bit field-entry offset for the first of them.
+      auto* skip_data = lookup_table + (adj_fnum / 16) * (sizeof(SkipEntry16) /
+                                                          sizeof(uint16_t));
+      SkipEntry16 se = {skip_data[0], skip_data[1]};
+      adj_fnum &= 15;
+      uint32_t skipmap = se.skipmap;
+      uint16_t skipbit = 1 << adj_fnum;
+      if (PROTOBUF_PREDICT_FALSE(skipmap & skipbit)) return nullptr;
+      skipmap &= skipbit - 1;
+      adj_fnum += se.field_entry_offset;
+#if (__GNUC__ || __clang__) && __POPCNT__
+      adj_fnum -= __builtin_popcount(skipmap);
+#else
+      while (skipmap) {
+        --adj_fnum;
+        skipmap &= skipmap - 1;
+      }
+#endif
+      auto* entry = field_entries + adj_fnum;
+      PROTOBUF_ASSUME(entry != nullptr);
+      return entry;
+    }
+    lookup_table +=
+        num_skip_entries * (sizeof(SkipEntry16) / sizeof(*lookup_table));
+  }
+}
+
+// Field names are stored in a format of:
+//
+// 1) A table of name sizes, one byte each, from 1 to 255 per name.
+//    `entries` is the size of this first table.
+// 1a) padding bytes, so the table of name sizes is a multiple of
+//     eight bytes in length. They are zero.
+//
+// 2) All the names, concatenated, with neither separation nor termination.
+//
+// This is designed to be compact but not particularly fast to retrieve.
+// In particular, it takes O(n) to retrieve the name of the n'th field,
+// which is usually fine because most protos have fewer than 10 fields.
+static StringPiece FindName(const char* name_data, size_t entries,
+                                  size_t index) {
+  // The compiler unrolls these... if this isn't fast enough,
+  // there's an AVX version at https://godbolt.org/z/eojrjqzfr
+  // ARM-compatible version at https://godbolt.org/z/n5YT5Ee85
+
+  // The field name sizes are padded up to a multiple of 8, so we
+  // must pad them here.
+  size_t num_sizes = (entries + 7) & -8;
+  auto* uint8s = reinterpret_cast<const uint8_t*>(name_data);
+  size_t pos = std::accumulate(uint8s, uint8s + index, num_sizes);
+  size_t size = name_data[index];
+  auto* start = &name_data[pos];
+  return {start, size};
+}
+
+StringPiece TcParser::MessageName(const TcParseTableBase* table) {
+  return FindName(table->name_data(), table->num_field_entries + 1, 0);
+}
+
+StringPiece TcParser::FieldName(const TcParseTableBase* table,
+                                      const FieldEntry* field_entry) {
+  const FieldEntry* const field_entries = table->field_entries_begin();
+  auto field_index = static_cast<size_t>(field_entry - field_entries);
+  return FindName(table->name_data(), table->num_field_entries + 1,
+                  field_index + 1);
+}
+
+const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
+  uint32_t tag;
+  ptr = ReadTagInlined(ptr, &tag);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+
+  auto* entry = FindFieldEntry(table, tag >> 3);
+  if (entry == nullptr) {
+    data.data = tag;
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // The handler may need the tag and the entry to resolve fallback logic. Both
+  // of these are 32 bits, so pack them into (the 64-bit) `data`. Since we can't
+  // pack the entry pointer itself, just pack its offset from `table`.
+  uint64_t entry_offset = reinterpret_cast<const char*>(entry) -
+                          reinterpret_cast<const char*>(table);
+  data.data = entry_offset << 32 | tag;
+
+  using field_layout::FieldKind;
+  auto field_type = entry->type_card & FieldKind::kFkMask;
+  switch (field_type) {
+    case FieldKind::kFkNone:
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkVarint:
+      PROTOBUF_MUSTTAIL return MpVarint(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkPackedVarint:
+      PROTOBUF_MUSTTAIL return MpPackedVarint(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkFixed:
+      PROTOBUF_MUSTTAIL return MpFixed(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkPackedFixed:
+      PROTOBUF_MUSTTAIL return MpPackedFixed(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkString:
+      PROTOBUF_MUSTTAIL return MpString(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkMessage:
+      PROTOBUF_MUSTTAIL return MpMessage(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkMap:
+      PROTOBUF_MUSTTAIL return MpMap(PROTOBUF_TC_PARAM_PASS);
+    default:
+      return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+}
+
+namespace {
+
+// Offset returns the address `offset` bytes after `base`.
+inline void* Offset(void* base, uint32_t offset) {
+  return static_cast<uint8_t*>(base) + offset;
+}
+
+// InvertPacked changes tag bits from the given wire type to length
+// delimited. This is the difference expected between packed and non-packed
+// repeated fields.
+template <WireFormatLite::WireType Wt>
+inline PROTOBUF_ALWAYS_INLINE void InvertPacked(TcFieldData& data) {
+  data.data ^= Wt ^ WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+// Message fields
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename TagType, bool group_coding>
+inline PROTOBUF_ALWAYS_INLINE
+const char* TcParser::SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto saved_tag = UnalignedLoad<TagType>(ptr);
+  ptr += sizeof(TagType);
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  SyncHasbits(msg, hasbits, table);
+  auto& field = RefAt<MessageLite*>(msg, data.offset());
+  if (field == nullptr) {
+    const MessageLite* default_instance =
+        table->field_aux(data.aux_idx())->message_default;
+    field = default_instance->New(ctx->data().arena);
+  }
+  if (group_coding) {
+    return ctx->ParseGroup(field, ptr, FastDecodeTag(saved_tag));
+  }
+  return ctx->ParseMessage(field, ptr);
+}
+
+const char* TcParser::FastMS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint8_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastMS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint16_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, bool group_coding>
+inline PROTOBUF_ALWAYS_INLINE
+const char* TcParser::RepeatedParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto saved_tag = UnalignedLoad<TagType>(ptr);
+  ptr += sizeof(TagType);
+  SyncHasbits(msg, hasbits, table);
+  const MessageLite* default_instance =
+      table->field_aux(data.aux_idx())->message_default;
+  auto& field = RefAt<RepeatedPtrFieldBase>(msg, data.offset());
+  MessageLite* submsg =
+      field.Add<GenericTypeHandler<MessageLite>>(default_instance);
+  if (group_coding) {
+    return ctx->ParseGroup(submsg, ptr, FastDecodeTag(saved_tag));
+  }
+  return ctx->ParseMessage(submsg, ptr);
+}
+
+const char* TcParser::FastMR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint8_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastMR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint16_t, false>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastGR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Fixed fields
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename LayoutType, typename TagType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularFixed(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  ptr += sizeof(TagType);  // Consume tag
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  RefAt<LayoutType>(msg, data.offset()) = UnalignedLoad<LayoutType>(ptr);
+  ptr += sizeof(LayoutType);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastF32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename LayoutType, typename TagType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedFixed(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    // Check if the field can be parsed as packed repeated:
+    constexpr WireFormatLite::WireType fallback_wt =
+        sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
+                                : WireFormatLite::WIRETYPE_FIXED64;
+    InvertPacked<fallback_wt>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
+  int idx = field.size();
+  auto elem = field.Add();
+  int space = field.Capacity() - idx;
+  idx = 0;
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  do {
+    ptr += sizeof(TagType);
+    elem[idx++] = UnalignedLoad<LayoutType>(ptr);
+    ptr += sizeof(LayoutType);
+    if (idx >= space) break;
+    if (!ctx->DataAvailable(ptr)) break;
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  field.AddNAlreadyReserved(idx - 1);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastF32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// Note: some versions of GCC will fail with error "function not inlinable" if
+// corecursive functions are both marked with PROTOBUF_ALWAYS_INLINE (Clang
+// accepts this). We can still apply the attribute to one of the two functions,
+// just not both (so we do mark the Repeated variant as always inlined). This
+// also applies to PackedVarint, below.
+template <typename LayoutType, typename TagType>
+const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    // Try parsing as non-packed repeated:
+    constexpr WireFormatLite::WireType fallback_wt =
+        sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
+        : WireFormatLite::WIRETYPE_FIXED64;
+    InvertPacked<fallback_wt>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  ptr += sizeof(TagType);
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+  auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
+  int size = ReadSize(&ptr);
+  // TODO(dlj): add a tailcalling variant of ReadPackedFixed.
+  return ctx->ReadPackedFixed(ptr, size,
+                              static_cast<RepeatedField<LayoutType>*>(&field));
+}
+
+const char* TcParser::FastF32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Varint fields
+//////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE uint64_t
+shift_left_fill_with_ones(uint64_t byte, uint64_t ones) {
+  return (byte << (n * 7)) | (ones >> (64 - (n * 7)));
+}
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
+// put the new value in res.  Return whether the result was negative.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
+    uint64_t byte, uint64_t ones, int64_t& res) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+  // For the first two rounds (ptr[1] and ptr[2]), micro benchmarks show a
+  // substantial improvement from capturing the sign from the condition code
+  // register on x86-64.
+  bool sign_bit;
+  asm("shldq %3, %2, %1"
+      : "=@ccs"(sign_bit), "+r"(byte)
+      : "r"(ones), "i"(n * 7));
+  res = byte;
+  return sign_bit;
+#else
+  // Generic fallback:
+  res = (byte << (n * 7)) | (ones >> (64 - (n * 7)));
+  return static_cast<int64_t>(res) < 0;
+#endif
+}
+
+inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, uint64_t>
+Parse64FallbackPair(const char* p, int64_t res1) {
+  auto ptr = reinterpret_cast<const int8_t*>(p);
+
+  // The algorithm relies on sign extension for each byte to set all high bits
+  // when the varint continues. It also relies on asserting all of the lower
+  // bits for each successive byte read. This allows the result to be aggregated
+  // using a bitwise AND. For example:
+  //
+  //          8       1          64     57 ... 24     17  16      9  8       1
+  // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111  1111 1111  1aaa aaaa
+  // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111  11bb bbbb  b111 1111
+  // ptr[2] = 1ccc cccc ; res3 = 0000 0000 ... 000c cccc  cc11 1111  1111 1111
+  //                             ---------------------------------------------
+  //        res1 & res2 & res3 = 0000 0000 ... 000c cccc  ccbb bbbb  baaa aaaa
+  //
+  // On x86-64, a shld from a single register filled with enough 1s in the high
+  // bits can accomplish all this in one instruction. It so happens that res1
+  // has 57 high bits of ones, which is enough for the largest shift done.
+  GOOGLE_DCHECK_EQ(res1 >> 7, -1);
+  uint64_t ones = res1;  // save the high 1 bits from res1 (input to SHLD)
+  int64_t res2, res3;    // accumulated result chunks
+
+  if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
+    goto done2;
+  if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
+    goto done3;
+
+  // For the remainder of the chunks, check the sign of the AND result.
+  res1 &= shift_left_fill_with_ones<3>(ptr[3], ones);
+  if (res1 >= 0) goto done4;
+  res2 &= shift_left_fill_with_ones<4>(ptr[4], ones);
+  if (res2 >= 0) goto done5;
+  res3 &= shift_left_fill_with_ones<5>(ptr[5], ones);
+  if (res3 >= 0) goto done6;
+  res1 &= shift_left_fill_with_ones<6>(ptr[6], ones);
+  if (res1 >= 0) goto done7;
+  res2 &= shift_left_fill_with_ones<7>(ptr[7], ones);
+  if (res2 >= 0) goto done8;
+  res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
+  if (res3 >= 0) goto done9;
+
+  // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
+  // case, the continuation bit of ptr[8] already set the top bit of res3
+  // correctly, so all we have to do is check that the expected case is true.
+  if (PROTOBUF_PREDICT_TRUE(ptr[9] == 1)) goto done10;
+
+  // A value of 0, however, represents an over-serialized varint. This case
+  // should not happen, but if does (say, due to a nonconforming serializer),
+  // deassert the continuation bit that came from ptr[8].
+  if (ptr[9] == 0) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+    // Use a small instruction since this is an uncommon code path.
+    asm("btcq $63,%0" : "+r"(res3));
+#else
+    res3 ^= static_cast<uint64_t>(1) << 63;
+#endif
+    goto done10;
+  }
+
+  // If the 10th byte/ptr[9] itself has any other value, then it is too big to
+  // fit in 64 bits. If the continue bit is set, it is an unterminated varint.
+  return {nullptr, 0};
+
+done2:
+  return {p + 2, res1 & res2};
+done3:
+  return {p + 3, res1 & res2 & res3};
+done4:
+  return {p + 4, res1 & res2 & res3};
+done5:
+  return {p + 5, res1 & res2 & res3};
+done6:
+  return {p + 6, res1 & res2 & res3};
+done7:
+  return {p + 7, res1 & res2 & res3};
+done8:
+  return {p + 8, res1 & res2 & res3};
+done9:
+  return {p + 9, res1 & res2 & res3};
+done10:
+  return {p + 10, res1 & res2 & res3};
+}
+
+inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
+                                                      uint64_t* value) {
+  int64_t byte = static_cast<int8_t>(*p);
+  if (PROTOBUF_PREDICT_TRUE(byte >= 0)) {
+    *value = byte;
+    return p + 1;
+  } else {
+    auto tmp = Parse64FallbackPair(p, byte);
+    if (PROTOBUF_PREDICT_TRUE(tmp.first)) *value = tmp.second;
+    return tmp.first;
+  }
+}
+
+template <typename FieldType, bool zigzag = false>
+inline FieldType ZigZagDecodeHelper(uint64_t value) {
+  return static_cast<FieldType>(value);
+}
+
+template <>
+inline int32_t ZigZagDecodeHelper<int32_t, true>(uint64_t value) {
+  return WireFormatLite::ZigZagDecode32(value);
+}
+
+template <>
+inline int64_t ZigZagDecodeHelper<int64_t, true>(uint64_t value) {
+  return WireFormatLite::ZigZagDecode64(value);
+}
+
+bool EnumIsValidAux(int32_t val, uint16_t xform_val,
+                    TcParseTableBase::FieldAux aux) {
+  if (xform_val == field_layout::kTvRange) {
+    auto lo = aux.enum_range.start;
+    return lo <= val && val < (lo + aux.enum_range.length);
+  }
+  return aux.enum_validator(val);
+}
+
+}  // namespace
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularVarint(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  ptr += sizeof(TagType);  // Consume tag
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+  // clang isn't smart enough to be able to only conditionally save
+  // registers to the stack, so we turn the integer-greater-than-128
+  // case into a separate routine.
+  if (PROTOBUF_PREDICT_FALSE(static_cast<int8_t>(*ptr) < 0)) {
+    PROTOBUF_MUSTTAIL return SingularVarBigint<FieldType, TagType, zigzag>(
+        PROTOBUF_TC_PARAM_PASS);
+  }
+
+  RefAt<FieldType>(msg, data.offset()) =
+      ZigZagDecodeHelper<FieldType, zigzag>(static_cast<uint8_t>(*ptr++));
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint(
+    PROTOBUF_TC_PARAM_DECL) {
+  // For some reason clang wants to save 5 registers to the stack here,
+  // but we only need four for this code, so save the data we don't need
+  // to the stack.  Happily, saving them this way uses regular store
+  // instructions rather than PUSH/POP, which saves time at the cost of greater
+  // code size, but for this heavily-used piece of code, that's fine.
+  struct Spill {
+    uint64_t field_data;
+    ::google::protobuf::MessageLite* msg;
+    const ::google::protobuf::internal::TcParseTableBase* table;
+    uint64_t hasbits;
+  };
+  volatile Spill spill = {data.data, msg, table, hasbits};
+
+  uint64_t tmp = 0;
+  PROTOBUF_ASSUME(static_cast<int8_t>(*ptr) < 0);
+  ptr = ParseVarint(ptr, &tmp);
+
+  data.data = spill.field_data;
+  msg = spill.msg;
+  table = spill.table;
+  hasbits = spill.hasbits;
+
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  RefAt<FieldType>(msg, data.offset()) =
+      ZigZagDecodeHelper<FieldType, zigzag>(tmp);
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<bool, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedVarint(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    // Try parsing as non-packed repeated:
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  do {
+    ptr += sizeof(TagType);
+    uint64_t tmp = 0;
+    ptr = ParseVarint(ptr, &tmp);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    field.Add(ZigZagDecodeHelper<FieldType, zigzag>(tmp));
+    if (!ctx->DataAvailable(ptr)) {
+      break;
+    }
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastV8R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<bool, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<bool, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// See comment on PackedFixed for why this is not PROTOBUF_ALWAYS_INLINE.
+template <typename FieldType, typename TagType, bool zigzag>
+const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  ptr += sizeof(TagType);
+  // Since ctx->ReadPackedVarint does not use TailCall or Return, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+  auto* field = &RefAt<RepeatedField<FieldType>>(msg, data.offset());
+  return ctx->ReadPackedVarint(ptr, [field](uint64_t varint) {
+    FieldType val;
+    if (zigzag) {
+      if (sizeof(FieldType) == 8) {
+        val = WireFormatLite::ZigZagDecode64(varint);
+      } else {
+        val = WireFormatLite::ZigZagDecode32(varint);
+      }
+    } else {
+      val = varint;
+    }
+    field->Add(val);
+  });
+}
+
+const char* TcParser::FastV8P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<bool, uint8_t>(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<bool, uint16_t>(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Enum fields
+//////////////////////////////////////////////////////////////////////////////
+
+PROTOBUF_NOINLINE const char* TcParser::FastUnknownEnumFallback(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)msg;
+  (void)ctx;
+  (void)hasbits;
+
+  // If we know we want to put this field directly into the unknown field set,
+  // then we can skip the call to MiniParse and directly call table->fallback.
+  // However, we first have to update `data` to contain the decoded tag.
+  uint32_t tag;
+  ptr = ReadTag(ptr, &tag);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  data.data = tag;
+  PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, uint16_t xform_val>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  const char* ptr2 = ptr;  // Save for unknown enum case
+  ptr += sizeof(TagType);  // Consume tag
+  uint64_t tmp = 0;
+  ptr = ParseVarint(ptr, &tmp);
+  if (ptr == nullptr) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
+  if (PROTOBUF_PREDICT_FALSE(
+          !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
+    ptr = ptr2;
+    PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  RefAt<int32_t>(msg, data.offset()) = tmp;
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastErS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, uint16_t xform_val>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedEnum(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      // Packed parsing is handled by generated fallback.
+      PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
+  do {
+    const char* ptr2 = ptr;  // save for unknown enum case
+    ptr += sizeof(TagType);
+    uint64_t tmp = 0;
+    ptr = ParseVarint(ptr, &tmp);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    if (PROTOBUF_PREDICT_FALSE(
+            !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
+      // We can avoid duplicate work in MiniParse by directly calling
+      // table->fallback.
+      ptr = ptr2;
+      PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    field.Add(static_cast<int32_t>(tmp));
+    if (!ctx->DataAvailable(ptr)) {
+      break;
+    }
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastErR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint8_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastErR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint16_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint8_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint16_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// String/bytes fields
+//////////////////////////////////////////////////////////////////////////////
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
+                       bool emit_stacktrace);
+
+void TcParser::ReportFastUtf8Error(uint32_t decoded_tag,
+                                   const TcParseTableBase* table) {
+  uint32_t field_num = decoded_tag >> 3;
+  const auto* entry = FindFieldEntry(table, field_num);
+  PrintUTF8ErrorLog(MessageName(table), FieldName(table, entry), "parsing",
+                    false);
+}
+
+namespace {
+
+PROTOBUF_NOINLINE
+const char* SingularStringParserFallback(ArenaStringPtr* s, const char* ptr,
+                                         EpsCopyInputStream* stream) {
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+  return stream->ReadString(ptr, size, s->MutableNoCopy(nullptr));
+}
+
+}  // namespace
+
+template <typename TagType, TcParser::Utf8Type utf8>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto saved_tag = UnalignedLoad<TagType>(ptr);
+  ptr += sizeof(TagType);
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  auto& field = RefAt<ArenaStringPtr>(msg, data.offset());
+  auto arena = ctx->data().arena;
+  if (arena) {
+    ptr = ctx->ReadArenaString(ptr, &field, arena);
+  } else {
+    ptr = SingularStringParserFallback(&field, ptr, ctx);
+  }
+  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+  switch (utf8) {
+    case kNoUtf8:
+#ifdef NDEBUG
+    case kUtf8ValidateOnly:
+#endif
+      return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+    default:
+      if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) {
+        return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+      }
+      ReportFastUtf8Error(FastDecodeTag(saved_tag), table);
+      return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
+                           : ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+  }
+}
+
+const char* TcParser::FastBS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// Inlined string variants:
+
+const char* TcParser::FastBiS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBiS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSiS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSiS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUiS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUiS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, TcParser::Utf8Type utf8>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  auto& field = RefAt<RepeatedPtrField<std::string>>(msg, data.offset());
+  do {
+    ptr += sizeof(TagType);
+    std::string* str = field.Add();
+    ptr = InlineGreedyStringParser(str, ptr, ctx);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    switch (utf8) {
+      case kNoUtf8:
+#ifdef NDEBUG
+      case kUtf8ValidateOnly:
+#endif
+        break;
+      default:
+        if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(*str))) {
+          break;
+        }
+        ReportFastUtf8Error(FastDecodeTag(expected_tag), table);
+        if (utf8 == kUtf8) return Error(PROTOBUF_TC_PARAM_PASS);
+        break;
+    }
+    if (!ctx->DataAvailable(ptr)) break;
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastBR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Mini parsing
+//////////////////////////////////////////////////////////////////////////////
+
+namespace {
+inline void SetHas(const TcParseTableBase* table, const FieldEntry& entry,
+                   MessageLite* msg, uint64_t& hasbits) {
+  int32_t has_idx = entry.has_idx;
+  if (has_idx < 32) {
+    hasbits |= uint64_t{1} << has_idx;
+  } else {
+    auto* hasblocks = &TcParser::RefAt<uint32_t>(msg, table->has_bits_offset);
+#if defined(__x86_64__) && defined(__GNUC__)
+    asm("bts %1, %0\n" : "+m"(*hasblocks) : "r"(has_idx));
+#else
+    auto& hasblock = hasblocks[has_idx / 32];
+    hasblock |= uint32_t{1} << (has_idx % 32);
+#endif
+  }
+}
+}  // namespace
+
+// Destroys any existing oneof union member (if necessary). Returns true if the
+// caller is responsible for initializing the object, or false if the field
+// already has the desired case.
+bool TcParser::ChangeOneof(const TcParseTableBase* table,
+                           const TcParseTableBase::FieldEntry& entry,
+                           uint32_t field_num, ParseContext* ctx,
+                           MessageLite* msg) {
+  // The _oneof_case_ array offset is stored in the first aux entry.
+  uint32_t oneof_case_offset = table->field_aux(0u)->offset;
+  // The _oneof_case_ array index is stored in the has-bit index.
+  uint32_t* oneof_case =
+      &TcParser::RefAt<uint32_t>(msg, oneof_case_offset) + entry.has_idx;
+  uint32_t current_case = *oneof_case;
+  *oneof_case = field_num;
+
+  if (current_case == 0) {
+    // If the member is empty, we don't have anything to clear. Caller is
+    // responsible for creating a new member object.
+    return true;
+  }
+  if (current_case == field_num) {
+    // If the member is already active, then it should be merged. We're done.
+    return false;
+  }
+  // Look up the value that is already stored, and dispose of it if necessary.
+  const FieldEntry* current_entry = FindFieldEntry(table, current_case);
+  uint16_t current_kind = current_entry->type_card & field_layout::kFkMask;
+  uint16_t current_rep = current_entry->type_card & field_layout::kRepMask;
+  if (current_kind == field_layout::kFkString) {
+    switch (current_rep) {
+      case field_layout::kRepAString: {
+        auto& field = RefAt<ArenaStringPtr>(msg, current_entry->offset);
+        field.Destroy();
+        break;
+      }
+      case field_layout::kRepSString:
+      case field_layout::kRepIString:
+      default:
+        GOOGLE_LOG(DFATAL) << "string rep not handled: "
+                    << (current_rep >> field_layout::kRepShift);
+        return true;
+    }
+  } else if (current_kind == field_layout::kFkMessage) {
+    switch (current_rep) {
+      case field_layout::kRepMessage:
+      case field_layout::kRepGroup:
+      case field_layout::kRepIWeak: {
+        auto& field = RefAt<MessageLite*>(msg, current_entry->offset);
+        if (!ctx->data().arena) {
+          delete field;
+        }
+        break;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "message rep not handled: "
+                    << (current_rep >> field_layout::kRepShift);
+        break;
+    }
+  }
+  return true;
+}
+
+const char* TcParser::MpFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing (wiretype fallback is handled there):
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for mismatched wiretype:
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+  if (rep == field_layout::kRep64Bits) {
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED64) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED32) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  // Set the field present:
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (card == field_layout::kFcOneof) {
+    ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+  // Copy the value:
+  if (rep == field_layout::kRep64Bits) {
+    RefAt<uint64_t>(msg, entry.offset) = UnalignedLoad<uint64_t>(ptr);
+    ptr += sizeof(uint64_t);
+  } else {
+    RefAt<uint32_t>(msg, entry.offset) = UnalignedLoad<uint32_t>(ptr);
+    ptr += sizeof(uint32_t);
+  }
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+
+  // Check for packed repeated fallback:
+  if (decoded_wiretype == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpPackedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t type_card = entry.type_card;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED64) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    constexpr auto size = sizeof(uint64_t);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      ptr = ptr2;
+      *field.Add() = UnalignedLoad<uint64_t>(ptr);
+      ptr += size;
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED32) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    constexpr auto size = sizeof(uint32_t);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      ptr = ptr2;
+      *field.Add() = UnalignedLoad<uint32_t>(ptr);
+      ptr += size;
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpPackedFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+
+  // Check for non-packed repeated fallback:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpRepeatedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+
+  int size = ReadSize(&ptr);
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    ptr = ctx->ReadPackedFixed(ptr, size, &field);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    ptr = ctx->ReadPackedFixed(ptr, size, &field);
+  }
+
+  if (ptr == nullptr) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing:
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  if ((data.tag() & 7) != WireFormatLite::WIRETYPE_VARINT) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+
+  // Parse the value:
+  const char* ptr2 = ptr;  // save for unknown enum case
+  uint64_t tmp = 0;
+  ptr = ParseVarint(ptr, &tmp);
+  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+
+  // Transform and/or validate the value
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    if (is_zigzag) {
+      tmp = WireFormatLite::ZigZagDecode64(tmp);
+    }
+  } else if (rep == field_layout::kRep32Bits) {
+    if (is_validated_enum) {
+      if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
+        ptr = ptr2;
+        PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      }
+    } else if (is_zigzag) {
+      tmp = WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
+    }
+  }
+
+  // Mark the field as present:
+  const bool is_oneof = card == field_layout::kFcOneof;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+
+  if (rep == field_layout::kRep64Bits) {
+    RefAt<uint64_t>(msg, entry.offset) = tmp;
+  } else if (rep == field_layout::kRep32Bits) {
+    RefAt<uint32_t>(msg, entry.offset) = static_cast<uint32_t>(tmp);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    RefAt<bool>(msg, entry.offset) = static_cast<bool>(tmp);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  auto type_card = entry.type_card;
+  const uint32_t decoded_tag = data.tag();
+  auto decoded_wiretype = decoded_tag & 7;
+
+  // Check for packed repeated fallback:
+  if (decoded_wiretype == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpPackedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_VARINT) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  uint16_t xform_val = (type_card & field_layout::kTvMask);
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp = 0;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp);
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else if (rep == field_layout::kRep32Bits) {
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp = 0;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (is_validated_enum) {
+        if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
+          ptr = ptr2;
+          PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+        }
+      } else if (is_zigzag) {
+        tmp = WireFormatLite::ZigZagDecode32(tmp);
+      }
+      field.Add(tmp);
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    auto& field = RefAt<RepeatedField<bool>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp = 0;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      field.Add(static_cast<bool>(tmp));
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  auto type_card = entry.type_card;
+  auto decoded_wiretype = data.tag() & 7;
+
+  // Check for non-packed repeated fallback:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpRepeatedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  uint16_t xform_val = (type_card & field_layout::kTvMask);
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+  if (is_validated_enum) {
+    // TODO(b/206890171): handle enums
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto* field = &RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(ptr, [field, is_zigzag](uint64_t value) {
+      field->Add(is_zigzag ? WireFormatLite::ZigZagDecode64(value) : value);
+    });
+  } else if (rep == field_layout::kRep32Bits) {
+    auto* field = &RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(ptr, [field, is_zigzag](uint64_t value) {
+      field->Add(is_zigzag ? WireFormatLite::ZigZagDecode32(
+                                 static_cast<uint32_t>(value))
+                           : value);
+    });
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    auto* field = &RefAt<RepeatedField<bool>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(
+        ptr, [field](uint64_t value) { field->Add(value); });
+  }
+
+  return Error(PROTOBUF_TC_PARAM_PASS);
+}
+
+bool TcParser::MpVerifyUtf8(StringPiece wire_bytes,
+                            const TcParseTableBase* table,
+                            const FieldEntry& entry, uint16_t xform_val) {
+  if (xform_val == field_layout::kTvUtf8) {
+    if (!IsStructurallyValidUTF8(wire_bytes)) {
+      PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing",
+                        false);
+      return false;
+    }
+    return true;
+  }
+#ifndef NDEBUG
+  if (xform_val == field_layout::kTvUtf8Debug) {
+    if (!IsStructurallyValidUTF8(wire_bytes)) {
+      PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing",
+                        false);
+    }
+  }
+#endif  // NDEBUG
+  return true;
+}
+
+const char* TcParser::MpString(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedString(PROTOBUF_TC_PARAM_PASS);
+  }
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRepIString) {
+    // TODO(b/198211897): support InilnedStringField.
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Mark the field as present:
+  const bool is_oneof = card == field_layout::kFcOneof;
+  bool need_init = false;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    need_init = ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+
+  bool is_valid = false;
+  Arena* arena = ctx->data().arena;
+  switch (rep) {
+    case field_layout::kRepAString: {
+      auto& field = RefAt<ArenaStringPtr>(msg, entry.offset);
+      if (need_init) field.InitDefault();
+      if (arena) {
+        ptr = ctx->ReadArenaString(ptr, &field, arena);
+      } else {
+        std::string* str = field.MutableNoCopy(nullptr);
+        ptr = InlineGreedyStringParser(str, ptr, ctx);
+      }
+      if (!ptr) break;
+      is_valid = MpVerifyUtf8(field.Get(), table, entry, xform_val);
+      break;
+    }
+
+    case field_layout::kRepIString: {
+      break;
+    }
+  }
+
+  if (ptr == nullptr || !is_valid) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedString(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  switch (rep) {
+    case field_layout::kRepSString: {
+      auto& field = RefAt<RepeatedPtrField<std::string>>(msg, entry.offset);
+      const char* ptr2 = ptr;
+      uint32_t next_tag;
+      do {
+        ptr = ptr2;
+        std::string* str = field.Add();
+        ptr = InlineGreedyStringParser(str, ptr, ctx);
+        if (PROTOBUF_PREDICT_FALSE(
+                ptr == nullptr ||
+                !MpVerifyUtf8(*str, table, entry, xform_val))) {
+          return Error(PROTOBUF_TC_PARAM_PASS);
+        }
+        if (!ctx->DataAvailable(ptr)) break;
+        ptr2 = ReadTag(ptr, &next_tag);
+      } while (next_tag == decoded_tag);
+      break;
+    }
+
+#ifndef NDEBUG
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported repeated string rep: " << rep;
+      break;
+#endif
+  }
+
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing:
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedMessage(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const bool is_group = rep == field_layout::kRepGroup;
+
+  // Validate wiretype:
+  switch (rep) {
+    case field_layout::kRepMessage:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+        goto fallback;
+      }
+      break;
+    case field_layout::kRepGroup:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_START_GROUP) {
+        goto fallback;
+      }
+      break;
+    default: {
+    fallback:
+      // Lazy and implicit weak fields are handled by generated code:
+      // TODO(b/210762816): support these.
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+
+  const bool is_oneof = card == field_layout::kFcOneof;
+  bool need_init = false;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    need_init = ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+  MessageLite*& field = RefAt<MessageLite*>(msg, entry.offset);
+  if (need_init || field == nullptr) {
+    const MessageLite* default_instance =
+        table->field_aux(&entry)->message_default;
+    field = default_instance->New(ctx->data().arena);
+  }
+  SyncHasbits(msg, hasbits, table);
+  if (is_group) {
+    return ctx->ParseGroup(field, ptr, decoded_tag);
+  }
+  return ctx->ParseMessage(field, ptr);
+}
+
+const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  GOOGLE_DCHECK_EQ(type_card & field_layout::kFcMask,
+            static_cast<uint16_t>(field_layout::kFcRepeated));
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const bool is_group = rep == field_layout::kRepGroup;
+
+  // Validate wiretype:
+  switch (rep) {
+    case field_layout::kRepMessage:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+        goto fallback;
+      }
+      break;
+    case field_layout::kRepGroup:
+      if (decoded_wiretype != WireFormatLite::WIRETYPE_START_GROUP) {
+        goto fallback;
+      }
+      break;
+    default: {
+    fallback:
+      // Lazy and implicit weak fields are handled by generated code:
+      // TODO(b/210762816): support these.
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+
+  SyncHasbits(msg, hasbits, table);
+  const MessageLite* default_instance =
+      table->field_aux(&entry)->message_default;
+  auto& field = RefAt<RepeatedPtrFieldBase>(msg, entry.offset);
+  MessageLite* value =
+      field.Add<GenericTypeHandler<MessageLite>>(default_instance);
+  if (is_group) {
+    return ctx->ParseGroup(value, ptr, decoded_tag);
+  }
+  return ctx->ParseMessage(value, ptr);
+}
+
+const char* TcParser::MpMap(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  (void)entry;
+  PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_util.cpp
new file mode 100644
index 0000000..cad12a3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/generated_message_util.cpp
@@ -0,0 +1,409 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/generated_message_util.h>
+
+#include <atomic>
+#include <limits>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void DestroyMessage(const void* message) {
+  static_cast<const MessageLite*>(message)->~MessageLite();
+}
+void DestroyString(const void* s) {
+  static_cast<const std::string*>(s)->~basic_string();
+}
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplicitlyConstructedArenaString
+        fixed_address_empty_string{};  // NOLINT
+
+
+PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
+static bool InitProtobufDefaultsImpl() {
+  fixed_address_empty_string.DefaultConstruct();
+  OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
+
+
+  init_protobuf_defaults_state.store(true, std::memory_order_release);
+  return true;
+}
+
+void InitProtobufDefaultsSlow() {
+  static bool is_inited = InitProtobufDefaultsImpl();
+  (void)is_inited;
+}
+// Force the initialization of the empty string.
+// Normally, registration would do it, but we don't have any guarantee that
+// there is any object with reflection.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 static std::true_type init_empty_string =
+    (InitProtobufDefaultsSlow(), std::true_type{});
+
+size_t StringSpaceUsedExcludingSelfLong(const std::string& str) {
+  const void* start = &str;
+  const void* end = &str + 1;
+  if (start <= str.data() && str.data() < end) {
+    // The string's data is stored inside the string object itself.
+    return 0;
+  } else {
+    return str.capacity();
+  }
+}
+
+template <typename T>
+const T& Get(const void* ptr) {
+  return *static_cast<const T*>(ptr);
+}
+
+// PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite.
+// WireFormatLite has a very inconvenient interface with respect to template
+// meta-programming. This class wraps the different named functions into
+// a single Serialize / SerializeToArray interface.
+template <int type>
+struct PrimitiveTypeHelper;
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
+  typedef bool Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
+  typedef int32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteInt32NoTag(Get<int32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
+  typedef int32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteSInt32NoTag(Get<int32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
+  typedef uint32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteUInt32NoTag(Get<uint32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
+  typedef int64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteInt64NoTag(Get<int64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
+  typedef int64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteSInt64NoTag(Get<int64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
+  typedef uint64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteUInt64NoTag(Get<uint64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
+  typedef uint32_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteFixed32NoTag(Get<uint32_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
+  typedef uint64_t Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    WireFormatLite::WriteFixed64NoTag(Get<uint64_t>(ptr), output);
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
+  typedef int32_t Type;
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
+  typedef int64_t Type;
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
+  typedef float Type;
+};
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
+  typedef double Type;
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
+  typedef std::string Type;
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    const Type& value = *static_cast<const Type*>(ptr);
+    output->WriteVarint32(value.size());
+    output->WriteRawMaybeAliased(value.data(), value.size());
+  }
+  static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
+    const Type& value = *static_cast<const Type*>(ptr);
+    return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
+  }
+};
+
+template <>
+struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
+    : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
+
+// We want to serialize to both CodedOutputStream and directly into byte arrays
+// without duplicating the code. In fact we might want extra output channels in
+// the future.
+template <typename O, int type>
+struct OutputHelper;
+
+template <int type, typename O>
+void SerializeTo(const void* ptr, O* output) {
+  OutputHelper<O, type>::Serialize(ptr, output);
+}
+
+template <typename O>
+void WriteTagTo(uint32_t tag, O* output) {
+  SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
+}
+
+template <typename O>
+void WriteLengthTo(uint32_t length, O* output) {
+  SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
+}
+
+// Specialization for coded output stream
+template <int type>
+struct OutputHelper<io::CodedOutputStream, type> {
+  static void Serialize(const void* ptr, io::CodedOutputStream* output) {
+    PrimitiveTypeHelper<type>::Serialize(ptr, output);
+  }
+};
+
+// Specialization for writing into a plain array
+struct ArrayOutput {
+  uint8_t* ptr;
+  bool is_deterministic;
+};
+
+template <int type>
+struct OutputHelper<ArrayOutput, type> {
+  static void Serialize(const void* ptr, ArrayOutput* output) {
+    output->ptr = PrimitiveTypeHelper<type>::SerializeToArray(ptr, output->ptr);
+  }
+};
+
+void SerializeMessageNoTable(const MessageLite* msg,
+                             io::CodedOutputStream* output) {
+  msg->SerializeWithCachedSizes(output);
+}
+
+void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
+  io::ArrayOutputStream array_stream(output->ptr, INT_MAX);
+  io::CodedOutputStream o(&array_stream);
+  o.SetSerializationDeterministic(output->is_deterministic);
+  msg->SerializeWithCachedSizes(&o);
+  output->ptr += o.ByteCount();
+}
+
+// We need to use a helper class to get access to the private members
+class AccessorHelper {
+ public:
+  static int Size(const RepeatedPtrFieldBase& x) { return x.size(); }
+  static void const* Get(const RepeatedPtrFieldBase& x, int idx) {
+    return x.raw_data()[idx];
+  }
+};
+
+void SerializeNotImplemented(int field) {
+  GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
+}
+
+// When switching to c++11 we should make these constexpr functions
+#define SERIALIZE_TABLE_OP(type, type_class) \
+  ((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
+
+template <int type>
+bool IsNull(const void* ptr) {
+  return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
+         0;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_STRING>(const void* ptr) {
+  return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
+  return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
+  return Get<const MessageLite*>(ptr) == nullptr;
+}
+
+template <>
+bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
+  return Get<const MessageLite*>(ptr) == nullptr;
+}
+
+void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr,
+                         uint32_t offset, uint32_t tag, uint32_t has_offset,
+                         io::CodedOutputStream* output) {
+  reinterpret_cast<const ExtensionSet*>(ptr + offset)
+      ->SerializeWithCachedSizes(extendee, tag, has_offset, output);
+}
+
+void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset,
+                                uint32_t /*tag*/, uint32_t /*has_offset*/,
+                                io::CodedOutputStream* output) {
+  output->WriteString(
+      reinterpret_cast<const InternalMetadata*>(ptr + offset)
+          ->unknown_fields<std::string>(&internal::GetEmptyString));
+}
+
+MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
+  if (message) {
+    MessageLite* ret = message->New();
+    ret->CheckTypeAndMergeFrom(*message);
+    return ret;
+  } else {
+    return nullptr;
+  }
+}
+
+void GenericSwap(MessageLite* m1, MessageLite* m2) {
+  std::unique_ptr<MessageLite> tmp(m1->New());
+  tmp->CheckTypeAndMergeFrom(*m1);
+  m1->Clear();
+  m1->CheckTypeAndMergeFrom(*m2);
+  m2->Clear();
+  m2->CheckTypeAndMergeFrom(*tmp);
+}
+
+// Returns a message owned by this Arena.  This may require Own()ing or
+// duplicating the message.
+MessageLite* GetOwnedMessageInternal(Arena* message_arena,
+                                     MessageLite* submessage,
+                                     Arena* submessage_arena) {
+  GOOGLE_DCHECK(Arena::InternalGetOwningArena(submessage) == submessage_arena);
+  GOOGLE_DCHECK(message_arena != submessage_arena);
+  GOOGLE_DCHECK_EQ(submessage_arena, nullptr);
+  if (message_arena != nullptr && submessage_arena == nullptr) {
+    message_arena->Own(submessage);
+    return submessage;
+  } else {
+    MessageLite* ret = submessage->New(message_arena);
+    ret->CheckTypeAndMergeFrom(*submessage);
+    return ret;
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/implicit_weak_message.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/implicit_weak_message.cpp
new file mode 100644
index 0000000..27ed6b6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/implicit_weak_message.cpp
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/implicit_weak_message.h>
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+const char* ImplicitWeakMessage::_InternalParse(const char* ptr,
+                                                ParseContext* ctx) {
+  return ctx->AppendString(ptr, data_);
+}
+
+struct ImplicitWeakMessageDefaultType {
+  constexpr ImplicitWeakMessageDefaultType()
+      : instance(ConstantInitialized{}) {}
+  ~ImplicitWeakMessageDefaultType() {}
+  union {
+    ImplicitWeakMessage instance;
+  };
+};
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ImplicitWeakMessageDefaultType
+    implicit_weak_message_default_instance;
+
+const ImplicitWeakMessage* ImplicitWeakMessage::default_instance() {
+  return reinterpret_cast<ImplicitWeakMessage*>(
+      &implicit_weak_message_default_instance);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/inlined_string_field.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/inlined_string_field.cpp
new file mode 100644
index 0000000..0c3e476
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/inlined_string_field.cpp
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/inlined_string_field.h>
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+
+std::string* InlinedStringField::Mutable(const LazyString& /*default_value*/,
+                                         Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  if (arena == nullptr || !donated) {
+    return UnsafeMutablePointer();
+  }
+  return MutableSlow(arena, donated, donating_states, mask, msg);
+}
+
+std::string* InlinedStringField::Mutable(Arena* arena, bool donated,
+                                         uint32_t* donating_states,
+                                         uint32_t mask, MessageLite* msg) {
+  if (arena == nullptr || !donated) {
+    return UnsafeMutablePointer();
+  }
+  return MutableSlow(arena, donated, donating_states, mask, msg);
+}
+
+std::string* InlinedStringField::MutableSlow(::google::protobuf::Arena* arena,
+                                             bool donated,
+                                             uint32_t* donating_states,
+                                             uint32_t mask, MessageLite* msg) {
+  (void)mask;
+  (void)msg;
+  return UnsafeMutablePointer();
+}
+
+void InlinedStringField::SetAllocated(const std::string* default_value,
+                                      std::string* value, Arena* arena,
+                                      bool donated, uint32_t* donating_states,
+                                      uint32_t mask, MessageLite* msg) {
+  (void)mask;
+  (void)msg;
+  SetAllocatedNoArena(default_value, value);
+}
+
+void InlinedStringField::Set(std::string&& value, Arena* arena, bool donated,
+                             uint32_t* donating_states, uint32_t mask,
+                             MessageLite* msg) {
+  (void)donating_states;
+  (void)mask;
+  (void)msg;
+  SetNoArena(std::move(value));
+}
+
+std::string* InlinedStringField::Release() {
+  auto* released = new std::string(std::move(*get_mutable()));
+  get_mutable()->clear();
+  return released;
+}
+
+std::string* InlinedStringField::Release(Arena* arena, bool donated) {
+  // We can not steal donated arena strings.
+  std::string* released = (arena != nullptr && donated)
+                              ? new std::string(*get_mutable())
+                              : new std::string(std::move(*get_mutable()));
+  get_mutable()->clear();
+  return released;
+}
+
+void InlinedStringField::ClearToDefault(const LazyString& default_value,
+                                        Arena* arena, bool donated) {
+  (void)arena;
+  get_mutable()->assign(default_value.get());
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/coded_stream.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/coded_stream.cpp
new file mode 100644
index 0000000..5399790
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/coded_stream.cpp
@@ -0,0 +1,967 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This implementation is heavily optimized to make reads and writes
+// of small values (especially varints) as fast as possible.  In
+// particular, we optimize for the common case that a read or a write
+// will not cross the end of the buffer, since we can avoid a lot
+// of branching in this case.
+
+#include <google/protobuf/io/coded_stream.h>
+
+#include <limits.h>
+
+#include <algorithm>
+#include <cstring>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+namespace {
+
+static const int kMaxVarintBytes = 10;
+static const int kMaxVarint32Bytes = 5;
+
+
+inline bool NextNonEmpty(ZeroCopyInputStream* input, const void** data,
+                         int* size) {
+  bool success;
+  do {
+    success = input->Next(data, size);
+  } while (success && *size == 0);
+  return success;
+}
+
+}  // namespace
+
+// CodedInputStream ==================================================
+
+CodedInputStream::~CodedInputStream() {
+  if (input_ != NULL) {
+    BackUpInputToCurrentPosition();
+  }
+}
+
+// Static.
+int CodedInputStream::default_recursion_limit_ = 100;
+
+
+void CodedInputStream::BackUpInputToCurrentPosition() {
+  int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
+  if (backup_bytes > 0) {
+    input_->BackUp(backup_bytes);
+
+    // total_bytes_read_ doesn't include overflow_bytes_.
+    total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
+    buffer_end_ = buffer_;
+    buffer_size_after_limit_ = 0;
+    overflow_bytes_ = 0;
+  }
+}
+
+inline void CodedInputStream::RecomputeBufferLimits() {
+  buffer_end_ += buffer_size_after_limit_;
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
+  if (closest_limit < total_bytes_read_) {
+    // The limit position is in the current buffer.  We must adjust
+    // the buffer size accordingly.
+    buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
+    buffer_end_ -= buffer_size_after_limit_;
+  } else {
+    buffer_size_after_limit_ = 0;
+  }
+}
+
+CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
+  // Current position relative to the beginning of the stream.
+  int current_position = CurrentPosition();
+
+  Limit old_limit = current_limit_;
+
+  // security: byte_limit is possibly evil, so check for negative values
+  // and overflow. Also check that the new requested limit is before the
+  // previous limit; otherwise we continue to enforce the previous limit.
+  if (PROTOBUF_PREDICT_TRUE(byte_limit >= 0 &&
+                            byte_limit <= INT_MAX - current_position &&
+                            byte_limit < current_limit_ - current_position)) {
+    current_limit_ = current_position + byte_limit;
+    RecomputeBufferLimits();
+  }
+
+  return old_limit;
+}
+
+void CodedInputStream::PopLimit(Limit limit) {
+  // The limit passed in is actually the *old* limit, which we returned from
+  // PushLimit().
+  current_limit_ = limit;
+  RecomputeBufferLimits();
+
+  // We may no longer be at a legitimate message end.  ReadTag() needs to be
+  // called again to find out.
+  legitimate_message_end_ = false;
+}
+
+std::pair<CodedInputStream::Limit, int>
+CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
+  return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
+}
+
+CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
+  uint32_t length;
+  return PushLimit(ReadVarint32(&length) ? length : 0);
+}
+
+bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_);
+  ++recursion_budget_;
+  return result;
+}
+
+bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  return result;
+}
+
+int CodedInputStream::BytesUntilLimit() const {
+  if (current_limit_ == INT_MAX) return -1;
+  int current_position = CurrentPosition();
+
+  return current_limit_ - current_position;
+}
+
+void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) {
+  // Make sure the limit isn't already past, since this could confuse other
+  // code.
+  int current_position = CurrentPosition();
+  total_bytes_limit_ = std::max(current_position, total_bytes_limit);
+  RecomputeBufferLimits();
+}
+
+int CodedInputStream::BytesUntilTotalBytesLimit() const {
+  if (total_bytes_limit_ == INT_MAX) return -1;
+  return total_bytes_limit_ - CurrentPosition();
+}
+
+void CodedInputStream::PrintTotalBytesLimitError() {
+  GOOGLE_LOG(ERROR)
+      << "A protocol message was rejected because it was too "
+         "big (more than "
+      << total_bytes_limit_
+      << " bytes).  To increase the limit (or to disable these "
+         "warnings), see CodedInputStream::SetTotalBytesLimit() "
+         "in third_party/protobuf/io/coded_stream.h.";
+}
+
+bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
+  if (buffer_size_after_limit_ > 0) {
+    // We hit a limit inside this buffer.  Advance to the limit and fail.
+    Advance(original_buffer_size);
+    return false;
+  }
+
+  count -= original_buffer_size;
+  buffer_ = NULL;
+  buffer_end_ = buffer_;
+
+  // Make sure this skip doesn't try to skip past the current limit.
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
+  int bytes_until_limit = closest_limit - total_bytes_read_;
+  if (bytes_until_limit < count) {
+    // We hit the limit.  Skip up to it then fail.
+    if (bytes_until_limit > 0) {
+      total_bytes_read_ = closest_limit;
+      input_->Skip(bytes_until_limit);
+    }
+    return false;
+  }
+
+  if (!input_->Skip(count)) {
+    total_bytes_read_ = input_->ByteCount();
+    return false;
+  }
+  total_bytes_read_ += count;
+  return true;
+}
+
+bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
+  if (BufferSize() == 0 && !Refresh()) return false;
+
+  *data = buffer_;
+  *size = BufferSize();
+  return true;
+}
+
+bool CodedInputStream::ReadRaw(void* buffer, int size) {
+  int current_buffer_size;
+  while ((current_buffer_size = BufferSize()) < size) {
+    // Reading past end of buffer.  Copy what we have, then refresh.
+    memcpy(buffer, buffer_, current_buffer_size);
+    buffer = reinterpret_cast<uint8_t*>(buffer) + current_buffer_size;
+    size -= current_buffer_size;
+    Advance(current_buffer_size);
+    if (!Refresh()) return false;
+  }
+
+  memcpy(buffer, buffer_, size);
+  Advance(size);
+
+  return true;
+}
+
+bool CodedInputStream::ReadString(std::string* buffer, int size) {
+  if (size < 0) return false;  // security: size is often user-supplied
+
+  if (BufferSize() >= size) {
+    STLStringResizeUninitialized(buffer, size);
+    std::pair<char*, bool> z = as_string_data(buffer);
+    if (z.second) {
+      // Oddly enough, memcpy() requires its first two args to be non-NULL even
+      // if we copy 0 bytes.  So, we have ensured that z.first is non-NULL here.
+      GOOGLE_DCHECK(z.first != NULL);
+      memcpy(z.first, buffer_, size);
+      Advance(size);
+    }
+    return true;
+  }
+
+  return ReadStringFallback(buffer, size);
+}
+
+bool CodedInputStream::ReadStringFallback(std::string* buffer, int size) {
+  if (!buffer->empty()) {
+    buffer->clear();
+  }
+
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
+  if (closest_limit != INT_MAX) {
+    int bytes_to_limit = closest_limit - CurrentPosition();
+    if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
+      buffer->reserve(size);
+    }
+  }
+
+  int current_buffer_size;
+  while ((current_buffer_size = BufferSize()) < size) {
+    // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
+    if (current_buffer_size != 0) {
+      // Note:  string1.append(string2) is O(string2.size()) (as opposed to
+      //   O(string1.size() + string2.size()), which would be bad).
+      buffer->append(reinterpret_cast<const char*>(buffer_),
+                     current_buffer_size);
+    }
+    size -= current_buffer_size;
+    Advance(current_buffer_size);
+    if (!Refresh()) return false;
+  }
+
+  buffer->append(reinterpret_cast<const char*>(buffer_), size);
+  Advance(size);
+
+  return true;
+}
+
+
+bool CodedInputStream::ReadLittleEndian32Fallback(uint32_t* value) {
+  uint8_t bytes[sizeof(*value)];
+
+  const uint8_t* ptr;
+  if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
+    // Fast path:  Enough bytes in the buffer to read directly.
+    ptr = buffer_;
+    Advance(sizeof(*value));
+  } else {
+    // Slow path:  Had to read past the end of the buffer.
+    if (!ReadRaw(bytes, sizeof(*value))) return false;
+    ptr = bytes;
+  }
+  ReadLittleEndian32FromArray(ptr, value);
+  return true;
+}
+
+bool CodedInputStream::ReadLittleEndian64Fallback(uint64_t* value) {
+  uint8_t bytes[sizeof(*value)];
+
+  const uint8_t* ptr;
+  if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
+    // Fast path:  Enough bytes in the buffer to read directly.
+    ptr = buffer_;
+    Advance(sizeof(*value));
+  } else {
+    // Slow path:  Had to read past the end of the buffer.
+    if (!ReadRaw(bytes, sizeof(*value))) return false;
+    ptr = bytes;
+  }
+  ReadLittleEndian64FromArray(ptr, value);
+  return true;
+}
+
+namespace {
+
+// Decodes varint64 with known size, N, and returns next pointer. Knowing N at
+// compile time, compiler can generate optimal code. For example, instead of
+// subtracting 0x80 at each iteration, it subtracts properly shifted mask once.
+template <size_t N>
+const uint8_t* DecodeVarint64KnownSize(const uint8_t* buffer, uint64_t* value) {
+  GOOGLE_DCHECK_GT(N, 0);
+  uint64_t result = static_cast<uint64_t>(buffer[N - 1]) << (7 * (N - 1));
+  for (size_t i = 0, offset = 0; i < N - 1; i++, offset += 7) {
+    result += static_cast<uint64_t>(buffer[i] - 0x80) << offset;
+  }
+  *value = result;
+  return buffer + N;
+}
+
+// Read a varint from the given buffer, write it to *value, and return a pair.
+// The first part of the pair is true iff the read was successful.  The second
+// part is buffer + (number of bytes read).  This function is always inlined,
+// so returning a pair is costless.
+PROTOBUF_ALWAYS_INLINE
+::std::pair<bool, const uint8_t*> ReadVarint32FromArray(uint32_t first_byte,
+                                                      const uint8_t* buffer,
+                                                      uint32_t* value);
+inline ::std::pair<bool, const uint8_t*> ReadVarint32FromArray(
+    uint32_t first_byte, const uint8_t* buffer, uint32_t* value) {
+  // Fast path:  We have enough bytes left in the buffer to guarantee that
+  // this read won't cross the end, so we can skip the checks.
+  GOOGLE_DCHECK_EQ(*buffer, first_byte);
+  GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
+  const uint8_t* ptr = buffer;
+  uint32_t b;
+  uint32_t result = first_byte - 0x80;
+  ++ptr;  // We just processed the first byte.  Move on to the second.
+  b = *(ptr++);
+  result += b << 7;
+  if (!(b & 0x80)) goto done;
+  result -= 0x80 << 7;
+  b = *(ptr++);
+  result += b << 14;
+  if (!(b & 0x80)) goto done;
+  result -= 0x80 << 14;
+  b = *(ptr++);
+  result += b << 21;
+  if (!(b & 0x80)) goto done;
+  result -= 0x80 << 21;
+  b = *(ptr++);
+  result += b << 28;
+  if (!(b & 0x80)) goto done;
+  // "result -= 0x80 << 28" is irrelevant.
+
+  // If the input is larger than 32 bits, we still need to read it all
+  // and discard the high-order bits.
+  for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
+    b = *(ptr++);
+    if (!(b & 0x80)) goto done;
+  }
+
+  // We have overrun the maximum size of a varint (10 bytes).  Assume
+  // the data is corrupt.
+  return std::make_pair(false, ptr);
+
+done:
+  *value = result;
+  return std::make_pair(true, ptr);
+}
+
+PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
+    const uint8_t* buffer, uint64_t* value);
+inline ::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
+    const uint8_t* buffer, uint64_t* value) {
+  // Assumes varint64 is at least 2 bytes.
+  GOOGLE_DCHECK_GE(buffer[0], 128);
+
+  const uint8_t* next;
+  if (buffer[1] < 128) {
+    next = DecodeVarint64KnownSize<2>(buffer, value);
+  } else if (buffer[2] < 128) {
+    next = DecodeVarint64KnownSize<3>(buffer, value);
+  } else if (buffer[3] < 128) {
+    next = DecodeVarint64KnownSize<4>(buffer, value);
+  } else if (buffer[4] < 128) {
+    next = DecodeVarint64KnownSize<5>(buffer, value);
+  } else if (buffer[5] < 128) {
+    next = DecodeVarint64KnownSize<6>(buffer, value);
+  } else if (buffer[6] < 128) {
+    next = DecodeVarint64KnownSize<7>(buffer, value);
+  } else if (buffer[7] < 128) {
+    next = DecodeVarint64KnownSize<8>(buffer, value);
+  } else if (buffer[8] < 128) {
+    next = DecodeVarint64KnownSize<9>(buffer, value);
+  } else if (buffer[9] < 128) {
+    next = DecodeVarint64KnownSize<10>(buffer, value);
+  } else {
+    // We have overrun the maximum size of a varint (10 bytes). Assume
+    // the data is corrupt.
+    return std::make_pair(false, buffer + 11);
+  }
+
+  return std::make_pair(true, next);
+}
+
+}  // namespace
+
+bool CodedInputStream::ReadVarint32Slow(uint32_t* value) {
+  // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+  // for one-byte varints.
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  *value = static_cast<uint32_t>(p.first);
+  return p.second;
+}
+
+int64_t CodedInputStream::ReadVarint32Fallback(uint32_t first_byte_or_zero) {
+  if (BufferSize() >= kMaxVarintBytes ||
+      // Optimization:  We're also safe if the buffer is non-empty and it ends
+      // with a byte that would terminate a varint.
+      (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+    GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
+        << "Caller should provide us with *buffer_ when buffer is non-empty";
+    uint32_t temp = 0;
+    ::std::pair<bool, const uint8_t*> p =
+        ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
+    if (!p.first) return -1;
+    buffer_ = p.second;
+    return temp;
+  } else {
+    // Really slow case: we will incur the cost of an extra function call here,
+    // but moving this out of line reduces the size of this function, which
+    // improves the common case. In micro benchmarks, this is worth about 10-15%
+    uint32_t temp;
+    return ReadVarint32Slow(&temp) ? static_cast<int64_t>(temp) : -1;
+  }
+}
+
+int CodedInputStream::ReadVarintSizeAsIntSlow() {
+  // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+  // for one-byte varints.
+  std::pair<uint64_t, bool> p = ReadVarint64Fallback();
+  if (!p.second || p.first > static_cast<uint64_t>(INT_MAX)) return -1;
+  return p.first;
+}
+
+int CodedInputStream::ReadVarintSizeAsIntFallback() {
+  if (BufferSize() >= kMaxVarintBytes ||
+      // Optimization:  We're also safe if the buffer is non-empty and it ends
+      // with a byte that would terminate a varint.
+      (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+    uint64_t temp;
+    ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first || temp > static_cast<uint64_t>(INT_MAX)) return -1;
+    buffer_ = p.second;
+    return temp;
+  } else {
+    // Really slow case: we will incur the cost of an extra function call here,
+    // but moving this out of line reduces the size of this function, which
+    // improves the common case. In micro benchmarks, this is worth about 10-15%
+    return ReadVarintSizeAsIntSlow();
+  }
+}
+
+uint32_t CodedInputStream::ReadTagSlow() {
+  if (buffer_ == buffer_end_) {
+    // Call refresh.
+    if (!Refresh()) {
+      // Refresh failed.  Make sure that it failed due to EOF, not because
+      // we hit total_bytes_limit_, which, unlike normal limits, is not a
+      // valid place to end a message.
+      int current_position = total_bytes_read_ - buffer_size_after_limit_;
+      if (current_position >= total_bytes_limit_) {
+        // Hit total_bytes_limit_.  But if we also hit the normal limit,
+        // we're still OK.
+        legitimate_message_end_ = current_limit_ == total_bytes_limit_;
+      } else {
+        legitimate_message_end_ = true;
+      }
+      return 0;
+    }
+  }
+
+  // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
+  // again, since we have now refreshed the buffer.
+  uint64_t result = 0;
+  if (!ReadVarint64(&result)) return 0;
+  return static_cast<uint32_t>(result);
+}
+
+uint32_t CodedInputStream::ReadTagFallback(uint32_t first_byte_or_zero) {
+  const int buf_size = BufferSize();
+  if (buf_size >= kMaxVarintBytes ||
+      // Optimization:  We're also safe if the buffer is non-empty and it ends
+      // with a byte that would terminate a varint.
+      (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
+    GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
+    if (first_byte_or_zero == 0) {
+      ++buffer_;
+      return 0;
+    }
+    uint32_t tag;
+    ::std::pair<bool, const uint8_t*> p =
+        ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
+    if (!p.first) {
+      return 0;
+    }
+    buffer_ = p.second;
+    return tag;
+  } else {
+    // We are commonly at a limit when attempting to read tags. Try to quickly
+    // detect this case without making another function call.
+    if ((buf_size == 0) &&
+        ((buffer_size_after_limit_ > 0) ||
+         (total_bytes_read_ == current_limit_)) &&
+        // Make sure that the limit we hit is not total_bytes_limit_, since
+        // in that case we still need to call Refresh() so that it prints an
+        // error.
+        total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
+      // We hit a byte limit.
+      legitimate_message_end_ = true;
+      return 0;
+    }
+    return ReadTagSlow();
+  }
+}
+
+bool CodedInputStream::ReadVarint64Slow(uint64_t* value) {
+  // Slow path:  This read might cross the end of the buffer, so we
+  // need to check and refresh the buffer if and when it does.
+
+  uint64_t result = 0;
+  int count = 0;
+  uint32_t b;
+
+  do {
+    if (count == kMaxVarintBytes) {
+      *value = 0;
+      return false;
+    }
+    while (buffer_ == buffer_end_) {
+      if (!Refresh()) {
+        *value = 0;
+        return false;
+      }
+    }
+    b = *buffer_;
+    result |= static_cast<uint64_t>(b & 0x7F) << (7 * count);
+    Advance(1);
+    ++count;
+  } while (b & 0x80);
+
+  *value = result;
+  return true;
+}
+
+std::pair<uint64_t, bool> CodedInputStream::ReadVarint64Fallback() {
+  if (BufferSize() >= kMaxVarintBytes ||
+      // Optimization:  We're also safe if the buffer is non-empty and it ends
+      // with a byte that would terminate a varint.
+      (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+    uint64_t temp;
+    ::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first) {
+      return std::make_pair(0, false);
+    }
+    buffer_ = p.second;
+    return std::make_pair(temp, true);
+  } else {
+    uint64_t temp;
+    bool success = ReadVarint64Slow(&temp);
+    return std::make_pair(temp, success);
+  }
+}
+
+bool CodedInputStream::Refresh() {
+  GOOGLE_DCHECK_EQ(0, BufferSize());
+
+  if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
+      total_bytes_read_ == current_limit_) {
+    // We've hit a limit.  Stop.
+    int current_position = total_bytes_read_ - buffer_size_after_limit_;
+
+    if (current_position >= total_bytes_limit_ &&
+        total_bytes_limit_ != current_limit_) {
+      // Hit total_bytes_limit_.
+      PrintTotalBytesLimitError();
+    }
+
+    return false;
+  }
+
+  const void* void_buffer;
+  int buffer_size;
+  if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
+    buffer_ = reinterpret_cast<const uint8_t*>(void_buffer);
+    buffer_end_ = buffer_ + buffer_size;
+    GOOGLE_CHECK_GE(buffer_size, 0);
+
+    if (total_bytes_read_ <= INT_MAX - buffer_size) {
+      total_bytes_read_ += buffer_size;
+    } else {
+      // Overflow.  Reset buffer_end_ to not include the bytes beyond INT_MAX.
+      // We can't get that far anyway, because total_bytes_limit_ is guaranteed
+      // to be less than it.  We need to keep track of the number of bytes
+      // we discarded, though, so that we can call input_->BackUp() to back
+      // up over them on destruction.
+
+      // The following line is equivalent to:
+      //   overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
+      // except that it avoids overflows.  Signed integer overflow has
+      // undefined results according to the C standard.
+      overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
+      buffer_end_ -= overflow_bytes_;
+      total_bytes_read_ = INT_MAX;
+    }
+
+    RecomputeBufferLimits();
+    return true;
+  } else {
+    buffer_ = NULL;
+    buffer_end_ = NULL;
+    return false;
+  }
+}
+
+// CodedOutputStream =================================================
+
+void EpsCopyOutputStream::EnableAliasing(bool enabled) {
+  aliasing_enabled_ = enabled && stream_->AllowsAliasing();
+}
+
+int64_t EpsCopyOutputStream::ByteCount(uint8_t* ptr) const {
+  // Calculate the current offset relative to the end of the stream buffer.
+  int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes);
+  return stream_->ByteCount() - delta;
+}
+
+// Flushes what's written out to the underlying ZeroCopyOutputStream buffers.
+// Returns the size remaining in the buffer and sets buffer_end_ to the start
+// of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value)
+int EpsCopyOutputStream::Flush(uint8_t* ptr) {
+  while (buffer_end_ && ptr > end_) {
+    int overrun = ptr - end_;
+    GOOGLE_DCHECK(!had_error_);
+    GOOGLE_DCHECK(overrun <= kSlopBytes);  // NOLINT
+    ptr = Next() + overrun;
+    if (had_error_) return 0;
+  }
+  int s;
+  if (buffer_end_) {
+    std::memcpy(buffer_end_, buffer_, ptr - buffer_);
+    buffer_end_ += ptr - buffer_;
+    s = end_ - ptr;
+  } else {
+    // The stream is writing directly in the ZeroCopyOutputStream buffer.
+    s = end_ + kSlopBytes - ptr;
+    buffer_end_ = ptr;
+  }
+  GOOGLE_DCHECK(s >= 0);  // NOLINT
+  return s;
+}
+
+uint8_t* EpsCopyOutputStream::Trim(uint8_t* ptr) {
+  if (had_error_) return ptr;
+  int s = Flush(ptr);
+  stream_->BackUp(s);
+  // Reset to initial state (expecting new buffer)
+  buffer_end_ = end_ = buffer_;
+  return buffer_;
+}
+
+
+uint8_t* EpsCopyOutputStream::FlushAndResetBuffer(uint8_t* ptr) {
+  if (had_error_) return buffer_;
+  int s = Flush(ptr);
+  if (had_error_) return buffer_;
+  return SetInitialBuffer(buffer_end_, s);
+}
+
+bool EpsCopyOutputStream::Skip(int count, uint8_t** pp) {
+  if (count < 0) return false;
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  int size = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  void* data = buffer_end_;
+  while (count > size) {
+    count -= size;
+    if (!stream_->Next(&data, &size)) {
+      *pp = Error();
+      return false;
+    }
+  }
+  *pp = SetInitialBuffer(static_cast<uint8_t*>(data) + count, size - count);
+  return true;
+}
+
+bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size,
+                                                 uint8_t** pp) {
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  *size = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  *data = buffer_end_;
+  while (*size == 0) {
+    if (!stream_->Next(data, size)) {
+      *pp = Error();
+      return false;
+    }
+  }
+  *pp = SetInitialBuffer(*data, *size);
+  return true;
+}
+
+uint8_t* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size,
+                                                               uint8_t** pp) {
+  if (had_error_) {
+    *pp = buffer_;
+    return nullptr;
+  }
+  int s = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return nullptr;
+  }
+  if (s >= size) {
+    auto res = buffer_end_;
+    *pp = SetInitialBuffer(buffer_end_ + size, s - size);
+    return res;
+  } else {
+    *pp = SetInitialBuffer(buffer_end_, s);
+    return nullptr;
+  }
+}
+
+uint8_t* EpsCopyOutputStream::Next() {
+  GOOGLE_DCHECK(!had_error_);  // NOLINT
+  if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error();
+  if (buffer_end_) {
+    // We're in the patch buffer and need to fill up the previous buffer.
+    std::memcpy(buffer_end_, buffer_, end_ - buffer_);
+    uint8_t* ptr;
+    int size;
+    do {
+      void* data;
+      if (PROTOBUF_PREDICT_FALSE(!stream_->Next(&data, &size))) {
+        // Stream has an error, we use the patch buffer to continue to be
+        // able to write.
+        return Error();
+      }
+      ptr = static_cast<uint8_t*>(data);
+    } while (size == 0);
+    if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
+      std::memcpy(ptr, end_, kSlopBytes);
+      end_ = ptr + size - kSlopBytes;
+      buffer_end_ = nullptr;
+      return ptr;
+    } else {
+      GOOGLE_DCHECK(size > 0);  // NOLINT
+      // Buffer to small
+      std::memmove(buffer_, end_, kSlopBytes);
+      buffer_end_ = ptr;
+      end_ = buffer_ + size;
+      return buffer_;
+    }
+  } else {
+    std::memcpy(buffer_, end_, kSlopBytes);
+    buffer_end_ = end_;
+    end_ = buffer_ + kSlopBytes;
+    return buffer_;
+  }
+}
+
+uint8_t* EpsCopyOutputStream::EnsureSpaceFallback(uint8_t* ptr) {
+  do {
+    if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_;
+    int overrun = ptr - end_;
+    GOOGLE_DCHECK(overrun >= 0);           // NOLINT
+    GOOGLE_DCHECK(overrun <= kSlopBytes);  // NOLINT
+    ptr = Next() + overrun;
+  } while (ptr >= end_);
+  GOOGLE_DCHECK(ptr < end_);  // NOLINT
+  return ptr;
+}
+
+uint8_t* EpsCopyOutputStream::WriteRawFallback(const void* data, int size,
+                                             uint8_t* ptr) {
+  int s = GetSize(ptr);
+  while (s < size) {
+    std::memcpy(ptr, data, s);
+    size -= s;
+    data = static_cast<const uint8_t*>(data) + s;
+    ptr = EnsureSpaceFallback(ptr + s);
+    s = GetSize(ptr);
+  }
+  std::memcpy(ptr, data, size);
+  return ptr + size;
+}
+
+uint8_t* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size,
+                                            uint8_t* ptr) {
+  if (size < GetSize(ptr)
+  ) {
+    return WriteRaw(data, size, ptr);
+  } else {
+    ptr = Trim(ptr);
+    if (stream_->WriteAliasedRaw(data, size)) return ptr;
+    return Error();
+  }
+}
+
+#ifndef PROTOBUF_LITTLE_ENDIAN
+uint8_t* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size,
+                                                   uint8_t* ptr) {
+  auto p = static_cast<const uint8_t*>(data);
+  auto end = p + size;
+  while (end - p >= kSlopBytes) {
+    ptr = EnsureSpace(ptr);
+    uint32_t buffer[4];
+    static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
+    std::memcpy(buffer, p, kSlopBytes);
+    p += kSlopBytes;
+    for (auto x : buffer)
+      ptr = CodedOutputStream::WriteLittleEndian32ToArray(x, ptr);
+  }
+  while (p < end) {
+    ptr = EnsureSpace(ptr);
+    uint32_t buffer;
+    std::memcpy(&buffer, p, 4);
+    p += 4;
+    ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr);
+  }
+  return ptr;
+}
+
+uint8_t* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size,
+                                                   uint8_t* ptr) {
+  auto p = static_cast<const uint8_t*>(data);
+  auto end = p + size;
+  while (end - p >= kSlopBytes) {
+    ptr = EnsureSpace(ptr);
+    uint64_t buffer[2];
+    static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
+    std::memcpy(buffer, p, kSlopBytes);
+    p += kSlopBytes;
+    for (auto x : buffer)
+      ptr = CodedOutputStream::WriteLittleEndian64ToArray(x, ptr);
+  }
+  while (p < end) {
+    ptr = EnsureSpace(ptr);
+    uint64_t buffer;
+    std::memcpy(&buffer, p, 8);
+    p += 8;
+    ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr);
+  }
+  return ptr;
+}
+#endif
+
+
+uint8_t* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32_t num,
+                                                           const std::string& s,
+                                                           uint8_t* ptr) {
+  ptr = EnsureSpace(ptr);
+  uint32_t size = s.size();
+  ptr = WriteLengthDelim(num, size, ptr);
+  return WriteRawMaybeAliased(s.data(), size, ptr);
+}
+
+uint8_t* EpsCopyOutputStream::WriteStringOutline(uint32_t num, const std::string& s,
+                                               uint8_t* ptr) {
+  ptr = EnsureSpace(ptr);
+  uint32_t size = s.size();
+  ptr = WriteLengthDelim(num, size, ptr);
+  return WriteRaw(s.data(), size, ptr);
+}
+
+std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
+    false};
+
+CodedOutputStream::~CodedOutputStream() { Trim(); }
+
+
+uint8_t* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str,
+                                                     uint8_t* target) {
+  GOOGLE_DCHECK_LE(str.size(), std::numeric_limits<uint32_t>::max());
+  target = WriteVarint32ToArray(str.size(), target);
+  return WriteStringToArray(str, target);
+}
+
+uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLineHelper(uint32_t value,
+                                                              uint8_t* target) {
+  GOOGLE_DCHECK_GE(value, 0x80);
+  target[0] |= static_cast<uint8_t>(0x80);
+  value >>= 7;
+  target[1] = static_cast<uint8_t>(value);
+  if (value < 0x80) {
+    return target + 2;
+  }
+  target += 2;
+  do {
+    // Turn on continuation bit in the byte we just wrote.
+    target[-1] |= static_cast<uint8_t>(0x80);
+    value >>= 7;
+    *target = static_cast<uint8_t>(value);
+    ++target;
+  } while (value >= 0x80);
+  return target;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/gzip_stream.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/gzip_stream.cpp
new file mode 100644
index 0000000..a5284b3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/gzip_stream.cpp
@@ -0,0 +1,334 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: brianolson@google.com (Brian Olson)
+//
+// This file contains the implementation of classes GzipInputStream and
+// GzipOutputStream.
+
+
+#if HAVE_ZLIB
+#include <google/protobuf/io/gzip_stream.h>
+#include <google/protobuf/port.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+static const int kDefaultBufferSize = 65536;
+
+GzipInputStream::GzipInputStream(ZeroCopyInputStream* sub_stream, Format format,
+                                 int buffer_size)
+    : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
+  zcontext_.state = Z_NULL;
+  zcontext_.zalloc = Z_NULL;
+  zcontext_.zfree = Z_NULL;
+  zcontext_.opaque = Z_NULL;
+  zcontext_.total_out = 0;
+  zcontext_.next_in = NULL;
+  zcontext_.avail_in = 0;
+  zcontext_.total_in = 0;
+  zcontext_.msg = NULL;
+  if (buffer_size == -1) {
+    output_buffer_length_ = kDefaultBufferSize;
+  } else {
+    output_buffer_length_ = buffer_size;
+  }
+  output_buffer_ = operator new(output_buffer_length_);
+  GOOGLE_CHECK(output_buffer_ != NULL);
+  zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
+  zcontext_.avail_out = output_buffer_length_;
+  output_position_ = output_buffer_;
+}
+GzipInputStream::~GzipInputStream() {
+  internal::SizedDelete(output_buffer_, output_buffer_length_);
+  zerror_ = inflateEnd(&zcontext_);
+}
+
+static inline int internalInflateInit2(z_stream* zcontext,
+                                       GzipInputStream::Format format) {
+  int windowBitsFormat = 0;
+  switch (format) {
+    case GzipInputStream::GZIP:
+      windowBitsFormat = 16;
+      break;
+    case GzipInputStream::AUTO:
+      windowBitsFormat = 32;
+      break;
+    case GzipInputStream::ZLIB:
+      windowBitsFormat = 0;
+      break;
+  }
+  return inflateInit2(zcontext, /* windowBits */ 15 | windowBitsFormat);
+}
+
+int GzipInputStream::Inflate(int flush) {
+  if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
+    // previous inflate filled output buffer. don't change input params yet.
+  } else if (zcontext_.avail_in == 0) {
+    const void* in;
+    int in_size;
+    bool first = zcontext_.next_in == NULL;
+    bool ok = sub_stream_->Next(&in, &in_size);
+    if (!ok) {
+      zcontext_.next_out = NULL;
+      zcontext_.avail_out = 0;
+      return Z_STREAM_END;
+    }
+    zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
+    zcontext_.avail_in = in_size;
+    if (first) {
+      int error = internalInflateInit2(&zcontext_, format_);
+      if (error != Z_OK) {
+        return error;
+      }
+    }
+  }
+  zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
+  zcontext_.avail_out = output_buffer_length_;
+  output_position_ = output_buffer_;
+  int error = inflate(&zcontext_, flush);
+  return error;
+}
+
+void GzipInputStream::DoNextOutput(const void** data, int* size) {
+  *data = output_position_;
+  *size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
+  output_position_ = zcontext_.next_out;
+}
+
+// implements ZeroCopyInputStream ----------------------------------
+bool GzipInputStream::Next(const void** data, int* size) {
+  bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) ||
+            (zerror_ == Z_BUF_ERROR);
+  if ((!ok) || (zcontext_.next_out == NULL)) {
+    return false;
+  }
+  if (zcontext_.next_out != output_position_) {
+    DoNextOutput(data, size);
+    return true;
+  }
+  if (zerror_ == Z_STREAM_END) {
+    if (zcontext_.next_out != NULL) {
+      // sub_stream_ may have concatenated streams to follow
+      zerror_ = inflateEnd(&zcontext_);
+      byte_count_ += zcontext_.total_out;
+      if (zerror_ != Z_OK) {
+        return false;
+      }
+      zerror_ = internalInflateInit2(&zcontext_, format_);
+      if (zerror_ != Z_OK) {
+        return false;
+      }
+    } else {
+      *data = NULL;
+      *size = 0;
+      return false;
+    }
+  }
+  zerror_ = Inflate(Z_NO_FLUSH);
+  if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
+    // The underlying stream's Next returned false inside Inflate.
+    return false;
+  }
+  ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) ||
+       (zerror_ == Z_BUF_ERROR);
+  if (!ok) {
+    return false;
+  }
+  DoNextOutput(data, size);
+  return true;
+}
+void GzipInputStream::BackUp(int count) {
+  output_position_ = reinterpret_cast<void*>(
+      reinterpret_cast<uintptr_t>(output_position_) - count);
+}
+bool GzipInputStream::Skip(int count) {
+  const void* data;
+  int size = 0;
+  bool ok = Next(&data, &size);
+  while (ok && (size < count)) {
+    count -= size;
+    ok = Next(&data, &size);
+  }
+  if (size > count) {
+    BackUp(size - count);
+  }
+  return ok;
+}
+int64_t GzipInputStream::ByteCount() const {
+  int64_t ret = byte_count_ + zcontext_.total_out;
+  if (zcontext_.next_out != NULL && output_position_ != NULL) {
+    ret += reinterpret_cast<uintptr_t>(zcontext_.next_out) -
+           reinterpret_cast<uintptr_t>(output_position_);
+  }
+  return ret;
+}
+
+// =========================================================================
+
+GzipOutputStream::Options::Options()
+    : format(GZIP),
+      buffer_size(kDefaultBufferSize),
+      compression_level(Z_DEFAULT_COMPRESSION),
+      compression_strategy(Z_DEFAULT_STRATEGY) {}
+
+GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
+  Init(sub_stream, Options());
+}
+
+GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
+                                   const Options& options) {
+  Init(sub_stream, options);
+}
+
+void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
+                            const Options& options) {
+  sub_stream_ = sub_stream;
+  sub_data_ = NULL;
+  sub_data_size_ = 0;
+
+  input_buffer_length_ = options.buffer_size;
+  input_buffer_ = operator new(input_buffer_length_);
+  GOOGLE_CHECK(input_buffer_ != NULL);
+
+  zcontext_.zalloc = Z_NULL;
+  zcontext_.zfree = Z_NULL;
+  zcontext_.opaque = Z_NULL;
+  zcontext_.next_out = NULL;
+  zcontext_.avail_out = 0;
+  zcontext_.total_out = 0;
+  zcontext_.next_in = NULL;
+  zcontext_.avail_in = 0;
+  zcontext_.total_in = 0;
+  zcontext_.msg = NULL;
+  // default to GZIP format
+  int windowBitsFormat = 16;
+  if (options.format == ZLIB) {
+    windowBitsFormat = 0;
+  }
+  zerror_ =
+      deflateInit2(&zcontext_, options.compression_level, Z_DEFLATED,
+                   /* windowBits */ 15 | windowBitsFormat,
+                   /* memLevel (default) */ 8, options.compression_strategy);
+}
+
+GzipOutputStream::~GzipOutputStream() {
+  Close();
+  internal::SizedDelete(input_buffer_, input_buffer_length_);
+}
+
+// private
+int GzipOutputStream::Deflate(int flush) {
+  int error = Z_OK;
+  do {
+    if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
+      bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
+      if (!ok) {
+        sub_data_ = NULL;
+        sub_data_size_ = 0;
+        return Z_BUF_ERROR;
+      }
+      GOOGLE_CHECK_GT(sub_data_size_, 0);
+      zcontext_.next_out = static_cast<Bytef*>(sub_data_);
+      zcontext_.avail_out = sub_data_size_;
+    }
+    error = deflate(&zcontext_, flush);
+  } while (error == Z_OK && zcontext_.avail_out == 0);
+  if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) {
+    // Notify lower layer of data.
+    sub_stream_->BackUp(zcontext_.avail_out);
+    // We don't own the buffer anymore.
+    sub_data_ = NULL;
+    sub_data_size_ = 0;
+  }
+  return error;
+}
+
+// implements ZeroCopyOutputStream ---------------------------------
+bool GzipOutputStream::Next(void** data, int* size) {
+  if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
+    return false;
+  }
+  if (zcontext_.avail_in != 0) {
+    zerror_ = Deflate(Z_NO_FLUSH);
+    if (zerror_ != Z_OK) {
+      return false;
+    }
+  }
+  if (zcontext_.avail_in == 0) {
+    // all input was consumed. reset the buffer.
+    zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
+    zcontext_.avail_in = input_buffer_length_;
+    *data = input_buffer_;
+    *size = input_buffer_length_;
+  } else {
+    // The loop in Deflate should consume all avail_in
+    GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
+  }
+  return true;
+}
+void GzipOutputStream::BackUp(int count) {
+  GOOGLE_CHECK_GE(zcontext_.avail_in, static_cast<uInt>(count));
+  zcontext_.avail_in -= count;
+}
+int64_t GzipOutputStream::ByteCount() const {
+  return zcontext_.total_in + zcontext_.avail_in;
+}
+
+bool GzipOutputStream::Flush() {
+  zerror_ = Deflate(Z_FULL_FLUSH);
+  // Return true if the flush succeeded or if it was a no-op.
+  return (zerror_ == Z_OK) ||
+         (zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
+          zcontext_.avail_out != 0);
+}
+
+bool GzipOutputStream::Close() {
+  if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
+    return false;
+  }
+  do {
+    zerror_ = Deflate(Z_FINISH);
+  } while (zerror_ == Z_OK);
+  zerror_ = deflateEnd(&zcontext_);
+  bool ok = zerror_ == Z_OK;
+  zerror_ = Z_STREAM_END;
+  return ok;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // HAVE_ZLIB
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/io_win32.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/io_win32.cpp
new file mode 100644
index 0000000..78c07d0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/io_win32.cpp
@@ -0,0 +1,471 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: laszlocsomor@google.com (Laszlo Csomor)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+// Implementation for long-path-aware open/mkdir/access/etc. on Windows, as well
+// as for the supporting utility functions.
+//
+// These functions convert the input path to an absolute Windows path
+// with "\\?\" prefix, then pass that to _wopen/_wmkdir/_waccess/etc.
+// (declared in <io.h>) respectively. This allows working with files/directories
+// whose paths are longer than MAX_PATH (260 chars).
+//
+// This file is only used on Windows, it's empty on other platforms.
+
+#if defined(_WIN32) && !defined(_XBOX_ONE)
+
+// Comment this out to fall back to using the ANSI versions (open, mkdir, ...)
+// instead of the Unicode ones (_wopen, _wmkdir, ...). Doing so can be useful to
+// debug failing tests if that's caused by the long path support.
+#define SUPPORT_LONGPATHS
+
+#include <google/protobuf/io/io_win32.h>
+
+#include <ctype.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <wctype.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+
+#include <windows.h>
+
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace win32 {
+namespace {
+
+using std::string;
+using std::wstring;
+
+template <typename char_type>
+struct CharTraits {
+  static bool is_alpha(char_type ch);
+};
+
+template <>
+struct CharTraits<char> {
+  static bool is_alpha(char ch) { return isalpha(ch); }
+};
+
+template <>
+struct CharTraits<wchar_t> {
+  static bool is_alpha(wchar_t ch) { return iswalpha(ch); }
+};
+
+template <typename char_type>
+bool null_or_empty(const char_type* s) {
+  return s == nullptr || *s == 0;
+}
+
+// Returns true if the path starts with a drive letter, e.g. "c:".
+// Note that this won't check for the "\" after the drive letter, so this also
+// returns true for "c:foo" (which is "c:\${PWD}\foo").
+// This check requires that a path not have a longpath prefix ("\\?\").
+template <typename char_type>
+bool has_drive_letter(const char_type* ch) {
+  return CharTraits<char_type>::is_alpha(ch[0]) && ch[1] == ':';
+}
+
+// Returns true if the path starts with a longpath prefix ("\\?\").
+template <typename char_type>
+bool has_longpath_prefix(const char_type* path) {
+  return path[0] == '\\' && path[1] == '\\' && path[2] == '?' &&
+         path[3] == '\\';
+}
+
+template <typename char_type>
+bool is_separator(char_type c) {
+  return c == '/' || c == '\\';
+}
+
+// Returns true if the path starts with a drive specifier (e.g. "c:\").
+template <typename char_type>
+bool is_path_absolute(const char_type* path) {
+  return has_drive_letter(path) && is_separator(path[2]);
+}
+
+template <typename char_type>
+bool is_drive_relative(const char_type* path) {
+  return has_drive_letter(path) && (path[2] == 0 || !is_separator(path[2]));
+}
+
+wstring join_paths(const wstring& path1, const wstring& path2) {
+  if (path1.empty() || is_path_absolute(path2.c_str()) ||
+      has_longpath_prefix(path2.c_str())) {
+    return path2;
+  }
+  if (path2.empty()) {
+    return path1;
+  }
+
+  if (is_separator(path1[path1.size() - 1])) {
+    return is_separator(path2[0]) ? (path1 + path2.substr(1))
+                                       : (path1 + path2);
+  } else {
+    return is_separator(path2[0]) ? (path1 + path2)
+                                       : (path1 + L'\\' + path2);
+  }
+}
+
+wstring normalize(wstring path) {
+  if (has_longpath_prefix(path.c_str())) {
+    path = path.substr(4);
+  }
+
+  static const wstring dot(L".");
+  static const wstring dotdot(L"..");
+  const WCHAR* p = path.c_str();
+
+  std::vector<wstring> segments;
+  int segment_start = -1;
+  // Find the path segments in `path` (separated by "/").
+  for (int i = 0;; ++i) {
+    if (!is_separator(p[i]) && p[i] != L'\0') {
+      // The current character does not end a segment, so start one unless it's
+      // already started.
+      if (segment_start < 0) {
+        segment_start = i;
+      }
+    } else if (segment_start >= 0 && i > segment_start) {
+      // The current character is "/" or "\0", so this ends a segment.
+      // Add that to `segments` if there's anything to add; handle "." and "..".
+      wstring segment(p, segment_start, i - segment_start);
+      segment_start = -1;
+      if (segment == dotdot) {
+        if (!segments.empty() &&
+            (!has_drive_letter(segments[0].c_str()) || segments.size() > 1)) {
+          segments.pop_back();
+        }
+      } else if (segment != dot && !segment.empty()) {
+        segments.push_back(segment);
+      }
+    }
+    if (p[i] == L'\0') {
+      break;
+    }
+  }
+
+  // Handle the case when `path` is just a drive specifier (or some degenerate
+  // form of it, e.g. "c:\..").
+  if (segments.size() == 1 && segments[0].size() == 2 &&
+      has_drive_letter(segments[0].c_str())) {
+    return segments[0] + L'\\';
+  }
+
+  // Join all segments.
+  bool first = true;
+  std::wstringstream result;
+  for (size_t i = 0; i < segments.size(); ++i) {
+    if (!first) {
+      result << L'\\';
+    }
+    first = false;
+    result << segments[i];
+  }
+  // Preserve trailing separator if the input contained it.
+  if (!path.empty() && is_separator(p[path.size() - 1])) {
+    result << L'\\';
+  }
+  return result.str();
+}
+
+bool as_windows_path(const char* path, wstring* result) {
+  if (null_or_empty(path)) {
+    result->clear();
+    return true;
+  }
+  wstring wpath;
+  if (!strings::utf8_to_wcs(path, &wpath)) {
+    return false;
+  }
+  if (has_longpath_prefix(wpath.c_str())) {
+    *result = wpath;
+    return true;
+  }
+  if (is_separator(path[0]) || is_drive_relative(path)) {
+    return false;
+  }
+
+
+  if (!is_path_absolute(wpath.c_str())) {
+    int size = ::GetCurrentDirectoryW(0, nullptr);
+    if (size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+      return false;
+    }
+    std::unique_ptr<WCHAR[]> wcwd(new WCHAR[size]);
+    ::GetCurrentDirectoryW(size, wcwd.get());
+    wpath = join_paths(wcwd.get(), wpath);
+  }
+  wpath = normalize(wpath);
+  if (!has_longpath_prefix(wpath.c_str())) {
+    // Add the "\\?\" prefix unconditionally. This way we prevent the Win32 API
+    // from processing the path and "helpfully" removing trailing dots from the
+    // path, for example.
+    // See https://github.com/bazelbuild/bazel/issues/2935
+    wpath = wstring(L"\\\\?\\") + wpath;
+  }
+  *result = wpath;
+  return true;
+}
+
+}  // namespace
+
+int open(const char* path, int flags, int mode) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wopen(wpath.c_str(), flags, mode);
+#else
+  return ::_open(path, flags, mode);
+#endif
+}
+
+int mkdir(const char* path, int /*_mode*/) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wmkdir(wpath.c_str());
+#else   // not SUPPORT_LONGPATHS
+  return ::_mkdir(path);
+#endif  // not SUPPORT_LONGPATHS
+}
+
+int access(const char* path, int mode) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_waccess(wpath.c_str(), mode);
+#else
+  return ::_access(path, mode);
+#endif
+}
+
+int chdir(const char* path) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wchdir(wpath.c_str());
+#else
+  return ::_chdir(path);
+#endif
+}
+
+int stat(const char* path, struct _stat* buffer) {
+#ifdef SUPPORT_LONGPATHS
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return -1;
+  }
+  return ::_wstat(wpath.c_str(), buffer);
+#else   // not SUPPORT_LONGPATHS
+  return ::_stat(path, buffer);
+#endif  // not SUPPORT_LONGPATHS
+}
+
+FILE* fopen(const char* path, const char* mode) {
+#ifdef SUPPORT_LONGPATHS
+  if (null_or_empty(path)) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  wstring wpath;
+  if (!as_windows_path(path, &wpath)) {
+    errno = ENOENT;
+    return nullptr;
+  }
+  wstring wmode;
+  if (!strings::utf8_to_wcs(mode, &wmode)) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  return ::_wfopen(wpath.c_str(), wmode.c_str());
+#else
+  return ::fopen(path, mode);
+#endif
+}
+
+int close(int fd) { return ::_close(fd); }
+
+int dup(int fd) { return ::_dup(fd); }
+
+int dup2(int fd1, int fd2) { return ::_dup2(fd1, fd2); }
+
+int read(int fd, void* buffer, size_t size) {
+  return ::_read(fd, buffer, size);
+}
+
+int setmode(int fd, int mode) { return ::_setmode(fd, mode); }
+
+int write(int fd, const void* buffer, size_t size) {
+  return ::_write(fd, buffer, size);
+}
+
+wstring testonly_utf8_to_winpath(const char* path) {
+  wstring wpath;
+  return as_windows_path(path, &wpath) ? wpath : wstring();
+}
+
+ExpandWildcardsResult ExpandWildcards(
+    const string& path, std::function<void(const string&)> consume) {
+  if (path.find_first_of("*?") == string::npos) {
+    // There are no wildcards in the path, we don't need to expand it.
+    consume(path);
+    return ExpandWildcardsResult::kSuccess;
+  }
+
+  wstring wpath;
+  if (!as_windows_path(path.c_str(), &wpath)) {
+    return ExpandWildcardsResult::kErrorInputPathConversion;
+  }
+
+  static const wstring kDot = L".";
+  static const wstring kDotDot = L"..";
+  WIN32_FIND_DATAW metadata;
+  HANDLE handle = ::FindFirstFileW(wpath.c_str(), &metadata);
+  if (handle == INVALID_HANDLE_VALUE) {
+    // The pattern does not match any files (or directories).
+    return ExpandWildcardsResult::kErrorNoMatchingFile;
+  }
+
+  string::size_type pos = path.find_last_of("\\/");
+  string dirname;
+  if (pos != string::npos) {
+    dirname = path.substr(0, pos + 1);
+  }
+
+  ExpandWildcardsResult matched = ExpandWildcardsResult::kErrorNoMatchingFile;
+  do {
+    // Ignore ".", "..", and directories.
+    if ((metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 &&
+        kDot != metadata.cFileName && kDotDot != metadata.cFileName) {
+      matched = ExpandWildcardsResult::kSuccess;
+      string filename;
+      if (!strings::wcs_to_utf8(metadata.cFileName, &filename)) {
+        matched = ExpandWildcardsResult::kErrorOutputPathConversion;
+        break;
+      }
+
+      if (dirname.empty()) {
+        consume(filename);
+      } else {
+        consume(dirname + filename);
+      }
+    }
+  } while (::FindNextFileW(handle, &metadata));
+  FindClose(handle);
+  return matched;
+}
+
+namespace strings {
+
+bool wcs_to_mbs(const WCHAR* s, string* out, bool outUtf8) {
+  if (null_or_empty(s)) {
+    out->clear();
+    return true;
+  }
+  BOOL usedDefaultChar = FALSE;
+  SetLastError(0);
+  int size = WideCharToMultiByte(
+      outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, nullptr, 0, nullptr,
+      outUtf8 ? nullptr : &usedDefaultChar);
+  if ((size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+      || usedDefaultChar) {
+    return false;
+  }
+  std::unique_ptr<CHAR[]> astr(new CHAR[size]);
+  WideCharToMultiByte(
+      outUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, astr.get(), size, nullptr, nullptr);
+  out->assign(astr.get());
+  return true;
+}
+
+bool mbs_to_wcs(const char* s, wstring* out, bool inUtf8) {
+  if (null_or_empty(s)) {
+    out->clear();
+    return true;
+  }
+
+  SetLastError(0);
+  int size =
+      MultiByteToWideChar(inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, nullptr, 0);
+  if (size == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return false;
+  }
+  std::unique_ptr<WCHAR[]> wstr(new WCHAR[size]);
+  MultiByteToWideChar(
+      inUtf8 ? CP_UTF8 : CP_ACP, 0, s, -1, wstr.get(), size + 1);
+  out->assign(wstr.get());
+  return true;
+}
+
+bool utf8_to_wcs(const char* input, wstring* out) {
+  return mbs_to_wcs(input, out, true);
+}
+
+bool wcs_to_utf8(const wchar_t* input, string* out) {
+  return wcs_to_mbs(input, out, true);
+}
+
+}  // namespace strings
+}  // namespace win32
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // defined(_WIN32)
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/printer.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/printer.cpp
new file mode 100644
index 0000000..47bd00b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/printer.cpp
@@ -0,0 +1,403 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/io/printer.h>
+
+#include <cctype>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
+    : variable_delimiter_(variable_delimiter),
+      output_(output),
+      buffer_(NULL),
+      buffer_size_(0),
+      offset_(0),
+      at_start_of_line_(true),
+      failed_(false),
+      annotation_collector_(NULL) {}
+
+Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
+                 AnnotationCollector* annotation_collector)
+    : variable_delimiter_(variable_delimiter),
+      output_(output),
+      buffer_(NULL),
+      buffer_size_(0),
+      offset_(0),
+      at_start_of_line_(true),
+      failed_(false),
+      annotation_collector_(annotation_collector) {}
+
+Printer::~Printer() {
+  // Only BackUp() if we invoked Next() at least once, and we have never failed.
+  // Note that we always call `Backup`, i.e. we call BackUp(0) as some output
+  // streams have buffered output, and BackUp() serves as a flush event in such
+  // implementations.
+  if (buffer_ != nullptr && !failed_) {
+    output_->BackUp(buffer_size_);
+  }
+}
+
+bool Printer::GetSubstitutionRange(const char* varname,
+                                   std::pair<size_t, size_t>* range) {
+  std::map<std::string, std::pair<size_t, size_t> >::const_iterator iter =
+      substitutions_.find(varname);
+  if (iter == substitutions_.end()) {
+    GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
+    return false;
+  }
+  if (iter->second.first > iter->second.second) {
+    GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
+                << varname;
+    return false;
+  }
+  *range = iter->second;
+  return true;
+}
+
+void Printer::Annotate(const char* begin_varname, const char* end_varname,
+                       const std::string& file_path,
+                       const std::vector<int>& path) {
+  if (annotation_collector_ == NULL) {
+    // Can't generate signatures with this Printer.
+    return;
+  }
+  std::pair<size_t, size_t> begin, end;
+  if (!GetSubstitutionRange(begin_varname, &begin) ||
+      !GetSubstitutionRange(end_varname, &end)) {
+    return;
+  }
+  if (begin.first > end.second) {
+    GOOGLE_LOG(DFATAL) << "  Annotation has negative length from " << begin_varname
+                << " to " << end_varname;
+  } else {
+    annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
+                                         path);
+  }
+}
+
+void Printer::Print(const std::map<std::string, std::string>& variables,
+                    const char* text) {
+  int size = strlen(text);
+  int pos = 0;  // The number of bytes we've written so far.
+  substitutions_.clear();
+  line_start_variables_.clear();
+
+  for (int i = 0; i < size; i++) {
+    if (text[i] == '\n') {
+      // Saw newline.  If there is more text, we may need to insert an indent
+      // here.  So, write what we have so far, including the '\n'.
+      WriteRaw(text + pos, i - pos + 1);
+      pos = i + 1;
+
+      // Setting this true will cause the next WriteRaw() to insert an indent
+      // first.
+      at_start_of_line_ = true;
+      line_start_variables_.clear();
+
+    } else if (text[i] == variable_delimiter_) {
+      // Saw the start of a variable name.
+
+      // Write what we have so far.
+      WriteRaw(text + pos, i - pos);
+      pos = i + 1;
+
+      // Find closing delimiter.
+      const char* end = strchr(text + pos, variable_delimiter_);
+      if (end == NULL) {
+        GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
+        end = text + pos;
+      }
+      int endpos = end - text;
+
+      std::string varname(text + pos, endpos - pos);
+      if (varname.empty()) {
+        // Two delimiters in a row reduce to a literal delimiter character.
+        WriteRaw(&variable_delimiter_, 1);
+      } else {
+        // Replace with the variable's value.
+        std::map<std::string, std::string>::const_iterator iter =
+            variables.find(varname);
+        if (iter == variables.end()) {
+          GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
+        } else {
+          if (at_start_of_line_ && iter->second.empty()) {
+            line_start_variables_.push_back(varname);
+          }
+          WriteRaw(iter->second.data(), iter->second.size());
+          std::pair<std::map<std::string, std::pair<size_t, size_t> >::iterator,
+                    bool>
+              inserted = substitutions_.insert(std::make_pair(
+                  varname,
+                  std::make_pair(offset_ - iter->second.size(), offset_)));
+          if (!inserted.second) {
+            // This variable was used multiple times.  Make its span have
+            // negative length so we can detect it if it gets used in an
+            // annotation.
+            inserted.first->second = std::make_pair(1, 0);
+          }
+        }
+      }
+
+      // Advance past this variable.
+      i = endpos;
+      pos = endpos + 1;
+    }
+  }
+
+  // Write the rest.
+  WriteRaw(text + pos, size - pos);
+}
+
+void Printer::Indent() { indent_ += "  "; }
+
+void Printer::Outdent() {
+  if (indent_.empty()) {
+    GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
+    return;
+  }
+
+  indent_.resize(indent_.size() - 2);
+}
+
+void Printer::PrintRaw(const std::string& data) {
+  WriteRaw(data.data(), data.size());
+}
+
+void Printer::PrintRaw(const char* data) {
+  if (failed_) return;
+  WriteRaw(data, strlen(data));
+}
+
+void Printer::WriteRaw(const char* data, int size) {
+  if (failed_) return;
+  if (size == 0) return;
+
+  if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
+    // Insert an indent.
+    at_start_of_line_ = false;
+    CopyToBuffer(indent_.data(), indent_.size());
+    if (failed_) return;
+    // Fix up empty variables (e.g., "{") that should be annotated as
+    // coming after the indent.
+    for (std::vector<std::string>::iterator i = line_start_variables_.begin();
+         i != line_start_variables_.end(); ++i) {
+      substitutions_[*i].first += indent_.size();
+      substitutions_[*i].second += indent_.size();
+    }
+  }
+
+  // If we're going to write any data, clear line_start_variables_, since
+  // we've either updated them in the block above or they no longer refer to
+  // the current line.
+  line_start_variables_.clear();
+
+  CopyToBuffer(data, size);
+}
+
+bool Printer::Next() {
+  do {
+    void* void_buffer;
+    if (!output_->Next(&void_buffer, &buffer_size_)) {
+      failed_ = true;
+      return false;
+    }
+    buffer_ = reinterpret_cast<char*>(void_buffer);
+  } while (buffer_size_ == 0);
+  return true;
+}
+
+void Printer::CopyToBuffer(const char* data, int size) {
+  if (failed_) return;
+  if (size == 0) return;
+
+  while (size > buffer_size_) {
+    // Data exceeds space in the buffer.  Copy what we can and request a
+    // new buffer.
+    if (buffer_size_ > 0) {
+      memcpy(buffer_, data, buffer_size_);
+      offset_ += buffer_size_;
+      data += buffer_size_;
+      size -= buffer_size_;
+    }
+    void* void_buffer;
+    failed_ = !output_->Next(&void_buffer, &buffer_size_);
+    if (failed_) return;
+    buffer_ = reinterpret_cast<char*>(void_buffer);
+  }
+
+  // Buffer is big enough to receive the data; copy it.
+  memcpy(buffer_, data, size);
+  buffer_ += size;
+  buffer_size_ -= size;
+  offset_ += size;
+}
+
+void Printer::IndentIfAtStart() {
+  if (at_start_of_line_) {
+    CopyToBuffer(indent_.data(), indent_.size());
+    at_start_of_line_ = false;
+  }
+}
+
+void Printer::FormatInternal(const std::vector<std::string>& args,
+                             const std::map<std::string, std::string>& vars,
+                             const char* format) {
+  auto save = format;
+  int arg_index = 0;
+  std::vector<AnnotationCollector::Annotation> annotations;
+  while (*format) {
+    char c = *format++;
+    switch (c) {
+      case '$':
+        format = WriteVariable(args, vars, format, &arg_index, &annotations);
+        continue;
+      case '\n':
+        at_start_of_line_ = true;
+        line_start_variables_.clear();
+        break;
+      default:
+        IndentIfAtStart();
+        break;
+    }
+    push_back(c);
+  }
+  if (arg_index != static_cast<int>(args.size())) {
+    GOOGLE_LOG(FATAL) << " Unused arguments. " << save;
+  }
+  if (!annotations.empty()) {
+    GOOGLE_LOG(FATAL) << " Annotation range is not-closed, expect $}$. " << save;
+  }
+}
+
+const char* Printer::WriteVariable(
+    const std::vector<std::string>& args,
+    const std::map<std::string, std::string>& vars, const char* format,
+    int* arg_index, std::vector<AnnotationCollector::Annotation>* annotations) {
+  auto start = format;
+  auto end = strchr(format, '$');
+  if (!end) {
+    GOOGLE_LOG(FATAL) << " Unclosed variable name.";
+  }
+  format = end + 1;
+  if (end == start) {
+    // "$$" is an escape for just '$'
+    IndentIfAtStart();
+    push_back('$');
+    return format;
+  }
+  if (*start == '{') {
+    GOOGLE_CHECK(std::isdigit(start[1]));
+    GOOGLE_CHECK_EQ(end - start, 2);
+    int idx = start[1] - '1';
+    if (idx < 0 || static_cast<size_t>(idx) >= args.size()) {
+      GOOGLE_LOG(FATAL) << "Annotation ${" << idx + 1 << "$ is out of bounds.";
+    }
+    if (idx > *arg_index) {
+      GOOGLE_LOG(FATAL) << "Annotation arg must be in correct order as given. Expected"
+                 << " ${" << (*arg_index) + 1 << "$ got ${" << idx + 1 << "$.";
+    } else if (idx == *arg_index) {
+      (*arg_index)++;
+    }
+    IndentIfAtStart();
+    annotations->push_back({{offset_, 0}, args[idx]});
+    return format;
+  } else if (*start == '}') {
+    GOOGLE_CHECK(annotations);
+    if (annotations->empty()) {
+      GOOGLE_LOG(FATAL) << "Unexpected end of annotation found.";
+    }
+    auto& a = annotations->back();
+    a.first.second = offset_;
+    if (annotation_collector_) annotation_collector_->AddAnnotationNew(a);
+    annotations->pop_back();
+    return format;
+  }
+  auto start_var = start;
+  while (start_var < end && *start_var == ' ') start_var++;
+  if (start_var == end) {
+    GOOGLE_LOG(FATAL) << " Empty variable.";
+  }
+  auto end_var = end;
+  while (start_var < end_var && *(end_var - 1) == ' ') end_var--;
+  std::string var_name{
+      start_var, static_cast<std::string::size_type>(end_var - start_var)};
+  std::string sub;
+  if (std::isdigit(var_name[0])) {
+    GOOGLE_CHECK_EQ(var_name.size(), 1U);  // No need for multi-digits
+    int idx = var_name[0] - '1';   // Start counting at 1
+    GOOGLE_CHECK_GE(idx, 0);
+    if (static_cast<size_t>(idx) >= args.size()) {
+      GOOGLE_LOG(FATAL) << "Argument $" << idx + 1 << "$ is out of bounds.";
+    }
+    if (idx > *arg_index) {
+      GOOGLE_LOG(FATAL) << "Arguments must be used in same order as given. Expected $"
+                 << (*arg_index) + 1 << "$ got $" << idx + 1 << "$.";
+    } else if (idx == *arg_index) {
+      (*arg_index)++;
+    }
+    sub = args[idx];
+  } else {
+    auto it = vars.find(var_name);
+    if (it == vars.end()) {
+      GOOGLE_LOG(FATAL) << " Unknown variable: " << var_name << ".";
+    }
+    sub = it->second;
+  }
+
+  // By returning here in case of empty we also skip possible spaces inside
+  // the $...$, i.e. "void$ dllexpor$ f();" -> "void f();" in the empty case.
+  if (sub.empty()) return format;
+
+  // We're going to write something non-empty so we need a possible indent.
+  IndentIfAtStart();
+
+  // Write the possible spaces in front.
+  CopyToBuffer(start, start_var - start);
+  // Write a non-empty substituted variable.
+  CopyToBuffer(sub.c_str(), sub.size());
+  // Finish off with writing possible trailing spaces.
+  CopyToBuffer(end_var, end - end_var);
+  return format;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/strtod.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/strtod.cpp
new file mode 100644
index 0000000..03acb5b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/strtod.cpp
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/io/strtod.h>
+
+#include <cstdio>
+#include <cstring>
+#include <limits>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+// This approximately 0x1.ffffffp127, but we don't use 0x1.ffffffp127 because
+// it won't compile in MSVC.
+const double MAX_FLOAT_AS_DOUBLE_ROUNDED = 3.4028235677973366e+38;
+
+float SafeDoubleToFloat(double value) {
+  // static_cast<float> on a number larger than float can result in illegal
+  // instruction error, so we need to manually convert it to infinity or max.
+  if (value > std::numeric_limits<float>::max()) {
+    // Max float value is about 3.4028234664E38 when represented as a double.
+    // However, when printing float as text, it will be rounded as
+    // 3.4028235e+38. If we parse the value of 3.4028235e+38 from text and
+    // compare it to 3.4028234664E38, we may think that it is larger, but
+    // actually, any number between these two numbers could only be represented
+    // as the same max float number in float, so we should treat them the same
+    // as max float.
+    if (value <= MAX_FLOAT_AS_DOUBLE_ROUNDED) {
+      return std::numeric_limits<float>::max();
+    }
+    return std::numeric_limits<float>::infinity();
+  } else if (value < -std::numeric_limits<float>::max()) {
+    if (value >= -MAX_FLOAT_AS_DOUBLE_ROUNDED) {
+      return -std::numeric_limits<float>::max();
+    }
+    return -std::numeric_limits<float>::infinity();
+  } else {
+    return static_cast<float>(value);
+  }
+}
+
+double NoLocaleStrtod(const char* str, char** endptr) {
+  return google::protobuf::internal::NoLocaleStrtod(str, endptr);
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/tokenizer.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/tokenizer.cpp
new file mode 100644
index 0000000..30d62ac
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/tokenizer.cpp
@@ -0,0 +1,1246 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Here we have a hand-written lexer.  At first you might ask yourself,
+// "Hand-written text processing?  Is Kenton crazy?!"  Well, first of all,
+// yes I am crazy, but that's beside the point.  There are actually reasons
+// why I ended up writing this this way.
+//
+// The traditional approach to lexing is to use lex to generate a lexer for
+// you.  Unfortunately, lex's output is ridiculously ugly and difficult to
+// integrate cleanly with C++ code, especially abstract code or code meant
+// as a library.  Better parser-generators exist but would add dependencies
+// which most users won't already have, which we'd like to avoid.  (GNU flex
+// has a C++ output option, but it's still ridiculously ugly, non-abstract,
+// and not library-friendly.)
+//
+// The next approach that any good software engineer should look at is to
+// use regular expressions.  And, indeed, I did.  I have code which
+// implements this same class using regular expressions.  It's about 200
+// lines shorter.  However:
+// - Rather than error messages telling you "This string has an invalid
+//   escape sequence at line 5, column 45", you get error messages like
+//   "Parse error on line 5".  Giving more precise errors requires adding
+//   a lot of code that ends up basically as complex as the hand-coded
+//   version anyway.
+// - The regular expression to match a string literal looks like this:
+//     kString  = new RE("(\"([^\"\\\\]|"              // non-escaped
+//                       "\\\\[abfnrtv?\"'\\\\0-7]|"   // normal escape
+//                       "\\\\x[0-9a-fA-F])*\"|"       // hex escape
+//                       "\'([^\'\\\\]|"        // Also support single-quotes.
+//                       "\\\\[abfnrtv?\"'\\\\0-7]|"
+//                       "\\\\x[0-9a-fA-F])*\')");
+//   Verifying the correctness of this line noise is actually harder than
+//   verifying the correctness of ConsumeString(), defined below.  I'm not
+//   even confident that the above is correct, after staring at it for some
+//   time.
+// - PCRE is fast, but there's still more overhead involved than the code
+//   below.
+// - Sadly, regular expressions are not part of the C standard library, so
+//   using them would require depending on some other library.  For the
+//   open source release, this could be really annoying.  Nobody likes
+//   downloading one piece of software just to find that they need to
+//   download something else to make it work, and in all likelihood
+//   people downloading Protocol Buffers will already be doing so just
+//   to make something else work.  We could include a copy of PCRE with
+//   our code, but that obligates us to keep it up-to-date and just seems
+//   like a big waste just to save 200 lines of code.
+//
+// On a similar but unrelated note, I'm even scared to use ctype.h.
+// Apparently functions like isalpha() are locale-dependent.  So, if we used
+// that, then if this code is being called from some program that doesn't
+// have its locale set to "C", it would behave strangely.  We can't just set
+// the locale to "C" ourselves since we might break the calling program that
+// way, particularly if it is multi-threaded.  WTF?  Someone please let me
+// (Kenton) know if I'm missing something here...
+//
+// I'd love to hear about other alternatives, though, as this code isn't
+// exactly pretty.
+
+#include <google/protobuf/io/tokenizer.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace io {
+namespace {
+
+// As mentioned above, I don't trust ctype.h due to the presence of "locales".
+// So, I have written replacement functions here.  Someone please smack me if
+// this is a bad idea or if there is some way around this.
+//
+// These "character classes" are designed to be used in template methods.
+// For instance, Tokenizer::ConsumeZeroOrMore<Whitespace>() will eat
+// whitespace.
+
+// Note:  No class is allowed to contain '\0', since this is used to mark end-
+//   of-input and is handled specially.
+
+#define CHARACTER_CLASS(NAME, EXPRESSION)                     \
+  class NAME {                                                \
+   public:                                                    \
+    static inline bool InClass(char c) { return EXPRESSION; } \
+  }
+
+CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || c == '\r' ||
+                                c == '\v' || c == '\f');
+CHARACTER_CLASS(WhitespaceNoNewline,
+                c == ' ' || c == '\t' || c == '\r' || c == '\v' || c == '\f');
+
+CHARACTER_CLASS(Unprintable, c<' ' && c> '\0');
+
+CHARACTER_CLASS(Digit, '0' <= c && c <= '9');
+CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7');
+CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
+                              ('A' <= c && c <= 'F'));
+
+CHARACTER_CLASS(Letter,
+                ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_'));
+
+CHARACTER_CLASS(Alphanumeric, ('a' <= c && c <= 'z') ||
+                                  ('A' <= c && c <= 'Z') ||
+                                  ('0' <= c && c <= '9') || (c == '_'));
+
+CHARACTER_CLASS(Escape, c == 'a' || c == 'b' || c == 'f' || c == 'n' ||
+                            c == 'r' || c == 't' || c == 'v' || c == '\\' ||
+                            c == '?' || c == '\'' || c == '\"');
+
+#undef CHARACTER_CLASS
+
+// Given a char, interpret it as a numeric digit and return its value.
+// This supports any number base up to 36.
+// Represents integer values of digits.
+// Uses 36 to indicate an invalid character since we support
+// bases up to 36.
+static const int8_t kAsciiToInt[256] = {
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 00-0F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 10-1F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // ' '-'/'
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,                           // '0'-'9'
+    36, 36, 36, 36, 36, 36, 36,                                      // ':'-'@'
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  // 'A'-'P'
+    26, 27, 28, 29, 30, 31, 32, 33, 34, 35,                          // 'Q'-'Z'
+    36, 36, 36, 36, 36, 36,                                          // '['-'`'
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  // 'a'-'p'
+    26, 27, 28, 29, 30, 31, 32, 33, 34, 35,                          // 'q'-'z'
+    36, 36, 36, 36, 36,                                              // '{'-DEL
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 80-8F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 90-9F
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // A0-AF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // B0-BF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // C0-CF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // D0-DF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // E0-EF
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // F0-FF
+};
+
+inline int DigitValue(char digit) { return kAsciiToInt[digit & 0xFF]; }
+
+// Inline because it's only used in one place.
+inline char TranslateEscape(char c) {
+  switch (c) {
+    case 'a':
+      return '\a';
+    case 'b':
+      return '\b';
+    case 'f':
+      return '\f';
+    case 'n':
+      return '\n';
+    case 'r':
+      return '\r';
+    case 't':
+      return '\t';
+    case 'v':
+      return '\v';
+    case '\\':
+      return '\\';
+    case '?':
+      return '\?';  // Trigraphs = :(
+    case '\'':
+      return '\'';
+    case '"':
+      return '\"';
+
+    // We expect escape sequences to have been validated separately.
+    default:
+      return '?';
+  }
+}
+
+}  // anonymous namespace
+
+ErrorCollector::~ErrorCollector() {}
+
+// ===================================================================
+
+Tokenizer::Tokenizer(ZeroCopyInputStream* input,
+                     ErrorCollector* error_collector)
+    : input_(input),
+      error_collector_(error_collector),
+      buffer_(NULL),
+      buffer_size_(0),
+      buffer_pos_(0),
+      read_error_(false),
+      line_(0),
+      column_(0),
+      record_target_(NULL),
+      record_start_(-1),
+      allow_f_after_float_(false),
+      comment_style_(CPP_COMMENT_STYLE),
+      require_space_after_number_(true),
+      allow_multiline_strings_(false) {
+  current_.line = 0;
+  current_.column = 0;
+  current_.end_column = 0;
+  current_.type = TYPE_START;
+
+  Refresh();
+}
+
+Tokenizer::~Tokenizer() {
+  // If we had any buffer left unread, return it to the underlying stream
+  // so that someone else can read it.
+  if (buffer_size_ > buffer_pos_) {
+    input_->BackUp(buffer_size_ - buffer_pos_);
+  }
+}
+
+bool Tokenizer::report_whitespace() const { return report_whitespace_; }
+// Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
+void Tokenizer::set_report_whitespace(bool report) {
+  report_whitespace_ = report;
+  report_newlines_ &= report;
+}
+
+// If true, newline tokens are reported by Next().
+bool Tokenizer::report_newlines() const { return report_newlines_; }
+// Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
+void Tokenizer::set_report_newlines(bool report) {
+  report_newlines_ = report;
+  report_whitespace_ |= report;  // enable report_whitespace if necessary
+}
+
+// -------------------------------------------------------------------
+// Internal helpers.
+
+void Tokenizer::NextChar() {
+  // Update our line and column counters based on the character being
+  // consumed.
+  if (current_char_ == '\n') {
+    ++line_;
+    column_ = 0;
+  } else if (current_char_ == '\t') {
+    column_ += kTabWidth - column_ % kTabWidth;
+  } else {
+    ++column_;
+  }
+
+  // Advance to the next character.
+  ++buffer_pos_;
+  if (buffer_pos_ < buffer_size_) {
+    current_char_ = buffer_[buffer_pos_];
+  } else {
+    Refresh();
+  }
+}
+
+void Tokenizer::Refresh() {
+  if (read_error_) {
+    current_char_ = '\0';
+    return;
+  }
+
+  // If we're in a token, append the rest of the buffer to it.
+  if (record_target_ != NULL && record_start_ < buffer_size_) {
+    record_target_->append(buffer_ + record_start_,
+                           buffer_size_ - record_start_);
+    record_start_ = 0;
+  }
+
+  const void* data = NULL;
+  buffer_ = NULL;
+  buffer_pos_ = 0;
+  do {
+    if (!input_->Next(&data, &buffer_size_)) {
+      // end of stream (or read error)
+      buffer_size_ = 0;
+      read_error_ = true;
+      current_char_ = '\0';
+      return;
+    }
+  } while (buffer_size_ == 0);
+
+  buffer_ = static_cast<const char*>(data);
+
+  current_char_ = buffer_[0];
+}
+
+inline void Tokenizer::RecordTo(std::string* target) {
+  record_target_ = target;
+  record_start_ = buffer_pos_;
+}
+
+inline void Tokenizer::StopRecording() {
+  // Note:  The if() is necessary because some STL implementations crash when
+  //   you call string::append(NULL, 0), presumably because they are trying to
+  //   be helpful by detecting the NULL pointer, even though there's nothing
+  //   wrong with reading zero bytes from NULL.
+  if (buffer_pos_ != record_start_) {
+    record_target_->append(buffer_ + record_start_,
+                           buffer_pos_ - record_start_);
+  }
+  record_target_ = NULL;
+  record_start_ = -1;
+}
+
+inline void Tokenizer::StartToken() {
+  current_.type = TYPE_START;  // Just for the sake of initializing it.
+  current_.text.clear();
+  current_.line = line_;
+  current_.column = column_;
+  RecordTo(&current_.text);
+}
+
+inline void Tokenizer::EndToken() {
+  StopRecording();
+  current_.end_column = column_;
+}
+
+// -------------------------------------------------------------------
+// Helper methods that consume characters.
+
+template <typename CharacterClass>
+inline bool Tokenizer::LookingAt() {
+  return CharacterClass::InClass(current_char_);
+}
+
+template <typename CharacterClass>
+inline bool Tokenizer::TryConsumeOne() {
+  if (CharacterClass::InClass(current_char_)) {
+    NextChar();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline bool Tokenizer::TryConsume(char c) {
+  if (current_char_ == c) {
+    NextChar();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+template <typename CharacterClass>
+inline void Tokenizer::ConsumeZeroOrMore() {
+  while (CharacterClass::InClass(current_char_)) {
+    NextChar();
+  }
+}
+
+template <typename CharacterClass>
+inline void Tokenizer::ConsumeOneOrMore(const char* error) {
+  if (!CharacterClass::InClass(current_char_)) {
+    AddError(error);
+  } else {
+    do {
+      NextChar();
+    } while (CharacterClass::InClass(current_char_));
+  }
+}
+
+// -------------------------------------------------------------------
+// Methods that read whole patterns matching certain kinds of tokens
+// or comments.
+
+void Tokenizer::ConsumeString(char delimiter) {
+  while (true) {
+    switch (current_char_) {
+      case '\0':
+        AddError("Unexpected end of string.");
+        return;
+
+      case '\n': {
+        if (!allow_multiline_strings_) {
+          AddError("String literals cannot cross line boundaries.");
+          return;
+        }
+        NextChar();
+        break;
+      }
+
+      case '\\': {
+        // An escape sequence.
+        NextChar();
+        if (TryConsumeOne<Escape>()) {
+          // Valid escape sequence.
+        } else if (TryConsumeOne<OctalDigit>()) {
+          // Possibly followed by two more octal digits, but these will
+          // just be consumed by the main loop anyway so we don't need
+          // to do so explicitly here.
+        } else if (TryConsume('x')) {
+          if (!TryConsumeOne<HexDigit>()) {
+            AddError("Expected hex digits for escape sequence.");
+          }
+          // Possibly followed by another hex digit, but again we don't care.
+        } else if (TryConsume('u')) {
+          if (!TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
+              !TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>()) {
+            AddError("Expected four hex digits for \\u escape sequence.");
+          }
+        } else if (TryConsume('U')) {
+          // We expect 8 hex digits; but only the range up to 0x10ffff is
+          // legal.
+          if (!TryConsume('0') || !TryConsume('0') ||
+              !(TryConsume('0') || TryConsume('1')) ||
+              !TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
+              !TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
+              !TryConsumeOne<HexDigit>()) {
+            AddError(
+                "Expected eight hex digits up to 10ffff for \\U escape "
+                "sequence");
+          }
+        } else {
+          AddError("Invalid escape sequence in string literal.");
+        }
+        break;
+      }
+
+      default: {
+        if (current_char_ == delimiter) {
+          NextChar();
+          return;
+        }
+        NextChar();
+        break;
+      }
+    }
+  }
+}
+
+Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
+                                              bool started_with_dot) {
+  bool is_float = false;
+
+  if (started_with_zero && (TryConsume('x') || TryConsume('X'))) {
+    // A hex number (started with "0x").
+    ConsumeOneOrMore<HexDigit>("\"0x\" must be followed by hex digits.");
+
+  } else if (started_with_zero && LookingAt<Digit>()) {
+    // An octal number (had a leading zero).
+    ConsumeZeroOrMore<OctalDigit>();
+    if (LookingAt<Digit>()) {
+      AddError("Numbers starting with leading zero must be in octal.");
+      ConsumeZeroOrMore<Digit>();
+    }
+
+  } else {
+    // A decimal number.
+    if (started_with_dot) {
+      is_float = true;
+      ConsumeZeroOrMore<Digit>();
+    } else {
+      ConsumeZeroOrMore<Digit>();
+
+      if (TryConsume('.')) {
+        is_float = true;
+        ConsumeZeroOrMore<Digit>();
+      }
+    }
+
+    if (TryConsume('e') || TryConsume('E')) {
+      is_float = true;
+      TryConsume('-') || TryConsume('+');
+      ConsumeOneOrMore<Digit>("\"e\" must be followed by exponent.");
+    }
+
+    if (allow_f_after_float_ && (TryConsume('f') || TryConsume('F'))) {
+      is_float = true;
+    }
+  }
+
+  if (LookingAt<Letter>() && require_space_after_number_) {
+    AddError("Need space between number and identifier.");
+  } else if (current_char_ == '.') {
+    if (is_float) {
+      AddError(
+          "Already saw decimal point or exponent; can't have another one.");
+    } else {
+      AddError("Hex and octal numbers must be integers.");
+    }
+  }
+
+  return is_float ? TYPE_FLOAT : TYPE_INTEGER;
+}
+
+void Tokenizer::ConsumeLineComment(std::string* content) {
+  if (content != NULL) RecordTo(content);
+
+  while (current_char_ != '\0' && current_char_ != '\n') {
+    NextChar();
+  }
+  TryConsume('\n');
+
+  if (content != NULL) StopRecording();
+}
+
+void Tokenizer::ConsumeBlockComment(std::string* content) {
+  int start_line = line_;
+  int start_column = column_ - 2;
+
+  if (content != NULL) RecordTo(content);
+
+  while (true) {
+    while (current_char_ != '\0' && current_char_ != '*' &&
+           current_char_ != '/' && current_char_ != '\n') {
+      NextChar();
+    }
+
+    if (TryConsume('\n')) {
+      if (content != NULL) StopRecording();
+
+      // Consume leading whitespace and asterisk;
+      ConsumeZeroOrMore<WhitespaceNoNewline>();
+      if (TryConsume('*')) {
+        if (TryConsume('/')) {
+          // End of comment.
+          break;
+        }
+      }
+
+      if (content != NULL) RecordTo(content);
+    } else if (TryConsume('*') && TryConsume('/')) {
+      // End of comment.
+      if (content != NULL) {
+        StopRecording();
+        // Strip trailing "*/".
+        content->erase(content->size() - 2);
+      }
+      break;
+    } else if (TryConsume('/') && current_char_ == '*') {
+      // Note:  We didn't consume the '*' because if there is a '/' after it
+      //   we want to interpret that as the end of the comment.
+      AddError(
+          "\"/*\" inside block comment.  Block comments cannot be nested.");
+    } else if (current_char_ == '\0') {
+      AddError("End-of-file inside block comment.");
+      error_collector_->AddError(start_line, start_column,
+                                 "  Comment started here.");
+      if (content != NULL) StopRecording();
+      break;
+    }
+  }
+}
+
+Tokenizer::NextCommentStatus Tokenizer::TryConsumeCommentStart() {
+  if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
+    if (TryConsume('/')) {
+      return LINE_COMMENT;
+    } else if (TryConsume('*')) {
+      return BLOCK_COMMENT;
+    } else {
+      // Oops, it was just a slash.  Return it.
+      current_.type = TYPE_SYMBOL;
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wrestrict"
+#endif
+      current_.text = "/";
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+      current_.line = line_;
+      current_.column = column_ - 1;
+      current_.end_column = column_;
+      return SLASH_NOT_COMMENT;
+    }
+  } else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
+    return LINE_COMMENT;
+  } else {
+    return NO_COMMENT;
+  }
+}
+
+bool Tokenizer::TryConsumeWhitespace() {
+  if (report_newlines_) {
+    if (TryConsumeOne<WhitespaceNoNewline>()) {
+      ConsumeZeroOrMore<WhitespaceNoNewline>();
+      current_.type = TYPE_WHITESPACE;
+      return true;
+    }
+    return false;
+  }
+  if (TryConsumeOne<Whitespace>()) {
+    ConsumeZeroOrMore<Whitespace>();
+    current_.type = TYPE_WHITESPACE;
+    return report_whitespace_;
+  }
+  return false;
+}
+
+bool Tokenizer::TryConsumeNewline() {
+  if (!report_whitespace_ || !report_newlines_) {
+    return false;
+  }
+  if (TryConsume('\n')) {
+    current_.type = TYPE_NEWLINE;
+    return true;
+  }
+  return false;
+}
+
+// -------------------------------------------------------------------
+
+bool Tokenizer::Next() {
+  previous_ = current_;
+
+  while (!read_error_) {
+    StartToken();
+    bool report_token = TryConsumeWhitespace() || TryConsumeNewline();
+    EndToken();
+    if (report_token) {
+      return true;
+    }
+
+    switch (TryConsumeCommentStart()) {
+      case LINE_COMMENT:
+        ConsumeLineComment(NULL);
+        continue;
+      case BLOCK_COMMENT:
+        ConsumeBlockComment(NULL);
+        continue;
+      case SLASH_NOT_COMMENT:
+        return true;
+      case NO_COMMENT:
+        break;
+    }
+
+    // Check for EOF before continuing.
+    if (read_error_) break;
+
+    if (LookingAt<Unprintable>() || current_char_ == '\0') {
+      AddError("Invalid control characters encountered in text.");
+      NextChar();
+      // Skip more unprintable characters, too.  But, remember that '\0' is
+      // also what current_char_ is set to after EOF / read error.  We have
+      // to be careful not to go into an infinite loop of trying to consume
+      // it, so make sure to check read_error_ explicitly before consuming
+      // '\0'.
+      while (TryConsumeOne<Unprintable>() ||
+             (!read_error_ && TryConsume('\0'))) {
+        // Ignore.
+      }
+
+    } else {
+      // Reading some sort of token.
+      StartToken();
+
+      if (TryConsumeOne<Letter>()) {
+        ConsumeZeroOrMore<Alphanumeric>();
+        current_.type = TYPE_IDENTIFIER;
+      } else if (TryConsume('0')) {
+        current_.type = ConsumeNumber(true, false);
+      } else if (TryConsume('.')) {
+        // This could be the beginning of a floating-point number, or it could
+        // just be a '.' symbol.
+
+        if (TryConsumeOne<Digit>()) {
+          // It's a floating-point number.
+          if (previous_.type == TYPE_IDENTIFIER &&
+              current_.line == previous_.line &&
+              current_.column == previous_.end_column) {
+            // We don't accept syntax like "blah.123".
+            error_collector_->AddError(
+                line_, column_ - 2,
+                "Need space between identifier and decimal point.");
+          }
+          current_.type = ConsumeNumber(false, true);
+        } else {
+          current_.type = TYPE_SYMBOL;
+        }
+      } else if (TryConsumeOne<Digit>()) {
+        current_.type = ConsumeNumber(false, false);
+      } else if (TryConsume('\"')) {
+        ConsumeString('\"');
+        current_.type = TYPE_STRING;
+      } else if (TryConsume('\'')) {
+        ConsumeString('\'');
+        current_.type = TYPE_STRING;
+      } else {
+        // Check if the high order bit is set.
+        if (current_char_ & 0x80) {
+          error_collector_->AddError(
+              line_, column_,
+              StringPrintf("Interpreting non ascii codepoint %d.",
+                              static_cast<unsigned char>(current_char_)));
+        }
+        NextChar();
+        current_.type = TYPE_SYMBOL;
+      }
+
+      EndToken();
+      return true;
+    }
+  }
+
+  // EOF
+  current_.type = TYPE_END;
+  current_.text.clear();
+  current_.line = line_;
+  current_.column = column_;
+  current_.end_column = column_;
+  return false;
+}
+
+namespace {
+
+// Helper class for collecting comments and putting them in the right places.
+//
+// This basically just buffers the most recent comment until it can be decided
+// exactly where that comment should be placed.  When Flush() is called, the
+// current comment goes into either prev_trailing_comments or detached_comments.
+// When the CommentCollector is destroyed, the last buffered comment goes into
+// next_leading_comments.
+class CommentCollector {
+ public:
+  CommentCollector(std::string* prev_trailing_comments,
+                   std::vector<std::string>* detached_comments,
+                   std::string* next_leading_comments)
+      : prev_trailing_comments_(prev_trailing_comments),
+        detached_comments_(detached_comments),
+        next_leading_comments_(next_leading_comments),
+        has_comment_(false),
+        is_line_comment_(false),
+        can_attach_to_prev_(true) {
+    if (prev_trailing_comments != NULL) prev_trailing_comments->clear();
+    if (detached_comments != NULL) detached_comments->clear();
+    if (next_leading_comments != NULL) next_leading_comments->clear();
+  }
+
+  ~CommentCollector() {
+    // Whatever is in the buffer is a leading comment.
+    if (next_leading_comments_ != NULL && has_comment_) {
+      comment_buffer_.swap(*next_leading_comments_);
+    }
+  }
+
+  // About to read a line comment.  Get the comment buffer pointer in order to
+  // read into it.
+  std::string* GetBufferForLineComment() {
+    // We want to combine with previous line comments, but not block comments.
+    if (has_comment_ && !is_line_comment_) {
+      Flush();
+    }
+    has_comment_ = true;
+    is_line_comment_ = true;
+    return &comment_buffer_;
+  }
+
+  // About to read a block comment.  Get the comment buffer pointer in order to
+  // read into it.
+  std::string* GetBufferForBlockComment() {
+    if (has_comment_) {
+      Flush();
+    }
+    has_comment_ = true;
+    is_line_comment_ = false;
+    return &comment_buffer_;
+  }
+
+  void ClearBuffer() {
+    comment_buffer_.clear();
+    has_comment_ = false;
+  }
+
+  // Called once we know that the comment buffer is complete and is *not*
+  // connected to the next token.
+  void Flush() {
+    if (has_comment_) {
+      if (can_attach_to_prev_) {
+        if (prev_trailing_comments_ != NULL) {
+          prev_trailing_comments_->append(comment_buffer_);
+        }
+        can_attach_to_prev_ = false;
+      } else {
+        if (detached_comments_ != NULL) {
+          detached_comments_->push_back(comment_buffer_);
+        }
+      }
+      ClearBuffer();
+    }
+  }
+
+  void DetachFromPrev() { can_attach_to_prev_ = false; }
+
+ private:
+  std::string* prev_trailing_comments_;
+  std::vector<std::string>* detached_comments_;
+  std::string* next_leading_comments_;
+
+  std::string comment_buffer_;
+
+  // True if any comments were read into comment_buffer_.  This can be true even
+  // if comment_buffer_ is empty, namely if the comment was "/**/".
+  bool has_comment_;
+
+  // Is the comment in the comment buffer a line comment?
+  bool is_line_comment_;
+
+  // Is it still possible that we could be reading a comment attached to the
+  // previous token?
+  bool can_attach_to_prev_;
+};
+
+}  // namespace
+
+bool Tokenizer::NextWithComments(std::string* prev_trailing_comments,
+                                 std::vector<std::string>* detached_comments,
+                                 std::string* next_leading_comments) {
+  CommentCollector collector(prev_trailing_comments, detached_comments,
+                             next_leading_comments);
+
+  if (current_.type == TYPE_START) {
+    // Ignore unicode byte order mark(BOM) if it appears at the file
+    // beginning. Only UTF-8 BOM (0xEF 0xBB 0xBF) is accepted.
+    if (TryConsume(static_cast<char>(0xEF))) {
+      if (!TryConsume(static_cast<char>(0xBB)) ||
+          !TryConsume(static_cast<char>(0xBF))) {
+        AddError(
+            "Proto file starts with 0xEF but not UTF-8 BOM. "
+            "Only UTF-8 is accepted for proto file.");
+        return false;
+      }
+    }
+    collector.DetachFromPrev();
+  } else {
+    // A comment appearing on the same line must be attached to the previous
+    // declaration.
+    ConsumeZeroOrMore<WhitespaceNoNewline>();
+    switch (TryConsumeCommentStart()) {
+      case LINE_COMMENT:
+        ConsumeLineComment(collector.GetBufferForLineComment());
+
+        // Don't allow comments on subsequent lines to be attached to a trailing
+        // comment.
+        collector.Flush();
+        break;
+      case BLOCK_COMMENT:
+        ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+        ConsumeZeroOrMore<WhitespaceNoNewline>();
+        if (!TryConsume('\n')) {
+          // Oops, the next token is on the same line.  If we recorded a comment
+          // we really have no idea which token it should be attached to.
+          collector.ClearBuffer();
+          return Next();
+        }
+
+        // Don't allow comments on subsequent lines to be attached to a trailing
+        // comment.
+        collector.Flush();
+        break;
+      case SLASH_NOT_COMMENT:
+        return true;
+      case NO_COMMENT:
+        if (!TryConsume('\n')) {
+          // The next token is on the same line.  There are no comments.
+          return Next();
+        }
+        break;
+    }
+  }
+
+  // OK, we are now on the line *after* the previous token.
+  while (true) {
+    ConsumeZeroOrMore<WhitespaceNoNewline>();
+
+    switch (TryConsumeCommentStart()) {
+      case LINE_COMMENT:
+        ConsumeLineComment(collector.GetBufferForLineComment());
+        break;
+      case BLOCK_COMMENT:
+        ConsumeBlockComment(collector.GetBufferForBlockComment());
+
+        // Consume the rest of the line so that we don't interpret it as a
+        // blank line the next time around the loop.
+        ConsumeZeroOrMore<WhitespaceNoNewline>();
+        TryConsume('\n');
+        break;
+      case SLASH_NOT_COMMENT:
+        return true;
+      case NO_COMMENT:
+        if (TryConsume('\n')) {
+          // Completely blank line.
+          collector.Flush();
+          collector.DetachFromPrev();
+        } else {
+          bool result = Next();
+          if (!result || current_.text == "}" || current_.text == "]" ||
+              current_.text == ")") {
+            // It looks like we're at the end of a scope.  In this case it
+            // makes no sense to attach a comment to the following token.
+            collector.Flush();
+          }
+          return result;
+        }
+        break;
+    }
+  }
+}
+
+// -------------------------------------------------------------------
+// Token-parsing helpers.  Remember that these don't need to report
+// errors since any errors should already have been reported while
+// tokenizing.  Also, these can assume that whatever text they
+// are given is text that the tokenizer actually parsed as a token
+// of the given type.
+
+bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
+                             uint64_t* output) {
+  // We can't just use strtoull() because (a) it accepts negative numbers,
+  // (b) We want additional range checks, (c) it reports overflows via errno.
+
+#if 0
+  const char *str_begin = text.c_str();
+  if (*str_begin == '-') return false;
+  char *str_end = nullptr;
+  errno = 0;
+  *output = std::strtoull(str_begin, &str_end, 0);
+  return (errno == 0 && str_end && *str_end == '\0' && *output <= max_value);
+#endif
+
+  const char* ptr = text.c_str();
+  int base = 10;
+  uint64_t overflow_if_mul_base = (kuint64max / 10) + 1;
+  if (ptr[0] == '0') {
+    if (ptr[1] == 'x' || ptr[1] == 'X') {
+      // This is hex.
+      base = 16;
+      overflow_if_mul_base = (kuint64max / 16) + 1;
+      ptr += 2;
+    } else {
+      // This is octal.
+      base = 8;
+      overflow_if_mul_base = (kuint64max / 8) + 1;
+    }
+  }
+
+  uint64_t result = 0;
+  // For all the leading '0's, and also the first non-zero character, we
+  // don't need to multiply.
+  while (*ptr != '\0') {
+    int digit = DigitValue(*ptr++);
+    if (digit >= base) {
+      // The token provided by Tokenizer is invalid. i.e., 099 is an invalid
+      // token, but Tokenizer still think it's integer.
+      return false;
+    }
+    if (digit != 0) {
+      result = digit;
+      break;
+    }
+  }
+  for (; *ptr != '\0'; ptr++) {
+    int digit = DigitValue(*ptr);
+    if (digit < 0 || digit >= base) {
+      // The token provided by Tokenizer is invalid. i.e., 099 is an invalid
+      // token, but Tokenizer still think it's integer.
+      return false;
+    }
+    if (result >= overflow_if_mul_base) {
+      // We know the multiply we're about to do will overflow, so exit now.
+      return false;
+    }
+    // We know that result * base won't overflow, but adding digit might...
+    result = result * base + digit;
+    // C++ guarantees defined "wrap" semantics when unsigned integer
+    // operations overflow, making this a fast way to check if adding
+    // digit made result overflow, and thus, wrap around.
+    if (result < static_cast<uint64_t>(base)) return false;
+  }
+  if (result > max_value) return false;
+
+  *output = result;
+  return true;
+}
+
+double Tokenizer::ParseFloat(const std::string& text) {
+  const char* start = text.c_str();
+  char* end;
+  double result = NoLocaleStrtod(start, &end);
+
+  // "1e" is not a valid float, but if the tokenizer reads it, it will
+  // report an error but still return it as a valid token.  We need to
+  // accept anything the tokenizer could possibly return, error or not.
+  if (*end == 'e' || *end == 'E') {
+    ++end;
+    if (*end == '-' || *end == '+') ++end;
+  }
+
+  // If the Tokenizer had allow_f_after_float_ enabled, the float may be
+  // suffixed with the letter 'f'.
+  if (*end == 'f' || *end == 'F') {
+    ++end;
+  }
+
+  GOOGLE_LOG_IF(DFATAL,
+         static_cast<size_t>(end - start) != text.size() || *start == '-')
+      << " Tokenizer::ParseFloat() passed text that could not have been"
+         " tokenized as a float: "
+      << CEscape(text);
+  return result;
+}
+
+// Helper to append a Unicode code point to a string as UTF8, without bringing
+// in any external dependencies.
+static void AppendUTF8(uint32_t code_point, std::string* output) {
+  uint32_t tmp = 0;
+  int len = 0;
+  if (code_point <= 0x7f) {
+    tmp = code_point;
+    len = 1;
+  } else if (code_point <= 0x07ff) {
+    tmp = 0x0000c080 | ((code_point & 0x07c0) << 2) | (code_point & 0x003f);
+    len = 2;
+  } else if (code_point <= 0xffff) {
+    tmp = 0x00e08080 | ((code_point & 0xf000) << 4) |
+          ((code_point & 0x0fc0) << 2) | (code_point & 0x003f);
+    len = 3;
+  } else if (code_point <= 0x10ffff) {
+    tmp = 0xf0808080 | ((code_point & 0x1c0000) << 6) |
+          ((code_point & 0x03f000) << 4) | ((code_point & 0x000fc0) << 2) |
+          (code_point & 0x003f);
+    len = 4;
+  } else {
+    // Unicode code points end at 0x10FFFF, so this is out-of-range.
+    // ConsumeString permits hex values up to 0x1FFFFF, and FetchUnicodePoint
+    // doesn't perform a range check.
+    StringAppendF(output, "\\U%08x", code_point);
+    return;
+  }
+  tmp = ghtonl(tmp);
+  output->append(reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+}
+
+// Try to read <len> hex digits from ptr, and stuff the numeric result into
+// *result. Returns true if that many digits were successfully consumed.
+static bool ReadHexDigits(const char* ptr, int len, uint32_t* result) {
+  *result = 0;
+  if (len == 0) return false;
+  for (const char* end = ptr + len; ptr < end; ++ptr) {
+    if (*ptr == '\0') return false;
+    *result = (*result << 4) + DigitValue(*ptr);
+  }
+  return true;
+}
+
+// Handling UTF-16 surrogate pairs. UTF-16 encodes code points in the range
+// 0x10000...0x10ffff as a pair of numbers, a head surrogate followed by a trail
+// surrogate. These numbers are in a reserved range of Unicode code points, so
+// if we encounter such a pair we know how to parse it and convert it into a
+// single code point.
+static const uint32_t kMinHeadSurrogate = 0xd800;
+static const uint32_t kMaxHeadSurrogate = 0xdc00;
+static const uint32_t kMinTrailSurrogate = 0xdc00;
+static const uint32_t kMaxTrailSurrogate = 0xe000;
+
+static inline bool IsHeadSurrogate(uint32_t code_point) {
+  return (code_point >= kMinHeadSurrogate) && (code_point < kMaxHeadSurrogate);
+}
+
+static inline bool IsTrailSurrogate(uint32_t code_point) {
+  return (code_point >= kMinTrailSurrogate) &&
+         (code_point < kMaxTrailSurrogate);
+}
+
+// Combine a head and trail surrogate into a single Unicode code point.
+static uint32_t AssembleUTF16(uint32_t head_surrogate,
+                              uint32_t trail_surrogate) {
+  GOOGLE_DCHECK(IsHeadSurrogate(head_surrogate));
+  GOOGLE_DCHECK(IsTrailSurrogate(trail_surrogate));
+  return 0x10000 + (((head_surrogate - kMinHeadSurrogate) << 10) |
+                    (trail_surrogate - kMinTrailSurrogate));
+}
+
+// Convert the escape sequence parameter to a number of expected hex digits.
+static inline int UnicodeLength(char key) {
+  if (key == 'u') return 4;
+  if (key == 'U') return 8;
+  return 0;
+}
+
+// Given a pointer to the 'u' or 'U' starting a Unicode escape sequence, attempt
+// to parse that sequence. On success, returns a pointer to the first char
+// beyond that sequence, and fills in *code_point. On failure, returns ptr
+// itself.
+static const char* FetchUnicodePoint(const char* ptr, uint32_t* code_point) {
+  const char* p = ptr;
+  // Fetch the code point.
+  const int len = UnicodeLength(*p++);
+  if (!ReadHexDigits(p, len, code_point)) return ptr;
+  p += len;
+
+  // Check if the code point we read is a "head surrogate." If so, then we
+  // expect it to be immediately followed by another code point which is a valid
+  // "trail surrogate," and together they form a UTF-16 pair which decodes into
+  // a single Unicode point. Trail surrogates may only use \u, not \U.
+  if (IsHeadSurrogate(*code_point) && *p == '\\' && *(p + 1) == 'u') {
+    uint32_t trail_surrogate;
+    if (ReadHexDigits(p + 2, 4, &trail_surrogate) &&
+        IsTrailSurrogate(trail_surrogate)) {
+      *code_point = AssembleUTF16(*code_point, trail_surrogate);
+      p += 6;
+    }
+    // If this failed, then we just emit the head surrogate as a code point.
+    // It's bogus, but so is the string.
+  }
+
+  return p;
+}
+
+// The text string must begin and end with single or double quote
+// characters.
+void Tokenizer::ParseStringAppend(const std::string& text,
+                                  std::string* output) {
+  // Reminder: text[0] is always a quote character.  (If text is
+  // empty, it's invalid, so we'll just return).
+  const size_t text_size = text.size();
+  if (text_size == 0) {
+    GOOGLE_LOG(DFATAL) << " Tokenizer::ParseStringAppend() passed text that could not"
+                   " have been tokenized as a string: "
+                << CEscape(text);
+    return;
+  }
+
+  // Reserve room for new string. The branch is necessary because if
+  // there is already space available the reserve() call might
+  // downsize the output.
+  const size_t new_len = text_size + output->size();
+  if (new_len > output->capacity()) {
+    output->reserve(new_len);
+  }
+
+  // Loop through the string copying characters to "output" and
+  // interpreting escape sequences.  Note that any invalid escape
+  // sequences or other errors were already reported while tokenizing.
+  // In this case we do not need to produce valid results.
+  for (const char* ptr = text.c_str() + 1; *ptr != '\0'; ptr++) {
+    if (*ptr == '\\' && ptr[1] != '\0') {
+      // An escape sequence.
+      ++ptr;
+
+      if (OctalDigit::InClass(*ptr)) {
+        // An octal escape.  May one, two, or three digits.
+        int code = DigitValue(*ptr);
+        if (OctalDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = code * 8 + DigitValue(*ptr);
+        }
+        if (OctalDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = code * 8 + DigitValue(*ptr);
+        }
+        output->push_back(static_cast<char>(code));
+
+      } else if (*ptr == 'x') {
+        // A hex escape.  May zero, one, or two digits.  (The zero case
+        // will have been caught as an error earlier.)
+        int code = 0;
+        if (HexDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = DigitValue(*ptr);
+        }
+        if (HexDigit::InClass(ptr[1])) {
+          ++ptr;
+          code = code * 16 + DigitValue(*ptr);
+        }
+        output->push_back(static_cast<char>(code));
+
+      } else if (*ptr == 'u' || *ptr == 'U') {
+        uint32_t unicode;
+        const char* end = FetchUnicodePoint(ptr, &unicode);
+        if (end == ptr) {
+          // Failure: Just dump out what we saw, don't try to parse it.
+          output->push_back(*ptr);
+        } else {
+          AppendUTF8(unicode, output);
+          ptr = end - 1;  // Because we're about to ++ptr.
+        }
+      } else {
+        // Some other escape code.
+        output->push_back(TranslateEscape(*ptr));
+      }
+
+    } else if (*ptr == text[0] && ptr[1] == '\0') {
+      // Ignore final quote matching the starting quote.
+    } else {
+      output->push_back(*ptr);
+    }
+  }
+}
+
+template <typename CharacterClass>
+static bool AllInClass(const std::string& s) {
+  for (const char character : s) {
+    if (!CharacterClass::InClass(character)) return false;
+  }
+  return true;
+}
+
+bool Tokenizer::IsIdentifier(const std::string& text) {
+  // Mirrors IDENTIFIER definition in Tokenizer::Next() above.
+  if (text.size() == 0) return false;
+  if (!Letter::InClass(text.at(0))) return false;
+  if (!AllInClass<Alphanumeric>(text.substr(1))) return false;
+  return true;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream.cpp
new file mode 100644
index 0000000..f81555e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream.cpp
@@ -0,0 +1,55 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+
+bool ZeroCopyOutputStream::WriteAliasedRaw(const void* /* data */,
+                                           int /* size */) {
+  GOOGLE_LOG(FATAL) << "This ZeroCopyOutputStream doesn't support aliasing. "
+                "Reaching here usually means a ZeroCopyOutputStream "
+                "implementation bug.";
+  return false;
+}
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream_impl.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream_impl.cpp
new file mode 100644
index 0000000..c66bc86
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream_impl.cpp
@@ -0,0 +1,372 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef _MSC_VER
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <algorithm>
+#include <iostream>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/io_win32.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+#ifdef _WIN32
+// Win32 lseek is broken:  If invoked on a non-seekable file descriptor, its
+// return value is undefined.  We re-define it to always produce an error.
+#define lseek(fd, offset, origin) ((off_t)-1)
+// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
+// them like we do below.
+using google::protobuf::io::win32::access;
+using google::protobuf::io::win32::close;
+using google::protobuf::io::win32::open;
+using google::protobuf::io::win32::read;
+using google::protobuf::io::win32::write;
+#endif
+
+namespace {
+
+// EINTR sucks.
+int close_no_eintr(int fd) {
+  int result;
+  do {
+    result = close(fd);
+  } while (result < 0 && errno == EINTR);
+  return result;
+}
+
+}  // namespace
+
+// ===================================================================
+
+FileInputStream::FileInputStream(int file_descriptor, int block_size)
+    : copying_input_(file_descriptor), impl_(&copying_input_, block_size) {}
+
+bool FileInputStream::Close() { return copying_input_.Close(); }
+
+bool FileInputStream::Next(const void** data, int* size) {
+  return impl_.Next(data, size);
+}
+
+void FileInputStream::BackUp(int count) { impl_.BackUp(count); }
+
+bool FileInputStream::Skip(int count) { return impl_.Skip(count); }
+
+int64_t FileInputStream::ByteCount() const { return impl_.ByteCount(); }
+
+FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
+    int file_descriptor)
+    : file_(file_descriptor),
+      close_on_delete_(false),
+      is_closed_(false),
+      errno_(0),
+      previous_seek_failed_(false) {
+#ifndef _WIN32
+  int flags = fcntl(file_, F_GETFL);
+  flags &= ~O_NONBLOCK;
+  fcntl(file_, F_SETFL, flags);
+#endif
+}
+
+FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
+  if (close_on_delete_) {
+    if (!Close()) {
+      GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
+    }
+  }
+}
+
+bool FileInputStream::CopyingFileInputStream::Close() {
+  GOOGLE_CHECK(!is_closed_);
+
+  is_closed_ = true;
+  if (close_no_eintr(file_) != 0) {
+    // The docs on close() do not specify whether a file descriptor is still
+    // open after close() fails with EIO.  However, the glibc source code
+    // seems to indicate that it is not.
+    errno_ = errno;
+    return false;
+  }
+
+  return true;
+}
+
+int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
+  GOOGLE_CHECK(!is_closed_);
+
+  int result;
+  do {
+    result = read(file_, buffer, size);
+  } while (result < 0 && errno == EINTR);
+
+  if (result < 0) {
+    // Read error (not EOF).
+    errno_ = errno;
+  }
+
+  return result;
+}
+
+int FileInputStream::CopyingFileInputStream::Skip(int count) {
+  GOOGLE_CHECK(!is_closed_);
+
+  if (!previous_seek_failed_ && lseek(file_, count, SEEK_CUR) != (off_t)-1) {
+    // Seek succeeded.
+    return count;
+  } else {
+    // Failed to seek.
+
+    // Note to self:  Don't seek again.  This file descriptor doesn't
+    // support it.
+    previous_seek_failed_ = true;
+
+    // Use the default implementation.
+    return CopyingInputStream::Skip(count);
+  }
+}
+
+// ===================================================================
+
+FileOutputStream::FileOutputStream(int file_descriptor, int /*block_size*/)
+    : CopyingOutputStreamAdaptor(&copying_output_),
+      copying_output_(file_descriptor) {}
+
+bool FileOutputStream::Close() {
+  bool flush_succeeded = Flush();
+  return copying_output_.Close() && flush_succeeded;
+}
+
+FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
+    int file_descriptor)
+    : file_(file_descriptor),
+      close_on_delete_(false),
+      is_closed_(false),
+      errno_(0) {}
+
+FileOutputStream::~FileOutputStream() { Flush(); }
+
+FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
+  if (close_on_delete_) {
+    if (!Close()) {
+      GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
+    }
+  }
+}
+
+bool FileOutputStream::CopyingFileOutputStream::Close() {
+  GOOGLE_CHECK(!is_closed_);
+
+  is_closed_ = true;
+  if (close_no_eintr(file_) != 0) {
+    // The docs on close() do not specify whether a file descriptor is still
+    // open after close() fails with EIO.  However, the glibc source code
+    // seems to indicate that it is not.
+    errno_ = errno;
+    return false;
+  }
+
+  return true;
+}
+
+bool FileOutputStream::CopyingFileOutputStream::Write(const void* buffer,
+                                                      int size) {
+  GOOGLE_CHECK(!is_closed_);
+  int total_written = 0;
+
+  const uint8_t* buffer_base = reinterpret_cast<const uint8_t*>(buffer);
+
+  while (total_written < size) {
+    int bytes;
+    do {
+      bytes = write(file_, buffer_base + total_written, size - total_written);
+    } while (bytes < 0 && errno == EINTR);
+
+    if (bytes <= 0) {
+      // Write error.
+
+      // FIXME(kenton):  According to the man page, if write() returns zero,
+      //   there was no error; write() simply did not write anything.  It's
+      //   unclear under what circumstances this might happen, but presumably
+      //   errno won't be set in this case.  I am confused as to how such an
+      //   event should be handled.  For now I'm treating it as an error, since
+      //   retrying seems like it could lead to an infinite loop.  I suspect
+      //   this never actually happens anyway.
+
+      if (bytes < 0) {
+        errno_ = errno;
+      }
+      return false;
+    }
+    total_written += bytes;
+  }
+
+  return true;
+}
+
+// ===================================================================
+
+IstreamInputStream::IstreamInputStream(std::istream* input, int block_size)
+    : copying_input_(input), impl_(&copying_input_, block_size) {}
+
+bool IstreamInputStream::Next(const void** data, int* size) {
+  return impl_.Next(data, size);
+}
+
+void IstreamInputStream::BackUp(int count) { impl_.BackUp(count); }
+
+bool IstreamInputStream::Skip(int count) { return impl_.Skip(count); }
+
+int64_t IstreamInputStream::ByteCount() const { return impl_.ByteCount(); }
+
+IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
+    std::istream* input)
+    : input_(input) {}
+
+IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
+
+int IstreamInputStream::CopyingIstreamInputStream::Read(void* buffer,
+                                                        int size) {
+  input_->read(reinterpret_cast<char*>(buffer), size);
+  int result = input_->gcount();
+  if (result == 0 && input_->fail() && !input_->eof()) {
+    return -1;
+  }
+  return result;
+}
+
+// ===================================================================
+
+OstreamOutputStream::OstreamOutputStream(std::ostream* output, int block_size)
+    : copying_output_(output), impl_(&copying_output_, block_size) {}
+
+OstreamOutputStream::~OstreamOutputStream() { impl_.Flush(); }
+
+bool OstreamOutputStream::Next(void** data, int* size) {
+  return impl_.Next(data, size);
+}
+
+void OstreamOutputStream::BackUp(int count) { impl_.BackUp(count); }
+
+int64_t OstreamOutputStream::ByteCount() const { return impl_.ByteCount(); }
+
+OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
+    std::ostream* output)
+    : output_(output) {}
+
+OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
+}
+
+bool OstreamOutputStream::CopyingOstreamOutputStream::Write(const void* buffer,
+                                                            int size) {
+  output_->write(reinterpret_cast<const char*>(buffer), size);
+  return output_->good();
+}
+
+// ===================================================================
+
+ConcatenatingInputStream::ConcatenatingInputStream(
+    ZeroCopyInputStream* const streams[], int count)
+    : streams_(streams), stream_count_(count), bytes_retired_(0) {
+}
+
+bool ConcatenatingInputStream::Next(const void** data, int* size) {
+  while (stream_count_ > 0) {
+    if (streams_[0]->Next(data, size)) return true;
+
+    // That stream is done.  Advance to the next one.
+    bytes_retired_ += streams_[0]->ByteCount();
+    ++streams_;
+    --stream_count_;
+  }
+
+  // No more streams.
+  return false;
+}
+
+void ConcatenatingInputStream::BackUp(int count) {
+  if (stream_count_ > 0) {
+    streams_[0]->BackUp(count);
+  } else {
+    GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next().";
+  }
+}
+
+bool ConcatenatingInputStream::Skip(int count) {
+  while (stream_count_ > 0) {
+    // Assume that ByteCount() can be used to find out how much we actually
+    // skipped when Skip() fails.
+    int64_t target_byte_count = streams_[0]->ByteCount() + count;
+    if (streams_[0]->Skip(count)) return true;
+
+    // Hit the end of the stream.  Figure out how many more bytes we still have
+    // to skip.
+    int64_t final_byte_count = streams_[0]->ByteCount();
+    GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
+    count = target_byte_count - final_byte_count;
+
+    // That stream is done.  Advance to the next one.
+    bytes_retired_ += final_byte_count;
+    ++streams_;
+    --stream_count_;
+  }
+
+  return false;
+}
+
+int64_t ConcatenatingInputStream::ByteCount() const {
+  if (stream_count_ == 0) {
+    return bytes_retired_;
+  } else {
+    return bytes_retired_ + streams_[0]->ByteCount();
+  }
+}
+
+
+// ===================================================================
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream_impl_lite.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream_impl_lite.cpp
new file mode 100644
index 0000000..b3dfd84
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/io/zero_copy_stream_impl_lite.cpp
@@ -0,0 +1,470 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+#include <algorithm>
+#include <limits>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+
+namespace {
+
+// Default block size for Copying{In,Out}putStreamAdaptor.
+static const int kDefaultBlockSize = 8192;
+
+}  // namespace
+
+// ===================================================================
+
+ArrayInputStream::ArrayInputStream(const void* data, int size, int block_size)
+    : data_(reinterpret_cast<const uint8_t*>(data)),
+      size_(size),
+      block_size_(block_size > 0 ? block_size : size),
+      position_(0),
+      last_returned_size_(0) {}
+
+bool ArrayInputStream::Next(const void** data, int* size) {
+  if (position_ < size_) {
+    last_returned_size_ = std::min(block_size_, size_ - position_);
+    *data = data_ + position_;
+    *size = last_returned_size_;
+    position_ += last_returned_size_;
+    return true;
+  } else {
+    // We're at the end of the array.
+    last_returned_size_ = 0;  // Don't let caller back up.
+    return false;
+  }
+}
+
+void ArrayInputStream::BackUp(int count) {
+  GOOGLE_CHECK_GT(last_returned_size_, 0)
+      << "BackUp() can only be called after a successful Next().";
+  GOOGLE_CHECK_LE(count, last_returned_size_);
+  GOOGLE_CHECK_GE(count, 0);
+  position_ -= count;
+  last_returned_size_ = 0;  // Don't let caller back up further.
+}
+
+bool ArrayInputStream::Skip(int count) {
+  GOOGLE_CHECK_GE(count, 0);
+  last_returned_size_ = 0;  // Don't let caller back up.
+  if (count > size_ - position_) {
+    position_ = size_;
+    return false;
+  } else {
+    position_ += count;
+    return true;
+  }
+}
+
+int64_t ArrayInputStream::ByteCount() const { return position_; }
+
+
+// ===================================================================
+
+ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
+    : data_(reinterpret_cast<uint8_t*>(data)),
+      size_(size),
+      block_size_(block_size > 0 ? block_size : size),
+      position_(0),
+      last_returned_size_(0) {}
+
+bool ArrayOutputStream::Next(void** data, int* size) {
+  if (position_ < size_) {
+    last_returned_size_ = std::min(block_size_, size_ - position_);
+    *data = data_ + position_;
+    *size = last_returned_size_;
+    position_ += last_returned_size_;
+    return true;
+  } else {
+    // We're at the end of the array.
+    last_returned_size_ = 0;  // Don't let caller back up.
+    return false;
+  }
+}
+
+void ArrayOutputStream::BackUp(int count) {
+  GOOGLE_CHECK_LE(count, last_returned_size_)
+      << "BackUp() can not exceed the size of the last Next() call.";
+  GOOGLE_CHECK_GE(count, 0);
+  position_ -= count;
+  last_returned_size_ -= count;
+}
+
+int64_t ArrayOutputStream::ByteCount() const { return position_; }
+
+// ===================================================================
+
+StringOutputStream::StringOutputStream(std::string* target) : target_(target) {}
+
+bool StringOutputStream::Next(void** data, int* size) {
+  GOOGLE_CHECK(target_ != NULL);
+  size_t old_size = target_->size();
+
+  // Grow the string.
+  size_t new_size;
+  if (old_size < target_->capacity()) {
+    // Resize the string to match its capacity, since we can get away
+    // without a memory allocation this way.
+    new_size = target_->capacity();
+  } else {
+    // Size has reached capacity, try to double it.
+    new_size = old_size * 2;
+  }
+  // Avoid integer overflow in returned '*size'.
+  new_size = std::min(new_size, old_size + std::numeric_limits<int>::max());
+  // Increase the size, also make sure that it is at least kMinimumSize.
+  STLStringResizeUninitialized(
+      target_,
+      std::max(new_size,
+               kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
+
+  *data = mutable_string_data(target_) + old_size;
+  *size = target_->size() - old_size;
+  return true;
+}
+
+void StringOutputStream::BackUp(int count) {
+  GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK(target_ != NULL);
+  GOOGLE_CHECK_LE(static_cast<size_t>(count), target_->size());
+  target_->resize(target_->size() - count);
+}
+
+int64_t StringOutputStream::ByteCount() const {
+  GOOGLE_CHECK(target_ != NULL);
+  return target_->size();
+}
+
+// ===================================================================
+
+int CopyingInputStream::Skip(int count) {
+  char junk[4096];
+  int skipped = 0;
+  while (skipped < count) {
+    int bytes = Read(junk, std::min(count - skipped,
+                                    implicit_cast<int>(sizeof(junk))));
+    if (bytes <= 0) {
+      // EOF or read error.
+      return skipped;
+    }
+    skipped += bytes;
+  }
+  return skipped;
+}
+
+CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
+    CopyingInputStream* copying_stream, int block_size)
+    : copying_stream_(copying_stream),
+      owns_copying_stream_(false),
+      failed_(false),
+      position_(0),
+      buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
+      buffer_used_(0),
+      backup_bytes_(0) {}
+
+CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
+  if (owns_copying_stream_) {
+    delete copying_stream_;
+  }
+}
+
+bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
+  if (failed_) {
+    // Already failed on a previous read.
+    return false;
+  }
+
+  AllocateBufferIfNeeded();
+
+  if (backup_bytes_ > 0) {
+    // We have data left over from a previous BackUp(), so just return that.
+    *data = buffer_.get() + buffer_used_ - backup_bytes_;
+    *size = backup_bytes_;
+    backup_bytes_ = 0;
+    return true;
+  }
+
+  // Read new data into the buffer.
+  buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
+  if (buffer_used_ <= 0) {
+    // EOF or read error.  We don't need the buffer anymore.
+    if (buffer_used_ < 0) {
+      // Read error (not EOF).
+      failed_ = true;
+    }
+    FreeBuffer();
+    return false;
+  }
+  position_ += buffer_used_;
+
+  *size = buffer_used_;
+  *data = buffer_.get();
+  return true;
+}
+
+void CopyingInputStreamAdaptor::BackUp(int count) {
+  GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
+      << " BackUp() can only be called after Next().";
+  GOOGLE_CHECK_LE(count, buffer_used_)
+      << " Can't back up over more bytes than were returned by the last call"
+         " to Next().";
+  GOOGLE_CHECK_GE(count, 0) << " Parameter to BackUp() can't be negative.";
+
+  backup_bytes_ = count;
+}
+
+bool CopyingInputStreamAdaptor::Skip(int count) {
+  GOOGLE_CHECK_GE(count, 0);
+
+  if (failed_) {
+    // Already failed on a previous read.
+    return false;
+  }
+
+  // First skip any bytes left over from a previous BackUp().
+  if (backup_bytes_ >= count) {
+    // We have more data left over than we're trying to skip.  Just chop it.
+    backup_bytes_ -= count;
+    return true;
+  }
+
+  count -= backup_bytes_;
+  backup_bytes_ = 0;
+
+  int skipped = copying_stream_->Skip(count);
+  position_ += skipped;
+  return skipped == count;
+}
+
+int64_t CopyingInputStreamAdaptor::ByteCount() const {
+  return position_ - backup_bytes_;
+}
+
+void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
+  if (buffer_.get() == NULL) {
+    buffer_.reset(new uint8_t[buffer_size_]);
+  }
+}
+
+void CopyingInputStreamAdaptor::FreeBuffer() {
+  GOOGLE_CHECK_EQ(backup_bytes_, 0);
+  buffer_used_ = 0;
+  buffer_.reset();
+}
+
+// ===================================================================
+
+CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
+    CopyingOutputStream* copying_stream, int block_size)
+    : copying_stream_(copying_stream),
+      owns_copying_stream_(false),
+      failed_(false),
+      position_(0),
+      buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
+      buffer_used_(0) {}
+
+CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
+  WriteBuffer();
+  if (owns_copying_stream_) {
+    delete copying_stream_;
+  }
+}
+
+bool CopyingOutputStreamAdaptor::Flush() { return WriteBuffer(); }
+
+bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
+  if (buffer_used_ == buffer_size_) {
+    if (!WriteBuffer()) return false;
+  }
+
+  AllocateBufferIfNeeded();
+
+  *data = buffer_.get() + buffer_used_;
+  *size = buffer_size_ - buffer_used_;
+  buffer_used_ = buffer_size_;
+  return true;
+}
+
+void CopyingOutputStreamAdaptor::BackUp(int count) {
+  if (count == 0) {
+    Flush();
+    return;
+  }
+  GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
+      << " BackUp() can only be called after Next().";
+  GOOGLE_CHECK_LE(count, buffer_used_)
+      << " Can't back up over more bytes than were returned by the last call"
+         " to Next().";
+
+  buffer_used_ -= count;
+}
+
+int64_t CopyingOutputStreamAdaptor::ByteCount() const {
+  return position_ + buffer_used_;
+}
+
+bool CopyingOutputStreamAdaptor::WriteAliasedRaw(const void* data, int size) {
+  if (size >= buffer_size_) {
+    if (!Flush() || !copying_stream_->Write(data, size)) {
+      return false;
+    }
+    GOOGLE_DCHECK_EQ(buffer_used_, 0);
+    position_ += size;
+    return true;
+  }
+
+  void* out;
+  int out_size;
+  while (true) {
+    if (!Next(&out, &out_size)) {
+      return false;
+    }
+
+    if (size <= out_size) {
+      std::memcpy(out, data, size);
+      BackUp(out_size - size);
+      return true;
+    }
+
+    std::memcpy(out, data, out_size);
+    data = static_cast<const char*>(data) + out_size;
+    size -= out_size;
+  }
+  return true;
+}
+
+
+bool CopyingOutputStreamAdaptor::WriteBuffer() {
+  if (failed_) {
+    // Already failed on a previous write.
+    return false;
+  }
+
+  if (buffer_used_ == 0) return true;
+
+  if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
+    position_ += buffer_used_;
+    buffer_used_ = 0;
+    return true;
+  } else {
+    failed_ = true;
+    FreeBuffer();
+    return false;
+  }
+}
+
+void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
+  if (buffer_ == NULL) {
+    buffer_.reset(new uint8_t[buffer_size_]);
+  }
+}
+
+void CopyingOutputStreamAdaptor::FreeBuffer() {
+  buffer_used_ = 0;
+  buffer_.reset();
+}
+
+// ===================================================================
+
+LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
+                                         int64_t limit)
+    : input_(input), limit_(limit) {
+  prior_bytes_read_ = input_->ByteCount();
+}
+
+LimitingInputStream::~LimitingInputStream() {
+  // If we overshot the limit, back up.
+  if (limit_ < 0) input_->BackUp(-limit_);
+}
+
+bool LimitingInputStream::Next(const void** data, int* size) {
+  if (limit_ <= 0) return false;
+  if (!input_->Next(data, size)) return false;
+
+  limit_ -= *size;
+  if (limit_ < 0) {
+    // We overshot the limit.  Reduce *size to hide the rest of the buffer.
+    *size += limit_;
+  }
+  return true;
+}
+
+void LimitingInputStream::BackUp(int count) {
+  if (limit_ < 0) {
+    input_->BackUp(count - limit_);
+    limit_ = count;
+  } else {
+    input_->BackUp(count);
+    limit_ += count;
+  }
+}
+
+bool LimitingInputStream::Skip(int count) {
+  if (count > limit_) {
+    if (limit_ < 0) return false;
+    input_->Skip(limit_);
+    limit_ = 0;
+    return false;
+  } else {
+    if (!input_->Skip(count)) return false;
+    limit_ -= count;
+    return true;
+  }
+}
+
+int64_t LimitingInputStream::ByteCount() const {
+  if (limit_ < 0) {
+    return input_->ByteCount() + limit_ - prior_bytes_read_;
+  } else {
+    return input_->ByteCount() - prior_bytes_read_;
+  }
+}
+
+
+// ===================================================================
+
+}  // namespace io
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/map.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/map.cpp
new file mode 100644
index 0000000..d60a9a2
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/map.cpp
@@ -0,0 +1,41 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/map.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void* const kGlobalEmptyTable[kGlobalEmptyTableSize] = {nullptr};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/map_field.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/map_field.cpp
new file mode 100644
index 0000000..ed662df
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/map_field.cpp
@@ -0,0 +1,654 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/map_field.h>
+
+#include <vector>
+
+#include <google/protobuf/map_field_inl.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+void MapFieldBase::Destruct() {
+  if (arena_ == nullptr) {
+    delete repeated_field_;
+  }
+  repeated_field_ = nullptr;
+}
+
+const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
+  ConstAccess();
+  SyncRepeatedFieldWithMap();
+  return *reinterpret_cast<RepeatedPtrFieldBase*>(repeated_field_);
+}
+
+RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() {
+  MutableAccess();
+  SyncRepeatedFieldWithMap();
+  SetRepeatedDirty();
+  return reinterpret_cast<RepeatedPtrFieldBase*>(repeated_field_);
+}
+
+void MapFieldBase::SwapState(MapFieldBase* other) {
+  // a relaxed swap of the atomic
+  auto other_state = other->state_.load(std::memory_order_relaxed);
+  auto this_state = state_.load(std::memory_order_relaxed);
+  other->state_.store(this_state, std::memory_order_relaxed);
+  state_.store(other_state, std::memory_order_relaxed);
+}
+
+void SwapRepeatedPtrToNull(RepeatedPtrField<Message>** from,
+                           RepeatedPtrField<Message>** to, Arena* from_arena,
+                           Arena* to_arena) {
+  GOOGLE_DCHECK(*from != nullptr);
+  GOOGLE_DCHECK(*to == nullptr);
+  *to = Arena::CreateMessage<RepeatedPtrField<Message> >(to_arena);
+  **to = std::move(**from);
+  if (from_arena == nullptr) {
+    delete *from;
+  }
+  *from = nullptr;
+}
+
+void MapFieldBase::Swap(MapFieldBase* other) {
+  if (arena_ == other->arena_) {
+    InternalSwap(other);
+    return;
+  }
+  if (repeated_field_ != nullptr || other->repeated_field_ != nullptr) {
+    if (repeated_field_ == nullptr) {
+      SwapRepeatedPtrToNull(&other->repeated_field_, &repeated_field_,
+                            other->arena_, arena_);
+    } else if (other->repeated_field_ == nullptr) {
+      SwapRepeatedPtrToNull(&repeated_field_, &other->repeated_field_, arena_,
+                            other->arena_);
+    } else {
+      repeated_field_->Swap(other->repeated_field_);
+    }
+  }
+  SwapState(other);
+}
+
+void MapFieldBase::UnsafeShallowSwap(MapFieldBase* other) {
+  GOOGLE_DCHECK_EQ(arena_, other->arena_);
+  InternalSwap(other);
+}
+
+void MapFieldBase::InternalSwap(MapFieldBase* other) {
+  std::swap(arena_, other->arena_);
+  std::swap(repeated_field_, other->repeated_field_);
+  SwapState(other);
+}
+
+size_t MapFieldBase::SpaceUsedExcludingSelfLong() const {
+  ConstAccess();
+  mutex_.Lock();
+  size_t size = SpaceUsedExcludingSelfNoLock();
+  mutex_.Unlock();
+  ConstAccess();
+  return size;
+}
+
+size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
+  if (repeated_field_ != nullptr) {
+    return repeated_field_->SpaceUsedExcludingSelfLong();
+  } else {
+    return 0;
+  }
+}
+
+bool MapFieldBase::IsMapValid() const {
+  ConstAccess();
+  // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
+  // executed before state_ is checked.
+  int state = state_.load(std::memory_order_acquire);
+  return state != STATE_MODIFIED_REPEATED;
+}
+
+bool MapFieldBase::IsRepeatedFieldValid() const {
+  ConstAccess();
+  int state = state_.load(std::memory_order_acquire);
+  return state != STATE_MODIFIED_MAP;
+}
+
+void MapFieldBase::SetMapDirty() {
+  MutableAccess();
+  // These are called by (non-const) mutator functions. So by our API it's the
+  // callers responsibility to have these calls properly ordered.
+  state_.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
+}
+
+void MapFieldBase::SetRepeatedDirty() {
+  MutableAccess();
+  // These are called by (non-const) mutator functions. So by our API it's the
+  // callers responsibility to have these calls properly ordered.
+  state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
+}
+
+void MapFieldBase::SyncRepeatedFieldWithMap() const {
+  ConstAccess();
+  // acquire here matches with release below to ensure that we can only see a
+  // value of CLEAN after all previous changes have been synced.
+  switch (state_.load(std::memory_order_acquire)) {
+    case STATE_MODIFIED_MAP:
+      mutex_.Lock();
+      // Double check state, because another thread may have seen the same
+      // state and done the synchronization before the current thread.
+      if (state_.load(std::memory_order_relaxed) == STATE_MODIFIED_MAP) {
+        SyncRepeatedFieldWithMapNoLock();
+        state_.store(CLEAN, std::memory_order_release);
+      }
+      mutex_.Unlock();
+      ConstAccess();
+      break;
+    case CLEAN:
+      mutex_.Lock();
+      // Double check state
+      if (state_.load(std::memory_order_relaxed) == CLEAN) {
+        if (repeated_field_ == nullptr) {
+          repeated_field_ =
+              Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
+        }
+        state_.store(CLEAN, std::memory_order_release);
+      }
+      mutex_.Unlock();
+      ConstAccess();
+      break;
+    default:
+      break;
+  }
+}
+
+void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
+  if (repeated_field_ == nullptr) {
+    repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
+  }
+}
+
+void MapFieldBase::SyncMapWithRepeatedField() const {
+  ConstAccess();
+  // acquire here matches with release below to ensure that we can only see a
+  // value of CLEAN after all previous changes have been synced.
+  if (state_.load(std::memory_order_acquire) == STATE_MODIFIED_REPEATED) {
+    mutex_.Lock();
+    // Double check state, because another thread may have seen the same state
+    // and done the synchronization before the current thread.
+    if (state_.load(std::memory_order_relaxed) == STATE_MODIFIED_REPEATED) {
+      SyncMapWithRepeatedFieldNoLock();
+      state_.store(CLEAN, std::memory_order_release);
+    }
+    mutex_.Unlock();
+    ConstAccess();
+  }
+}
+
+// ------------------DynamicMapField------------------
+DynamicMapField::DynamicMapField(const Message* default_entry)
+    : default_entry_(default_entry) {}
+
+DynamicMapField::DynamicMapField(const Message* default_entry, Arena* arena)
+    : TypeDefinedMapFieldBase<MapKey, MapValueRef>(arena),
+      map_(arena),
+      default_entry_(default_entry) {}
+
+DynamicMapField::~DynamicMapField() {
+  if (arena_ == nullptr) {
+    // DynamicMapField owns map values. Need to delete them before clearing the
+    // map.
+    for (auto& kv : map_) {
+      kv.second.DeleteData();
+    }
+    map_.clear();
+  }
+  Destruct();
+}
+
+int DynamicMapField::size() const { return GetMap().size(); }
+
+void DynamicMapField::Clear() {
+  Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
+  if (MapFieldBase::arena_ == nullptr) {
+    for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
+         iter != map->end(); ++iter) {
+      iter->second.DeleteData();
+    }
+  }
+
+  map->clear();
+
+  if (MapFieldBase::repeated_field_ != nullptr) {
+    MapFieldBase::repeated_field_->Clear();
+  }
+  // Data in map and repeated field are both empty, but we can't set status
+  // CLEAN which will invalidate previous reference to map.
+  MapFieldBase::SetMapDirty();
+}
+
+bool DynamicMapField::ContainsMapKey(const MapKey& map_key) const {
+  const Map<MapKey, MapValueRef>& map = GetMap();
+  Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key);
+  return iter != map.end();
+}
+
+void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
+  const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
+  map_val->SetType(val_des->cpp_type());
+  // Allocate memory for the MapValueRef, and initialize to
+  // default value.
+  switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                 \
+    TYPE* value = Arena::Create<TYPE>(MapFieldBase::arena_); \
+    map_val->SetValue(value);                                \
+    break;                                                   \
+  }
+    HANDLE_TYPE(INT32, int32_t);
+    HANDLE_TYPE(INT64, int64_t);
+    HANDLE_TYPE(UINT32, uint32_t);
+    HANDLE_TYPE(UINT64, uint64_t);
+    HANDLE_TYPE(DOUBLE, double);
+    HANDLE_TYPE(FLOAT, float);
+    HANDLE_TYPE(BOOL, bool);
+    HANDLE_TYPE(STRING, std::string);
+    HANDLE_TYPE(ENUM, int32_t);
+#undef HANDLE_TYPE
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      const Message& message =
+          default_entry_->GetReflection()->GetMessage(*default_entry_, val_des);
+      Message* value = message.New(MapFieldBase::arena_);
+      map_val->SetValue(value);
+      break;
+    }
+  }
+}
+
+bool DynamicMapField::InsertOrLookupMapValue(const MapKey& map_key,
+                                             MapValueRef* val) {
+  // Always use mutable map because users may change the map value by
+  // MapValueRef.
+  Map<MapKey, MapValueRef>* map = MutableMap();
+  Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
+  if (iter == map->end()) {
+    MapValueRef& map_val = map_[map_key];
+    AllocateMapValue(&map_val);
+    val->CopyFrom(map_val);
+    return true;
+  }
+  // map_key is already in the map. Make sure (*map)[map_key] is not called.
+  // [] may reorder the map and iterators.
+  val->CopyFrom(iter->second);
+  return false;
+}
+
+bool DynamicMapField::LookupMapValue(const MapKey& map_key,
+                                     MapValueConstRef* val) const {
+  const Map<MapKey, MapValueRef>& map = GetMap();
+  Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key);
+  if (iter == map.end()) {
+    return false;
+  }
+  // map_key is already in the map. Make sure (*map)[map_key] is not called.
+  // [] may reorder the map and iterators.
+  val->CopyFrom(iter->second);
+  return true;
+}
+
+bool DynamicMapField::DeleteMapValue(const MapKey& map_key) {
+  MapFieldBase::SyncMapWithRepeatedField();
+  Map<MapKey, MapValueRef>::iterator iter = map_.find(map_key);
+  if (iter == map_.end()) {
+    return false;
+  }
+  // Set map dirty only if the delete is successful.
+  MapFieldBase::SetMapDirty();
+  if (MapFieldBase::arena_ == nullptr) {
+    iter->second.DeleteData();
+  }
+  map_.erase(iter);
+  return true;
+}
+
+const Map<MapKey, MapValueRef>& DynamicMapField::GetMap() const {
+  MapFieldBase::SyncMapWithRepeatedField();
+  return map_;
+}
+
+Map<MapKey, MapValueRef>* DynamicMapField::MutableMap() {
+  MapFieldBase::SyncMapWithRepeatedField();
+  MapFieldBase::SetMapDirty();
+  return &map_;
+}
+
+void DynamicMapField::SetMapIteratorValue(MapIterator* map_iter) const {
+  Map<MapKey, MapValueRef>::const_iterator iter =
+      TypeDefinedMapFieldBase<MapKey, MapValueRef>::InternalGetIterator(
+          map_iter);
+  if (iter == map_.end()) return;
+  map_iter->key_.CopyFrom(iter->first);
+  map_iter->value_.CopyFrom(iter->second);
+}
+
+void DynamicMapField::MergeFrom(const MapFieldBase& other) {
+  GOOGLE_DCHECK(IsMapValid() && other.IsMapValid());
+  Map<MapKey, MapValueRef>* map = MutableMap();
+  const DynamicMapField& other_field =
+      reinterpret_cast<const DynamicMapField&>(other);
+  for (Map<MapKey, MapValueRef>::const_iterator other_it =
+           other_field.map_.begin();
+       other_it != other_field.map_.end(); ++other_it) {
+    Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first);
+    MapValueRef* map_val;
+    if (iter == map->end()) {
+      map_val = &map_[other_it->first];
+      AllocateMapValue(map_val);
+    } else {
+      map_val = &iter->second;
+    }
+
+    // Copy map value
+    const FieldDescriptor* field_descriptor =
+        default_entry_->GetDescriptor()->map_value();
+    switch (field_descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32: {
+        map_val->SetInt32Value(other_it->second.GetInt32Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+        map_val->SetInt64Value(other_it->second.GetInt64Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        map_val->SetUInt32Value(other_it->second.GetUInt32Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        map_val->SetUInt64Value(other_it->second.GetUInt64Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_FLOAT: {
+        map_val->SetFloatValue(other_it->second.GetFloatValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_DOUBLE: {
+        map_val->SetDoubleValue(other_it->second.GetDoubleValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_BOOL: {
+        map_val->SetBoolValue(other_it->second.GetBoolValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+        map_val->SetStringValue(other_it->second.GetStringValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        map_val->SetEnumValue(other_it->second.GetEnumValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        map_val->MutableMessageValue()->CopyFrom(
+            other_it->second.GetMessageValue());
+        break;
+      }
+    }
+  }
+}
+
+void DynamicMapField::Swap(MapFieldBase* other) {
+  DynamicMapField* other_field = down_cast<DynamicMapField*>(other);
+  std::swap(this->MapFieldBase::repeated_field_, other_field->repeated_field_);
+  map_.swap(other_field->map_);
+  // a relaxed swap of the atomic
+  auto other_state = other_field->state_.load(std::memory_order_relaxed);
+  auto this_state = this->MapFieldBase::state_.load(std::memory_order_relaxed);
+  other_field->state_.store(this_state, std::memory_order_relaxed);
+  this->MapFieldBase::state_.store(other_state, std::memory_order_relaxed);
+}
+
+void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const {
+  const Reflection* reflection = default_entry_->GetReflection();
+  const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
+  const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
+  if (MapFieldBase::repeated_field_ == nullptr) {
+    MapFieldBase::repeated_field_ =
+        Arena::CreateMessage<RepeatedPtrField<Message> >(MapFieldBase::arena_);
+  }
+
+  MapFieldBase::repeated_field_->Clear();
+
+  for (Map<MapKey, MapValueRef>::const_iterator it = map_.begin();
+       it != map_.end(); ++it) {
+    Message* new_entry = default_entry_->New(MapFieldBase::arena_);
+    MapFieldBase::repeated_field_->AddAllocated(new_entry);
+    const MapKey& map_key = it->first;
+    switch (key_des->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        reflection->SetString(new_entry, key_des, map_key.GetStringValue());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        reflection->SetBool(new_entry, key_des, map_key.GetBoolValue());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Can't get here.";
+        break;
+    }
+    const MapValueRef& map_val = it->second;
+    switch (val_des->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        reflection->SetString(new_entry, val_des, map_val.GetStringValue());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        reflection->SetBool(new_entry, val_des, map_val.GetBoolValue());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue());
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue());
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        const Message& message = map_val.GetMessageValue();
+        reflection->MutableMessage(new_entry, val_des)->CopyFrom(message);
+        break;
+      }
+    }
+  }
+}
+
+void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const {
+  Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
+  const Reflection* reflection = default_entry_->GetReflection();
+  const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
+  const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
+  // DynamicMapField owns map values. Need to delete them before clearing
+  // the map.
+  if (MapFieldBase::arena_ == nullptr) {
+    for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
+         iter != map->end(); ++iter) {
+      iter->second.DeleteData();
+    }
+  }
+  map->clear();
+  for (RepeatedPtrField<Message>::iterator it =
+           MapFieldBase::repeated_field_->begin();
+       it != MapFieldBase::repeated_field_->end(); ++it) {
+    // MapKey type will be set later.
+    MapKey map_key;
+    switch (key_des->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_STRING:
+        map_key.SetStringValue(reflection->GetString(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        map_key.SetInt64Value(reflection->GetInt64(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        map_key.SetInt32Value(reflection->GetInt32(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        map_key.SetUInt64Value(reflection->GetUInt64(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        map_key.SetUInt32Value(reflection->GetUInt32(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        map_key.SetBoolValue(reflection->GetBool(*it, key_des));
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Can't get here.";
+        break;
+    }
+
+    if (MapFieldBase::arena_ == nullptr) {
+      // Remove existing map value with same key.
+      Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
+      if (iter != map->end()) {
+        iter->second.DeleteData();
+      }
+    }
+
+    MapValueRef& map_val = (*map)[map_key];
+    map_val.SetType(val_des->cpp_type());
+    switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD)                   \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                 \
+    TYPE* value = Arena::Create<TYPE>(MapFieldBase::arena_); \
+    *value = reflection->Get##METHOD(*it, val_des);          \
+    map_val.SetValue(value);                                 \
+    break;                                                   \
+  }
+      HANDLE_TYPE(INT32, int32_t, Int32);
+      HANDLE_TYPE(INT64, int64_t, Int64);
+      HANDLE_TYPE(UINT32, uint32_t, UInt32);
+      HANDLE_TYPE(UINT64, uint64_t, UInt64);
+      HANDLE_TYPE(DOUBLE, double, Double);
+      HANDLE_TYPE(FLOAT, float, Float);
+      HANDLE_TYPE(BOOL, bool, Bool);
+      HANDLE_TYPE(STRING, std::string, String);
+      HANDLE_TYPE(ENUM, int32_t, EnumValue);
+#undef HANDLE_TYPE
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        const Message& message = reflection->GetMessage(*it, val_des);
+        Message* value = message.New(MapFieldBase::arena_);
+        value->CopyFrom(message);
+        map_val.SetValue(value);
+        break;
+      }
+    }
+  }
+}
+
+size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
+  size_t size = 0;
+  if (MapFieldBase::repeated_field_ != nullptr) {
+    size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelfLong();
+  }
+  size += sizeof(map_);
+  size_t map_size = map_.size();
+  if (map_size) {
+    Map<MapKey, MapValueRef>::const_iterator it = map_.begin();
+    size += sizeof(it->first) * map_size;
+    size += sizeof(it->second) * map_size;
+    // If key is string, add the allocated space.
+    if (it->first.type() == FieldDescriptor::CPPTYPE_STRING) {
+      size += sizeof(std::string) * map_size;
+    }
+    // Add the allocated space in MapValueRef.
+    switch (it->second.type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
+    size += sizeof(TYPE) * map_size;         \
+    break;                                   \
+  }
+      HANDLE_TYPE(INT32, int32_t);
+      HANDLE_TYPE(INT64, int64_t);
+      HANDLE_TYPE(UINT32, uint32_t);
+      HANDLE_TYPE(UINT64, uint64_t);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, std::string);
+      HANDLE_TYPE(ENUM, int32_t);
+#undef HANDLE_TYPE
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        while (it != map_.end()) {
+          const Message& message = it->second.GetMessageValue();
+          size += message.GetReflection()->SpaceUsedLong(message);
+          ++it;
+        }
+        break;
+      }
+    }
+  }
+  return size;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/message.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/message.cpp
new file mode 100644
index 0000000..6cdc6c8
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/message.cpp
@@ -0,0 +1,404 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/message.h>
+
+#include <iostream>
+#include <stack>
+#include <unordered_map>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/reflection_internal.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/hash.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+// TODO(gerbens) make this factorized better. This should not have to hop
+// to reflection. Currently uses GeneratedMessageReflection and thus is
+// defined in generated_message_reflection.cc
+void RegisterFileLevelMetadata(const DescriptorTable* descriptor_table);
+
+}  // namespace internal
+
+using internal::ReflectionOps;
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+void Message::MergeFrom(const Message& from) {
+  auto* class_to = GetClassData();
+  auto* class_from = from.GetClassData();
+  auto* merge_to_from = class_to ? class_to->merge_to_from : nullptr;
+  if (class_to == nullptr || class_to != class_from) {
+    merge_to_from = [](Message& to, const Message& from) {
+      ReflectionOps::Merge(from, &to);
+    };
+  }
+  merge_to_from(*this, from);
+}
+
+void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
+  MergeFrom(*down_cast<const Message*>(&other));
+}
+
+void Message::CopyFrom(const Message& from) {
+  if (&from == this) return;
+
+  auto* class_to = GetClassData();
+  auto* class_from = from.GetClassData();
+  auto* copy_to_from = class_to ? class_to->copy_to_from : nullptr;
+
+  if (class_to == nullptr || class_to != class_from) {
+    const Descriptor* descriptor = GetDescriptor();
+    GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
+        << ": Tried to copy from a message with a different type. "
+           "to: "
+        << descriptor->full_name()
+        << ", "
+           "from: "
+        << from.GetDescriptor()->full_name();
+    copy_to_from = [](Message& to, const Message& from) {
+      ReflectionOps::Copy(from, &to);
+    };
+  }
+  copy_to_from(*this, from);
+}
+
+void Message::CopyWithSourceCheck(Message& to, const Message& from) {
+#ifndef NDEBUG
+  FailIfCopyFromDescendant(to, from);
+#endif
+  to.Clear();
+  to.GetClassData()->merge_to_from(to, from);
+}
+
+void Message::FailIfCopyFromDescendant(Message& to, const Message& from) {
+  auto* arena = to.GetArenaForAllocation();
+  bool same_message_owned_arena = to.GetOwningArena() == nullptr &&
+                                  arena != nullptr &&
+                                  arena == from.GetOwningArena();
+  GOOGLE_CHECK(!same_message_owned_arena && !internal::IsDescendant(to, from))
+      << "Source of CopyFrom cannot be a descendant of the target.";
+}
+
+std::string Message::GetTypeName() const {
+  return GetDescriptor()->full_name();
+}
+
+void Message::Clear() { ReflectionOps::Clear(this); }
+
+bool Message::IsInitialized() const {
+  return ReflectionOps::IsInitialized(*this);
+}
+
+void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
+  return ReflectionOps::FindInitializationErrors(*this, "", errors);
+}
+
+std::string Message::InitializationErrorString() const {
+  std::vector<std::string> errors;
+  FindInitializationErrors(&errors);
+  return Join(errors, ", ");
+}
+
+void Message::CheckInitialized() const {
+  GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
+                         << "\" is missing required fields: "
+                         << InitializationErrorString();
+}
+
+void Message::DiscardUnknownFields() {
+  return ReflectionOps::DiscardUnknownFields(this);
+}
+
+const char* Message::_InternalParse(const char* ptr,
+                                    internal::ParseContext* ctx) {
+  return WireFormat::_InternalParse(this, ptr, ctx);
+}
+
+uint8_t* Message::_InternalSerialize(uint8_t* target,
+                                     io::EpsCopyOutputStream* stream) const {
+  return WireFormat::_InternalSerialize(*this, target, stream);
+}
+
+size_t Message::ByteSizeLong() const {
+  size_t size = WireFormat::ByteSize(*this);
+  SetCachedSize(internal::ToCachedSize(size));
+  return size;
+}
+
+void Message::SetCachedSize(int /* size */) const {
+  GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
+             << "\" implements neither SetCachedSize() nor ByteSize().  "
+                "Must implement one or the other.";
+}
+
+size_t Message::ComputeUnknownFieldsSize(
+    size_t total_size, internal::CachedSize* cached_size) const {
+  total_size += WireFormat::ComputeUnknownFieldsSize(
+      _internal_metadata_.unknown_fields<UnknownFieldSet>(
+          UnknownFieldSet::default_instance));
+  cached_size->Set(internal::ToCachedSize(total_size));
+  return total_size;
+}
+
+size_t Message::MaybeComputeUnknownFieldsSize(
+    size_t total_size, internal::CachedSize* cached_size) const {
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ComputeUnknownFieldsSize(total_size, cached_size);
+  }
+  cached_size->Set(internal::ToCachedSize(total_size));
+  return total_size;
+}
+
+size_t Message::SpaceUsedLong() const {
+  return GetReflection()->SpaceUsedLong(*this);
+}
+
+uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
+  return salt;
+}
+
+// =============================================================================
+// MessageFactory
+
+MessageFactory::~MessageFactory() {}
+
+namespace {
+
+
+#define HASH_MAP std::unordered_map
+#define STR_HASH_FXN hash<::google::protobuf::StringPiece>
+
+
+class GeneratedMessageFactory final : public MessageFactory {
+ public:
+  static GeneratedMessageFactory* singleton();
+
+  void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
+  void RegisterType(const Descriptor* descriptor, const Message* prototype);
+
+  // implements MessageFactory ---------------------------------------
+  const Message* GetPrototype(const Descriptor* type) override;
+
+ private:
+  // Only written at static init time, so does not require locking.
+  HASH_MAP<StringPiece, const google::protobuf::internal::DescriptorTable*,
+           STR_HASH_FXN>
+      file_map_;
+
+  internal::WrappedMutex mutex_;
+  // Initialized lazily, so requires locking.
+  std::unordered_map<const Descriptor*, const Message*> type_map_;
+};
+
+GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
+  static auto instance =
+      internal::OnShutdownDelete(new GeneratedMessageFactory);
+  return instance;
+}
+
+void GeneratedMessageFactory::RegisterFile(
+    const google::protobuf::internal::DescriptorTable* table) {
+  if (!InsertIfNotPresent(&file_map_, table->filename, table)) {
+    GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
+  }
+}
+
+void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
+                                           const Message* prototype) {
+  GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
+      << "Tried to register a non-generated type with the generated "
+         "type registry.";
+
+  // This should only be called as a result of calling a file registration
+  // function during GetPrototype(), in which case we already have locked
+  // the mutex.
+  mutex_.AssertHeld();
+  if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
+    GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
+  }
+}
+
+
+const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
+  {
+    ReaderMutexLock lock(&mutex_);
+    const Message* result = FindPtrOrNull(type_map_, type);
+    if (result != nullptr) return result;
+  }
+
+  // If the type is not in the generated pool, then we can't possibly handle
+  // it.
+  if (type->file()->pool() != DescriptorPool::generated_pool()) return nullptr;
+
+  // Apparently the file hasn't been registered yet.  Let's do that now.
+  const internal::DescriptorTable* registration_data =
+      FindPtrOrNull(file_map_, type->file()->name().c_str());
+  if (registration_data == nullptr) {
+    GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
+                   "registered: "
+                << type->file()->name();
+    return nullptr;
+  }
+
+  WriterMutexLock lock(&mutex_);
+
+  // Check if another thread preempted us.
+  const Message* result = FindPtrOrNull(type_map_, type);
+  if (result == nullptr) {
+    // Nope.  OK, register everything.
+    internal::RegisterFileLevelMetadata(registration_data);
+    // Should be here now.
+    result = FindPtrOrNull(type_map_, type);
+  }
+
+  if (result == nullptr) {
+    GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
+                << "registered: " << type->full_name();
+  }
+
+  return result;
+}
+
+}  // namespace
+
+MessageFactory* MessageFactory::generated_factory() {
+  return GeneratedMessageFactory::singleton();
+}
+
+void MessageFactory::InternalRegisterGeneratedFile(
+    const google::protobuf::internal::DescriptorTable* table) {
+  GeneratedMessageFactory::singleton()->RegisterFile(table);
+}
+
+void MessageFactory::InternalRegisterGeneratedMessage(
+    const Descriptor* descriptor, const Message* prototype) {
+  GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
+}
+
+
+namespace {
+template <typename T>
+T* GetSingleton() {
+  static T singleton;
+  return &singleton;
+}
+}  // namespace
+
+const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK(field->is_repeated());
+  switch (field->cpp_type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
+  case FieldDescriptor::CPPTYPE_##TYPE:   \
+    return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
+    HANDLE_PRIMITIVE_TYPE(INT32, int32_t)
+    HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t)
+    HANDLE_PRIMITIVE_TYPE(INT64, int64_t)
+    HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t)
+    HANDLE_PRIMITIVE_TYPE(FLOAT, float)
+    HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
+    HANDLE_PRIMITIVE_TYPE(BOOL, bool)
+    HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
+#undef HANDLE_PRIMITIVE_TYPE
+    case FieldDescriptor::CPPTYPE_STRING:
+      switch (field->options().ctype()) {
+        default:
+        case FieldOptions::STRING:
+          return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
+      }
+      break;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      if (field->is_map()) {
+        return GetSingleton<internal::MapFieldAccessor>();
+      } else {
+        return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
+      }
+  }
+  GOOGLE_LOG(FATAL) << "Should not reach here.";
+  return nullptr;
+}
+
+namespace internal {
+template <>
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
+// #240
+PROTOBUF_NOINLINE
+#endif
+    Message*
+    GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
+                                                  Arena* arena) {
+  return prototype->New(arena);
+}
+template <>
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
+// #240
+PROTOBUF_NOINLINE
+#endif
+    Arena*
+    GenericTypeHandler<Message>::GetOwningArena(Message* value) {
+  return value->GetOwningArena();
+}
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/message_lite.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/message_lite.cpp
new file mode 100644
index 0000000..da66c19
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/message_lite.cpp
@@ -0,0 +1,602 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Authors: wink@google.com (Wink Saville),
+//          kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/message_lite.h>
+
+#include <climits>
+#include <cstdint>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/mutex.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+std::string MessageLite::InitializationErrorString() const {
+  return "(cannot determine missing fields for lite message)";
+}
+
+std::string MessageLite::DebugString() const {
+  std::uintptr_t address = reinterpret_cast<std::uintptr_t>(this);
+  return StrCat("MessageLite at 0x", strings::Hex(address));
+}
+
+namespace {
+
+// When serializing, we first compute the byte size, then serialize the message.
+// If serialization produces a different number of bytes than expected, we
+// call this function, which crashes.  The problem could be due to a bug in the
+// protobuf implementation but is more likely caused by concurrent modification
+// of the message.  This function attempts to distinguish between the two and
+// provide a useful error message.
+void ByteSizeConsistencyError(size_t byte_size_before_serialization,
+                              size_t byte_size_after_serialization,
+                              size_t bytes_produced_by_serialization,
+                              const MessageLite& message) {
+  GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
+      << message.GetTypeName()
+      << " was modified concurrently during serialization.";
+  GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
+      << "Byte size calculation and serialization were inconsistent.  This "
+         "may indicate a bug in protocol buffers or it may be caused by "
+         "concurrent modification of "
+      << message.GetTypeName() << ".";
+  GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
+}
+
+std::string InitializationErrorMessage(const char* action,
+                                       const MessageLite& message) {
+  // Note:  We want to avoid depending on strutil in the lite library, otherwise
+  //   we'd use:
+  //
+  // return strings::Substitute(
+  //   "Can't $0 message of type \"$1\" because it is missing required "
+  //   "fields: $2",
+  //   action, message.GetTypeName(),
+  //   message.InitializationErrorString());
+
+  std::string result;
+  result += "Can't ";
+  result += action;
+  result += " message of type \"";
+  result += message.GetTypeName();
+  result += "\" because it is missing required fields: ";
+  result += message.InitializationErrorString();
+  return result;
+}
+
+inline StringPiece as_string_view(const void* data, int size) {
+  return StringPiece(static_cast<const char*>(data), size);
+}
+
+// Returns true of all required fields are present / have values.
+inline bool CheckFieldPresence(const internal::ParseContext& ctx,
+                               const MessageLite& msg,
+                               MessageLite::ParseFlags parse_flags) {
+  (void)ctx;  // Parameter is used by Google-internal code.
+  if (PROTOBUF_PREDICT_FALSE((parse_flags & MessageLite::kMergePartial) != 0)) {
+    return true;
+  }
+  return msg.IsInitializedWithErrors();
+}
+
+}  // namespace
+
+void MessageLite::LogInitializationErrorMessage() const {
+  GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *this);
+}
+
+namespace internal {
+
+template <bool aliasing>
+bool MergeFromImpl(StringPiece input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input);
+  ptr = msg->_InternalParse(ptr, &ctx);
+  // ctx has an explicit limit set (length of string_view).
+  if (PROTOBUF_PREDICT_TRUE(ptr && ctx.EndedAtLimit())) {
+    return CheckFieldPresence(ctx, *msg, parse_flags);
+  }
+  return false;
+}
+
+template <bool aliasing>
+bool MergeFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input);
+  ptr = msg->_InternalParse(ptr, &ctx);
+  // ctx has no explicit limit (hence we end on end of stream)
+  if (PROTOBUF_PREDICT_TRUE(ptr && ctx.EndedAtEndOfStream())) {
+    return CheckFieldPresence(ctx, *msg, parse_flags);
+  }
+  return false;
+}
+
+template <bool aliasing>
+bool MergeFromImpl(BoundedZCIS input, MessageLite* msg,
+                   MessageLite::ParseFlags parse_flags) {
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input.zcis, input.limit);
+  ptr = msg->_InternalParse(ptr, &ctx);
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
+  ctx.BackUp(ptr);
+  if (PROTOBUF_PREDICT_TRUE(ctx.EndedAtLimit())) {
+    return CheckFieldPresence(ctx, *msg, parse_flags);
+  }
+  return false;
+}
+
+template bool MergeFromImpl<false>(StringPiece input, MessageLite* msg,
+                                   MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<true>(StringPiece input, MessageLite* msg,
+                                  MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<false>(io::ZeroCopyInputStream* input,
+                                   MessageLite* msg,
+                                   MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<true>(io::ZeroCopyInputStream* input,
+                                  MessageLite* msg,
+                                  MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<false>(BoundedZCIS input, MessageLite* msg,
+                                   MessageLite::ParseFlags parse_flags);
+template bool MergeFromImpl<true>(BoundedZCIS input, MessageLite* msg,
+                                  MessageLite::ParseFlags parse_flags);
+
+}  // namespace internal
+
+class ZeroCopyCodedInputStream : public io::ZeroCopyInputStream {
+ public:
+  ZeroCopyCodedInputStream(io::CodedInputStream* cis) : cis_(cis) {}
+  bool Next(const void** data, int* size) final {
+    if (!cis_->GetDirectBufferPointer(data, size)) return false;
+    cis_->Skip(*size);
+    return true;
+  }
+  void BackUp(int count) final { cis_->Advance(-count); }
+  bool Skip(int count) final { return cis_->Skip(count); }
+  int64_t ByteCount() const final { return 0; }
+
+  bool aliasing_enabled() { return cis_->aliasing_enabled_; }
+
+ private:
+  io::CodedInputStream* cis_;
+};
+
+bool MessageLite::MergeFromImpl(io::CodedInputStream* input,
+                                MessageLite::ParseFlags parse_flags) {
+  ZeroCopyCodedInputStream zcis(input);
+  const char* ptr;
+  internal::ParseContext ctx(input->RecursionBudget(), zcis.aliasing_enabled(),
+                             &ptr, &zcis);
+  // MergePartialFromCodedStream allows terminating the wireformat by 0 or
+  // end-group tag. Leaving it up to the caller to verify correct ending by
+  // calling LastTagWas on input. We need to maintain this behavior.
+  ctx.TrackCorrectEnding();
+  ctx.data().pool = input->GetExtensionPool();
+  ctx.data().factory = input->GetExtensionFactory();
+  ptr = _InternalParse(ptr, &ctx);
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
+  ctx.BackUp(ptr);
+  if (!ctx.EndedAtEndOfStream()) {
+    GOOGLE_DCHECK_NE(ctx.LastTag(), 1);  // We can't end on a pushed limit.
+    if (ctx.IsExceedingLimit(ptr)) return false;
+    input->SetLastTag(ctx.LastTag());
+  } else {
+    input->SetConsumed();
+  }
+  return CheckFieldPresence(ctx, *this, parse_flags);
+}
+
+bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
+  return MergeFromImpl(input, kMergePartial);
+}
+
+bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
+  return MergeFromImpl(input, kMerge);
+}
+
+bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
+  Clear();
+  return MergeFromImpl(input, kParse);
+}
+
+bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
+  Clear();
+  return MergeFromImpl(input, kParsePartial);
+}
+
+bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+  return ParseFrom<kParse>(input);
+}
+
+bool MessageLite::ParsePartialFromZeroCopyStream(
+    io::ZeroCopyInputStream* input) {
+  return ParseFrom<kParsePartial>(input);
+}
+
+bool MessageLite::ParseFromFileDescriptor(int file_descriptor) {
+  io::FileInputStream input(file_descriptor);
+  return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool MessageLite::ParsePartialFromFileDescriptor(int file_descriptor) {
+  io::FileInputStream input(file_descriptor);
+  return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool MessageLite::ParseFromIstream(std::istream* input) {
+  io::IstreamInputStream zero_copy_input(input);
+  return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+bool MessageLite::ParsePartialFromIstream(std::istream* input) {
+  io::IstreamInputStream zero_copy_input(input);
+  return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+bool MessageLite::MergePartialFromBoundedZeroCopyStream(
+    io::ZeroCopyInputStream* input, int size) {
+  return ParseFrom<kMergePartial>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                                 int size) {
+  return ParseFrom<kMerge>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                                 int size) {
+  return ParseFrom<kParse>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
+    io::ZeroCopyInputStream* input, int size) {
+  return ParseFrom<kParsePartial>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::ParseFromString(ConstStringParam data) {
+  return ParseFrom<kParse>(data);
+}
+
+bool MessageLite::ParsePartialFromString(ConstStringParam data) {
+  return ParseFrom<kParsePartial>(data);
+}
+
+bool MessageLite::ParseFromArray(const void* data, int size) {
+  return ParseFrom<kParse>(as_string_view(data, size));
+}
+
+bool MessageLite::ParsePartialFromArray(const void* data, int size) {
+  return ParseFrom<kParsePartial>(as_string_view(data, size));
+}
+
+bool MessageLite::MergeFromString(ConstStringParam data) {
+  return ParseFrom<kMerge>(data);
+}
+
+
+// ===================================================================
+
+inline uint8_t* SerializeToArrayImpl(const MessageLite& msg, uint8_t* target,
+                                     int size) {
+  constexpr bool debug = false;
+  if (debug) {
+    // Force serialization to a stream with a block size of 1, which forces
+    // all writes to the stream to cross buffers triggering all fallback paths
+    // in the unittests when serializing to string / array.
+    io::ArrayOutputStream stream(target, size, 1);
+    uint8_t* ptr;
+    io::EpsCopyOutputStream out(
+        &stream, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
+        &ptr);
+    ptr = msg._InternalSerialize(ptr, &out);
+    out.Trim(ptr);
+    GOOGLE_DCHECK(!out.HadError() && stream.ByteCount() == size);
+    return target + size;
+  } else {
+    io::EpsCopyOutputStream out(
+        target, size,
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    auto res = msg._InternalSerialize(target, &out);
+    GOOGLE_DCHECK(target + size == res);
+    return res;
+  }
+}
+
+uint8_t* MessageLite::SerializeWithCachedSizesToArray(uint8_t* target) const {
+  // We only optimize this when using optimize_for = SPEED.  In other cases
+  // we just use the CodedOutputStream path.
+  return SerializeToArrayImpl(*this, target, GetCachedSize());
+}
+
+bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToCodedStream(output);
+}
+
+bool MessageLite::SerializePartialToCodedStream(
+    io::CodedOutputStream* output) const {
+  const size_t size = ByteSizeLong();  // Force size to be cached.
+  if (size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << size;
+    return false;
+  }
+
+  int original_byte_count = output->ByteCount();
+  SerializeWithCachedSizes(output);
+  if (output->HadError()) {
+    return false;
+  }
+  int final_byte_count = output->ByteCount();
+
+  if (final_byte_count - original_byte_count != static_cast<int64_t>(size)) {
+    ByteSizeConsistencyError(size, ByteSizeLong(),
+                             final_byte_count - original_byte_count, *this);
+  }
+
+  return true;
+}
+
+bool MessageLite::SerializeToZeroCopyStream(
+    io::ZeroCopyOutputStream* output) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToZeroCopyStream(output);
+}
+
+bool MessageLite::SerializePartialToZeroCopyStream(
+    io::ZeroCopyOutputStream* output) const {
+  const size_t size = ByteSizeLong();  // Force size to be cached.
+  if (size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << size;
+    return false;
+  }
+
+  uint8_t* target;
+  io::EpsCopyOutputStream stream(
+      output, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
+      &target);
+  target = _InternalSerialize(target, &stream);
+  stream.Trim(target);
+  if (stream.HadError()) return false;
+  return true;
+}
+
+bool MessageLite::SerializeToFileDescriptor(int file_descriptor) const {
+  io::FileOutputStream output(file_descriptor);
+  return SerializeToZeroCopyStream(&output) && output.Flush();
+}
+
+bool MessageLite::SerializePartialToFileDescriptor(int file_descriptor) const {
+  io::FileOutputStream output(file_descriptor);
+  return SerializePartialToZeroCopyStream(&output) && output.Flush();
+}
+
+bool MessageLite::SerializeToOstream(std::ostream* output) const {
+  {
+    io::OstreamOutputStream zero_copy_output(output);
+    if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
+  }
+  return output->good();
+}
+
+bool MessageLite::SerializePartialToOstream(std::ostream* output) const {
+  io::OstreamOutputStream zero_copy_output(output);
+  return SerializePartialToZeroCopyStream(&zero_copy_output);
+}
+
+bool MessageLite::AppendToString(std::string* output) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return AppendPartialToString(output);
+}
+
+bool MessageLite::AppendPartialToString(std::string* output) const {
+  size_t old_size = output->size();
+  size_t byte_size = ByteSizeLong();
+  if (byte_size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << byte_size;
+    return false;
+  }
+
+  STLStringResizeUninitializedAmortized(output, old_size + byte_size);
+  uint8_t* start =
+      reinterpret_cast<uint8_t*>(io::mutable_string_data(output) + old_size);
+  SerializeToArrayImpl(*this, start, byte_size);
+  return true;
+}
+
+bool MessageLite::SerializeToString(std::string* output) const {
+  output->clear();
+  return AppendToString(output);
+}
+
+bool MessageLite::SerializePartialToString(std::string* output) const {
+  output->clear();
+  return AppendPartialToString(output);
+}
+
+bool MessageLite::SerializeToArray(void* data, int size) const {
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToArray(data, size);
+}
+
+bool MessageLite::SerializePartialToArray(void* data, int size) const {
+  const size_t byte_size = ByteSizeLong();
+  if (byte_size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << byte_size;
+    return false;
+  }
+  if (size < static_cast<int64_t>(byte_size)) return false;
+  uint8_t* start = reinterpret_cast<uint8_t*>(data);
+  SerializeToArrayImpl(*this, start, byte_size);
+  return true;
+}
+
+std::string MessageLite::SerializeAsString() const {
+  // If the compiler implements the (Named) Return Value Optimization,
+  // the local variable 'output' will not actually reside on the stack
+  // of this function, but will be overlaid with the object that the
+  // caller supplied for the return value to be constructed in.
+  std::string output;
+  if (!AppendToString(&output)) output.clear();
+  return output;
+}
+
+std::string MessageLite::SerializePartialAsString() const {
+  std::string output;
+  if (!AppendPartialToString(&output)) output.clear();
+  return output;
+}
+
+
+namespace internal {
+
+MessageLite* NewFromPrototypeHelper(const MessageLite* prototype,
+                                    Arena* arena) {
+  return prototype->New(arena);
+}
+template <>
+void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
+                                            MessageLite* to) {
+  to->CheckTypeAndMergeFrom(from);
+}
+template <>
+void GenericTypeHandler<std::string>::Merge(const std::string& from,
+                                            std::string* to) {
+  *to = from;
+}
+
+// Non-inline implementations of InternalMetadata destructor
+// This is moved out of the header because the GOOGLE_DCHECK produces a lot of code.
+void InternalMetadata::CheckedDestruct() {
+  if (HasMessageOwnedArenaTag()) {
+    GOOGLE_DCHECK(!HasUnknownFieldsTag());
+    delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
+  }
+}
+
+// Non-inline variants of std::string specializations for
+// various InternalMetadata routines.
+template <>
+void InternalMetadata::DoClear<std::string>() {
+  mutable_unknown_fields<std::string>()->clear();
+}
+
+template <>
+void InternalMetadata::DoMergeFrom<std::string>(const std::string& other) {
+  mutable_unknown_fields<std::string>()->append(other);
+}
+
+template <>
+void InternalMetadata::DoSwap<std::string>(std::string* other) {
+  mutable_unknown_fields<std::string>()->swap(*other);
+}
+
+}  // namespace internal
+
+
+// ===================================================================
+// Shutdown support.
+
+namespace internal {
+
+struct ShutdownData {
+  ~ShutdownData() {
+    std::reverse(functions.begin(), functions.end());
+    for (auto pair : functions) pair.first(pair.second);
+  }
+
+  static ShutdownData* get() {
+    static auto* data = new ShutdownData;
+    return data;
+  }
+
+  std::vector<std::pair<void (*)(const void*), const void*>> functions;
+  Mutex mutex;
+};
+
+static void RunZeroArgFunc(const void* arg) {
+  void (*func)() = reinterpret_cast<void (*)()>(const_cast<void*>(arg));
+  func();
+}
+
+void OnShutdown(void (*func)()) {
+  OnShutdownRun(RunZeroArgFunc, reinterpret_cast<void*>(func));
+}
+
+void OnShutdownRun(void (*f)(const void*), const void* arg) {
+  auto shutdown_data = ShutdownData::get();
+  MutexLock lock(&shutdown_data->mutex);
+  shutdown_data->functions.push_back(std::make_pair(f, arg));
+}
+
+}  // namespace internal
+
+void ShutdownProtobufLibrary() {
+  // This function should be called only once, but accepts multiple calls.
+  static bool is_shutdown = false;
+  if (!is_shutdown) {
+    delete internal::ShutdownData::get();
+    is_shutdown = true;
+  }
+}
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/parse_context.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/parse_context.cpp
new file mode 100644
index 0000000..59852fd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/parse_context.cpp
@@ -0,0 +1,548 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/parse_context.h>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/endian.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format_lite.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+// Only call if at start of tag.
+bool ParseEndsInSlopRegion(const char* begin, int overrun, int depth) {
+  constexpr int kSlopBytes = EpsCopyInputStream::kSlopBytes;
+  GOOGLE_DCHECK_GE(overrun, 0);
+  GOOGLE_DCHECK_LE(overrun, kSlopBytes);
+  auto ptr = begin + overrun;
+  auto end = begin + kSlopBytes;
+  while (ptr < end) {
+    uint32_t tag;
+    ptr = ReadTag(ptr, &tag);
+    if (ptr == nullptr || ptr > end) return false;
+    // ending on 0 tag is allowed and is the major reason for the necessity of
+    // this function.
+    if (tag == 0) return true;
+    switch (tag & 7) {
+      case 0: {  // Varint
+        uint64_t val;
+        ptr = VarintParse(ptr, &val);
+        if (ptr == nullptr) return false;
+        break;
+      }
+      case 1: {  // fixed64
+        ptr += 8;
+        break;
+      }
+      case 2: {  // len delim
+        int32_t size = ReadSize(&ptr);
+        if (ptr == nullptr || size > end - ptr) return false;
+        ptr += size;
+        break;
+      }
+      case 3: {  // start group
+        depth++;
+        break;
+      }
+      case 4: {                    // end group
+        if (--depth < 0) return true;  // We exit early
+        break;
+      }
+      case 5: {  // fixed32
+        ptr += 4;
+        break;
+      }
+      default:
+        return false;  // Unknown wireformat
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+const char* EpsCopyInputStream::NextBuffer(int overrun, int depth) {
+  if (next_chunk_ == nullptr) return nullptr;  // We've reached end of stream.
+  if (next_chunk_ != buffer_) {
+    GOOGLE_DCHECK(size_ > kSlopBytes);
+    // The chunk is large enough to be used directly
+    buffer_end_ = next_chunk_ + size_ - kSlopBytes;
+    auto res = next_chunk_;
+    next_chunk_ = buffer_;
+    if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+    return res;
+  }
+  // Move the slop bytes of previous buffer to start of the patch buffer.
+  // Note we must use memmove because the previous buffer could be part of
+  // buffer_.
+  std::memmove(buffer_, buffer_end_, kSlopBytes);
+  if (overall_limit_ > 0 &&
+      (depth < 0 || !ParseEndsInSlopRegion(buffer_, overrun, depth))) {
+    const void* data;
+    // ZeroCopyInputStream indicates Next may return 0 size buffers. Hence
+    // we loop.
+    while (StreamNext(&data)) {
+      if (size_ > kSlopBytes) {
+        // We got a large chunk
+        std::memcpy(buffer_ + kSlopBytes, data, kSlopBytes);
+        next_chunk_ = static_cast<const char*>(data);
+        buffer_end_ = buffer_ + kSlopBytes;
+        if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
+        return buffer_;
+      } else if (size_ > 0) {
+        std::memcpy(buffer_ + kSlopBytes, data, size_);
+        next_chunk_ = buffer_;
+        buffer_end_ = buffer_ + size_;
+        if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
+        return buffer_;
+      }
+      GOOGLE_DCHECK(size_ == 0) << size_;
+    }
+    overall_limit_ = 0;  // Next failed, no more needs for next
+  }
+  // End of stream or array
+  if (aliasing_ == kNoDelta) {
+    // If there is no more block and aliasing is true, the previous block
+    // is still valid and we can alias. We have users relying on string_view's
+    // obtained from protos to outlive the proto, when the parse was from an
+    // array. This guarantees string_view's are always aliased if parsed from
+    // an array.
+    aliasing_ = reinterpret_cast<std::uintptr_t>(buffer_end_) -
+                reinterpret_cast<std::uintptr_t>(buffer_);
+  }
+  next_chunk_ = nullptr;
+  buffer_end_ = buffer_ + kSlopBytes;
+  size_ = 0;
+  return buffer_;
+}
+
+const char* EpsCopyInputStream::Next() {
+  GOOGLE_DCHECK(limit_ > kSlopBytes);
+  auto p = NextBuffer(0 /* immaterial */, -1);
+  if (p == nullptr) {
+    limit_end_ = buffer_end_;
+    // Distinguish ending on a pushed limit or ending on end-of-stream.
+    SetEndOfStream();
+    return nullptr;
+  }
+  limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
+  limit_end_ = buffer_end_ + std::min(0, limit_);
+  return p;
+}
+
+std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(int overrun,
+                                                              int depth) {
+  // Did we exceeded the limit (parse error).
+  if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
+  GOOGLE_DCHECK(overrun != limit_);  // Guaranteed by caller.
+  GOOGLE_DCHECK(overrun < limit_);   // Follows from above
+  // TODO(gerbens) Instead of this dcheck we could just assign, and remove
+  // updating the limit_end from PopLimit, ie.
+  // limit_end_ = buffer_end_ + (std::min)(0, limit_);
+  // if (ptr < limit_end_) return {ptr, false};
+  GOOGLE_DCHECK(limit_end_ == buffer_end_ + (std::min)(0, limit_));
+  // At this point we know the following assertion holds.
+  GOOGLE_DCHECK_GT(limit_, 0);
+  GOOGLE_DCHECK(limit_end_ == buffer_end_);  // because limit_ > 0
+  const char* p;
+  do {
+    // We are past the end of buffer_end_, in the slop region.
+    GOOGLE_DCHECK_GE(overrun, 0);
+    p = NextBuffer(overrun, depth);
+    if (p == nullptr) {
+      // We are at the end of the stream
+      if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
+      GOOGLE_DCHECK_GT(limit_, 0);
+      limit_end_ = buffer_end_;
+      // Distinguish ending on a pushed limit or ending on end-of-stream.
+      SetEndOfStream();
+      return {buffer_end_, true};
+    }
+    limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
+    p += overrun;
+    overrun = p - buffer_end_;
+  } while (overrun >= 0);
+  limit_end_ = buffer_end_ + std::min(0, limit_);
+  return {p, false};
+}
+
+const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
+  return AppendSize(ptr, size, [](const char* /*p*/, int /*s*/) {});
+}
+
+const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
+                                                   std::string* str) {
+  str->clear();
+  if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
+    // Reserve the string up to a static safe size. If strings are bigger than
+    // this we proceed by growing the string as needed. This protects against
+    // malicious payloads making protobuf hold on to a lot of memory.
+    str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
+  }
+  return AppendSize(ptr, size,
+                    [str](const char* p, int s) { str->append(p, s); });
+}
+
+const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
+                                                     std::string* str) {
+  if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
+    // Reserve the string up to a static safe size. If strings are bigger than
+    // this we proceed by growing the string as needed. This protects against
+    // malicious payloads making protobuf hold on to a lot of memory.
+    str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
+  }
+  return AppendSize(ptr, size,
+                    [str](const char* p, int s) { str->append(p, s); });
+}
+
+
+const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
+  zcis_ = zcis;
+  const void* data;
+  int size;
+  limit_ = INT_MAX;
+  if (zcis->Next(&data, &size)) {
+    overall_limit_ -= size;
+    if (size > kSlopBytes) {
+      auto ptr = static_cast<const char*>(data);
+      limit_ -= size - kSlopBytes;
+      limit_end_ = buffer_end_ = ptr + size - kSlopBytes;
+      next_chunk_ = buffer_;
+      if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+      return ptr;
+    } else {
+      limit_end_ = buffer_end_ = buffer_ + kSlopBytes;
+      next_chunk_ = buffer_;
+      auto ptr = buffer_ + 2 * kSlopBytes - size;
+      std::memcpy(ptr, data, size);
+      return ptr;
+    }
+  }
+  overall_limit_ = 0;
+  next_chunk_ = nullptr;
+  size_ = 0;
+  limit_end_ = buffer_end_ = buffer_;
+  return buffer_;
+}
+
+const char* ParseContext::ReadSizeAndPushLimitAndDepth(const char* ptr,
+                                                       int* old_limit) {
+  int size = ReadSize(&ptr);
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) {
+    *old_limit = 0;  // Make sure this isn't uninitialized even on error return
+    return nullptr;
+  }
+  *old_limit = PushLimit(ptr, size);
+  if (--depth_ < 0) return nullptr;
+  return ptr;
+}
+
+const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
+  int old;
+  ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
+  ptr = ptr ? msg->_InternalParse(ptr, this) : nullptr;
+  depth_++;
+  if (!PopLimit(old)) return nullptr;
+  return ptr;
+}
+
+inline void WriteVarint(uint64_t val, std::string* s) {
+  while (val >= 128) {
+    uint8_t c = val | 0x80;
+    s->push_back(c);
+    val >>= 7;
+  }
+  s->push_back(val);
+}
+
+void WriteVarint(uint32_t num, uint64_t val, std::string* s) {
+  WriteVarint(num << 3, s);
+  WriteVarint(val, s);
+}
+
+void WriteLengthDelimited(uint32_t num, StringPiece val, std::string* s) {
+  WriteVarint((num << 3) + 2, s);
+  WriteVarint(val.size(), s);
+  s->append(val.data(), val.size());
+}
+
+std::pair<const char*, uint32_t> VarintParseSlow32(const char* p,
+                                                   uint32_t res) {
+  for (std::uint32_t i = 2; i < 5; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  // Accept >5 bytes
+  for (std::uint32_t i = 5; i < 10; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint64_t> VarintParseSlow64(const char* p,
+                                                   uint32_t res32) {
+  uint64_t res = res32;
+  for (std::uint32_t i = 2; i < 10; i++) {
+    uint64_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res) {
+  for (std::uint32_t i = 2; i < 5; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t res) {
+  for (std::uint32_t i = 1; i < 4; i++) {
+    uint32_t byte = static_cast<uint8_t>(p[i]);
+    res += (byte - 1) << (7 * i);
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res};
+    }
+  }
+  std::uint32_t byte = static_cast<uint8_t>(p[4]);
+  if (PROTOBUF_PREDICT_FALSE(byte >= 8)) return {nullptr, 0};  // size >= 2gb
+  res += (byte - 1) << 28;
+  // Protect against sign integer overflow in PushLimit. Limits are relative
+  // to buffer ends and ptr could potential be kSlopBytes beyond a buffer end.
+  // To protect against overflow we reject limits absurdly close to INT_MAX.
+  if (PROTOBUF_PREDICT_FALSE(res > INT_MAX - ParseContext::kSlopBytes)) {
+    return {nullptr, 0};
+  }
+  return {p + 5, res};
+}
+
+const char* StringParser(const char* begin, const char* end, void* object,
+                         ParseContext*) {
+  auto str = static_cast<std::string*>(object);
+  str->append(begin, end - begin);
+  return end;
+}
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
+                       bool emit_stacktrace);
+
+bool VerifyUTF8(StringPiece str, const char* field_name) {
+  if (!IsStructurallyValidUTF8(str)) {
+    PrintUTF8ErrorLog("", field_name, "parsing", false);
+    return false;
+  }
+  return true;
+}
+
+const char* InlineGreedyStringParser(std::string* s, const char* ptr,
+                                     ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+  return ctx->ReadString(ptr, size, s);
+}
+
+
+template <typename T, bool sign>
+const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
+  return ctx->ReadPackedVarint(ptr, [object](uint64_t varint) {
+    T val;
+    if (sign) {
+      if (sizeof(T) == 8) {
+        val = WireFormatLite::ZigZagDecode64(varint);
+      } else {
+        val = WireFormatLite::ZigZagDecode32(varint);
+      }
+    } else {
+      val = varint;
+    }
+    static_cast<RepeatedField<T>*>(object)->Add(val);
+  });
+}
+
+const char* PackedInt32Parser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return VarintParser<int32_t, false>(object, ptr, ctx);
+}
+const char* PackedUInt32Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<uint32_t, false>(object, ptr, ctx);
+}
+const char* PackedInt64Parser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return VarintParser<int64_t, false>(object, ptr, ctx);
+}
+const char* PackedUInt64Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<uint64_t, false>(object, ptr, ctx);
+}
+const char* PackedSInt32Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<int32_t, true>(object, ptr, ctx);
+}
+const char* PackedSInt64Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<int64_t, true>(object, ptr, ctx);
+}
+
+const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
+  return VarintParser<int, false>(object, ptr, ctx);
+}
+
+const char* PackedBoolParser(void* object, const char* ptr, ParseContext* ctx) {
+  return VarintParser<bool, false>(object, ptr, ctx);
+}
+
+template <typename T>
+const char* FixedParser(void* object, const char* ptr, ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  return ctx->ReadPackedFixed(ptr, size,
+                              static_cast<RepeatedField<T>*>(object));
+}
+
+const char* PackedFixed32Parser(void* object, const char* ptr,
+                                ParseContext* ctx) {
+  return FixedParser<uint32_t>(object, ptr, ctx);
+}
+const char* PackedSFixed32Parser(void* object, const char* ptr,
+                                 ParseContext* ctx) {
+  return FixedParser<int32_t>(object, ptr, ctx);
+}
+const char* PackedFixed64Parser(void* object, const char* ptr,
+                                ParseContext* ctx) {
+  return FixedParser<uint64_t>(object, ptr, ctx);
+}
+const char* PackedSFixed64Parser(void* object, const char* ptr,
+                                 ParseContext* ctx) {
+  return FixedParser<int64_t>(object, ptr, ctx);
+}
+const char* PackedFloatParser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return FixedParser<float>(object, ptr, ctx);
+}
+const char* PackedDoubleParser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return FixedParser<double>(object, ptr, ctx);
+}
+
+class UnknownFieldLiteParserHelper {
+ public:
+  explicit UnknownFieldLiteParserHelper(std::string* unknown)
+      : unknown_(unknown) {}
+
+  void AddVarint(uint32_t num, uint64_t value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8, unknown_);
+    WriteVarint(value, unknown_);
+  }
+  void AddFixed64(uint32_t num, uint64_t value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 1, unknown_);
+    char buffer[8];
+    io::CodedOutputStream::WriteLittleEndian64ToArray(
+        value, reinterpret_cast<uint8_t*>(buffer));
+    unknown_->append(buffer, 8);
+  }
+  const char* ParseLengthDelimited(uint32_t num, const char* ptr,
+                                   ParseContext* ctx) {
+    int size = ReadSize(&ptr);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (unknown_ == nullptr) return ctx->Skip(ptr, size);
+    WriteVarint(num * 8 + 2, unknown_);
+    WriteVarint(size, unknown_);
+    return ctx->AppendString(ptr, size, unknown_);
+  }
+  const char* ParseGroup(uint32_t num, const char* ptr, ParseContext* ctx) {
+    if (unknown_) WriteVarint(num * 8 + 3, unknown_);
+    ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (unknown_) WriteVarint(num * 8 + 4, unknown_);
+    return ptr;
+  }
+  void AddFixed32(uint32_t num, uint32_t value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 5, unknown_);
+    char buffer[4];
+    io::CodedOutputStream::WriteLittleEndian32ToArray(
+        value, reinterpret_cast<uint8_t*>(buffer));
+    unknown_->append(buffer, 4);
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return WireFormatParser(*this, ptr, ctx);
+  }
+
+ private:
+  std::string* unknown_;
+};
+
+const char* UnknownGroupLiteParse(std::string* unknown, const char* ptr,
+                                  ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(unknown);
+  return WireFormatParser(field_parser, ptr, ctx);
+}
+
+const char* UnknownFieldParse(uint32_t tag, std::string* unknown,
+                              const char* ptr, ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(unknown);
+  return FieldParser(tag, field_parser, ptr, ctx);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/reflection_ops.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/reflection_ops.cpp
new file mode 100644
index 0000000..3a1972e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/reflection_ops.cpp
@@ -0,0 +1,459 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/reflection_ops.h>
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/unknown_field_set.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+static const Reflection* GetReflectionOrDie(const Message& m) {
+  const Reflection* r = m.GetReflection();
+  if (r == nullptr) {
+    const Descriptor* d = m.GetDescriptor();
+    const std::string& mtype = d ? d->name() : "unknown";
+    // RawMessage is one known type for which GetReflection() returns nullptr.
+    GOOGLE_LOG(FATAL) << "Message does not support reflection (type " << mtype << ").";
+  }
+  return r;
+}
+
+void ReflectionOps::Copy(const Message& from, Message* to) {
+  if (&from == to) return;
+  Clear(to);
+  Merge(from, to);
+}
+
+void ReflectionOps::Merge(const Message& from, Message* to) {
+  GOOGLE_CHECK_NE(&from, to);
+
+  const Descriptor* descriptor = from.GetDescriptor();
+  GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
+      << "Tried to merge messages of different types "
+      << "(merge " << descriptor->full_name() << " to "
+      << to->GetDescriptor()->full_name() << ")";
+
+  const Reflection* from_reflection = GetReflectionOrDie(from);
+  const Reflection* to_reflection = GetReflectionOrDie(*to);
+  bool is_from_generated = (from_reflection->GetMessageFactory() ==
+                            google::protobuf::MessageFactory::generated_factory());
+  bool is_to_generated = (to_reflection->GetMessageFactory() ==
+                          google::protobuf::MessageFactory::generated_factory());
+
+  std::vector<const FieldDescriptor*> fields;
+  from_reflection->ListFieldsOmitStripped(from, &fields);
+  for (const FieldDescriptor* field : fields) {
+    if (field->is_repeated()) {
+      // Use map reflection if both are in map status and have the
+      // same map type to avoid sync with repeated field.
+      // Note: As from and to messages have the same descriptor, the
+      // map field types are the same if they are both generated
+      // messages or both dynamic messages.
+      if (is_from_generated == is_to_generated && field->is_map()) {
+        const MapFieldBase* from_field =
+            from_reflection->GetMapData(from, field);
+        MapFieldBase* to_field = to_reflection->MutableMapData(to, field);
+        if (to_field->IsMapValid() && from_field->IsMapValid()) {
+          to_field->MergeFrom(*from_field);
+          continue;
+        }
+      }
+      int count = from_reflection->FieldSize(from, field);
+      for (int j = 0; j < count; j++) {
+        switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD)                                      \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                                \
+    to_reflection->Add##METHOD(                                           \
+        to, field, from_reflection->GetRepeated##METHOD(from, field, j)); \
+    break;
+
+          HANDLE_TYPE(INT32, Int32);
+          HANDLE_TYPE(INT64, Int64);
+          HANDLE_TYPE(UINT32, UInt32);
+          HANDLE_TYPE(UINT64, UInt64);
+          HANDLE_TYPE(FLOAT, Float);
+          HANDLE_TYPE(DOUBLE, Double);
+          HANDLE_TYPE(BOOL, Bool);
+          HANDLE_TYPE(STRING, String);
+          HANDLE_TYPE(ENUM, Enum);
+#undef HANDLE_TYPE
+
+          case FieldDescriptor::CPPTYPE_MESSAGE:
+            const Message& from_child =
+                from_reflection->GetRepeatedMessage(from, field, j);
+            if (from_reflection == to_reflection) {
+              to_reflection
+                  ->AddMessage(to, field,
+                               from_child.GetReflection()->GetMessageFactory())
+                  ->MergeFrom(from_child);
+            } else {
+              to_reflection->AddMessage(to, field)->MergeFrom(from_child);
+            }
+            break;
+        }
+      }
+    } else {
+      switch (field->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD)                                       \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                                 \
+    to_reflection->Set##METHOD(to, field,                                  \
+                               from_reflection->Get##METHOD(from, field)); \
+    break;
+
+        HANDLE_TYPE(INT32, Int32);
+        HANDLE_TYPE(INT64, Int64);
+        HANDLE_TYPE(UINT32, UInt32);
+        HANDLE_TYPE(UINT64, UInt64);
+        HANDLE_TYPE(FLOAT, Float);
+        HANDLE_TYPE(DOUBLE, Double);
+        HANDLE_TYPE(BOOL, Bool);
+        HANDLE_TYPE(STRING, String);
+        HANDLE_TYPE(ENUM, Enum);
+#undef HANDLE_TYPE
+
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          const Message& from_child = from_reflection->GetMessage(from, field);
+          if (from_reflection == to_reflection) {
+            to_reflection
+                ->MutableMessage(
+                    to, field, from_child.GetReflection()->GetMessageFactory())
+                ->MergeFrom(from_child);
+          } else {
+            to_reflection->MutableMessage(to, field)->MergeFrom(from_child);
+          }
+          break;
+      }
+    }
+  }
+
+  if (!from_reflection->GetUnknownFields(from).empty()) {
+    to_reflection->MutableUnknownFields(to)->MergeFrom(
+        from_reflection->GetUnknownFields(from));
+  }
+}
+
+void ReflectionOps::Clear(Message* message) {
+  const Reflection* reflection = GetReflectionOrDie(*message);
+
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFieldsOmitStripped(*message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    reflection->ClearField(message, field);
+  }
+
+  if (reflection->GetInternalMetadata(*message).have_unknown_fields()) {
+    reflection->MutableUnknownFields(message)->Clear();
+  }
+}
+
+bool ReflectionOps::IsInitialized(const Message& message, bool check_fields,
+                                  bool check_descendants) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = GetReflectionOrDie(message);
+  if (const int field_count = descriptor->field_count()) {
+    const FieldDescriptor* begin = descriptor->field(0);
+    const FieldDescriptor* end = begin + field_count;
+    GOOGLE_DCHECK_EQ(descriptor->field(field_count - 1), end - 1);
+
+    if (check_fields) {
+      // Check required fields of this message.
+      for (const FieldDescriptor* field = begin; field != end; ++field) {
+        if (field->is_required() && !reflection->HasField(message, field)) {
+          return false;
+        }
+      }
+    }
+
+    if (check_descendants) {
+      for (const FieldDescriptor* field = begin; field != end; ++field) {
+        if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          const Descriptor* message_type = field->message_type();
+          if (PROTOBUF_PREDICT_FALSE(message_type->options().map_entry())) {
+            if (message_type->field(1)->cpp_type() ==
+                FieldDescriptor::CPPTYPE_MESSAGE) {
+              const MapFieldBase* map_field =
+                  reflection->GetMapData(message, field);
+              if (map_field->IsMapValid()) {
+                MapIterator it(const_cast<Message*>(&message), field);
+                MapIterator end_map(const_cast<Message*>(&message), field);
+                for (map_field->MapBegin(&it), map_field->MapEnd(&end_map);
+                     it != end_map; ++it) {
+                  if (!it.GetValueRef().GetMessageValue().IsInitialized()) {
+                    return false;
+                  }
+                }
+              }
+            }
+          } else if (field->is_repeated()) {
+            const int size = reflection->FieldSize(message, field);
+            for (int j = 0; j < size; j++) {
+              if (!reflection->GetRepeatedMessage(message, field, j)
+                       .IsInitialized()) {
+                return false;
+              }
+            }
+          } else if (reflection->HasField(message, field)) {
+            if (!reflection->GetMessage(message, field).IsInitialized()) {
+              return false;
+            }
+          }
+        }
+      }
+    }
+  }
+  if (check_descendants && reflection->HasExtensionSet(message) &&
+      !reflection->GetExtensionSet(message).IsInitialized()) {
+    return false;
+  }
+  return true;
+}
+
+bool ReflectionOps::IsInitialized(const Message& message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = GetReflectionOrDie(message);
+
+  // Check required fields of this message.
+  {
+    const int field_count = descriptor->field_count();
+    for (int i = 0; i < field_count; i++) {
+      if (descriptor->field(i)->is_required()) {
+        if (!reflection->HasField(message, descriptor->field(i))) {
+          return false;
+        }
+      }
+    }
+  }
+
+  // Check that sub-messages are initialized.
+  std::vector<const FieldDescriptor*> fields;
+  // Should be safe to skip stripped fields because required fields are not
+  // stripped.
+  reflection->ListFieldsOmitStripped(message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+      if (field->is_map()) {
+        const FieldDescriptor* value_field = field->message_type()->field(1);
+        if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          const MapFieldBase* map_field =
+              reflection->GetMapData(message, field);
+          if (map_field->IsMapValid()) {
+            MapIterator iter(const_cast<Message*>(&message), field);
+            MapIterator end(const_cast<Message*>(&message), field);
+            for (map_field->MapBegin(&iter), map_field->MapEnd(&end);
+                 iter != end; ++iter) {
+              if (!iter.GetValueRef().GetMessageValue().IsInitialized()) {
+                return false;
+              }
+            }
+            continue;
+          }
+        } else {
+          continue;
+        }
+      }
+
+      if (field->is_repeated()) {
+        int size = reflection->FieldSize(message, field);
+
+        for (int j = 0; j < size; j++) {
+          if (!reflection->GetRepeatedMessage(message, field, j)
+                   .IsInitialized()) {
+            return false;
+          }
+        }
+      } else {
+        if (!reflection->GetMessage(message, field).IsInitialized()) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+static bool IsMapValueMessageTyped(const FieldDescriptor* map_field) {
+  return map_field->message_type()->field(1)->cpp_type() ==
+         FieldDescriptor::CPPTYPE_MESSAGE;
+}
+
+void ReflectionOps::DiscardUnknownFields(Message* message) {
+  const Reflection* reflection = GetReflectionOrDie(*message);
+
+  reflection->MutableUnknownFields(message)->Clear();
+
+  // Walk through the fields of this message and DiscardUnknownFields on any
+  // messages present.
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    // Skip over non-message fields.
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+      continue;
+    }
+    // Discard the unknown fields in maps that contain message values.
+    if (field->is_map() && IsMapValueMessageTyped(field)) {
+      const MapFieldBase* map_field =
+          reflection->MutableMapData(message, field);
+      if (map_field->IsMapValid()) {
+        MapIterator iter(message, field);
+        MapIterator end(message, field);
+        for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end;
+             ++iter) {
+          iter.MutableValueRef()->MutableMessageValue()->DiscardUnknownFields();
+        }
+      }
+      // Discard every unknown field inside messages in a repeated field.
+    } else if (field->is_repeated()) {
+      int size = reflection->FieldSize(*message, field);
+      for (int j = 0; j < size; j++) {
+        reflection->MutableRepeatedMessage(message, field, j)
+            ->DiscardUnknownFields();
+      }
+      // Discard the unknown fields inside an optional message.
+    } else {
+      reflection->MutableMessage(message, field)->DiscardUnknownFields();
+    }
+  }
+}
+
+static std::string SubMessagePrefix(const std::string& prefix,
+                                    const FieldDescriptor* field, int index) {
+  std::string result(prefix);
+  if (field->is_extension()) {
+    result.append("(");
+    result.append(field->full_name());
+    result.append(")");
+  } else {
+    result.append(field->name());
+  }
+  if (index != -1) {
+    result.append("[");
+    result.append(StrCat(index));
+    result.append("]");
+  }
+  result.append(".");
+  return result;
+}
+
+void ReflectionOps::FindInitializationErrors(const Message& message,
+                                             const std::string& prefix,
+                                             std::vector<std::string>* errors) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* reflection = GetReflectionOrDie(message);
+
+  // Check required fields of this message.
+  {
+    const int field_count = descriptor->field_count();
+    for (int i = 0; i < field_count; i++) {
+      if (descriptor->field(i)->is_required()) {
+        if (!reflection->HasField(message, descriptor->field(i))) {
+          errors->push_back(prefix + descriptor->field(i)->name());
+        }
+      }
+    }
+  }
+
+  // Check sub-messages.
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFieldsOmitStripped(message, &fields);
+  for (const FieldDescriptor* field : fields) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+      if (field->is_repeated()) {
+        int size = reflection->FieldSize(message, field);
+
+        for (int j = 0; j < size; j++) {
+          const Message& sub_message =
+              reflection->GetRepeatedMessage(message, field, j);
+          FindInitializationErrors(sub_message,
+                                   SubMessagePrefix(prefix, field, j), errors);
+        }
+      } else {
+        const Message& sub_message = reflection->GetMessage(message, field);
+        FindInitializationErrors(sub_message,
+                                 SubMessagePrefix(prefix, field, -1), errors);
+      }
+    }
+  }
+}
+
+void GenericSwap(Message* lhs, Message* rhs) {
+#ifndef PROTOBUF_FORCE_COPY_IN_SWAP
+  GOOGLE_DCHECK(Arena::InternalGetOwningArena(lhs) !=
+         Arena::InternalGetOwningArena(rhs));
+  GOOGLE_DCHECK(Arena::InternalGetOwningArena(lhs) != nullptr ||
+         Arena::InternalGetOwningArena(rhs) != nullptr);
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+  // At least one of these must have an arena, so make `rhs` point to it.
+  Arena* arena = Arena::InternalGetOwningArena(rhs);
+  if (arena == nullptr) {
+    std::swap(lhs, rhs);
+    arena = Arena::InternalGetOwningArena(rhs);
+  }
+
+  // Improve efficiency by placing the temporary on an arena so that messages
+  // are copied twice rather than three times.
+  Message* tmp = rhs->New(arena);
+  tmp->CheckTypeAndMergeFrom(*lhs);
+  lhs->Clear();
+  lhs->CheckTypeAndMergeFrom(*rhs);
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+  rhs->Clear();
+  rhs->CheckTypeAndMergeFrom(*tmp);
+  if (arena == nullptr) delete tmp;
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+  rhs->GetReflection()->Swap(tmp, rhs);
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/repeated_field.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/repeated_field.cpp
new file mode 100644
index 0000000..7264d0a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/repeated_field.cpp
@@ -0,0 +1,71 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/repeated_field.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<bool>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<uint64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<float>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<double>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedPtrField<std::string>;
+
+namespace internal {
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<bool>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<int32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<uint32_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<int64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<uint64_t>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<float>;
+template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedIterator<double>;
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/repeated_ptr_field.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/repeated_ptr_field.cpp
new file mode 100644
index 0000000..8e86727
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/repeated_ptr_field.cpp
@@ -0,0 +1,152 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/port.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
+  int new_size = current_size_ + extend_amount;
+  if (total_size_ >= new_size) {
+    // N.B.: rep_ is non-nullptr because extend_amount is always > 0, hence
+    // total_size must be non-zero since it is lower-bounded by new_size.
+    return &rep_->elements[current_size_];
+  }
+  Rep* old_rep = rep_;
+  Arena* arena = GetOwningArena();
+  new_size = internal::CalculateReserveSize<void*, kRepHeaderSize>(total_size_,
+                                                                   new_size);
+  GOOGLE_CHECK_LE(static_cast<int64_t>(new_size),
+           static_cast<int64_t>(
+               (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
+               sizeof(old_rep->elements[0])))
+      << "Requested size is too large to fit into size_t.";
+  size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size;
+  if (arena == nullptr) {
+    rep_ = reinterpret_cast<Rep*>(::operator new(bytes));
+  } else {
+    rep_ = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
+  }
+  const int old_total_size = total_size_;
+  total_size_ = new_size;
+  if (old_rep) {
+    if (old_rep->allocated_size > 0) {
+      memcpy(rep_->elements, old_rep->elements,
+             old_rep->allocated_size * sizeof(rep_->elements[0]));
+    }
+    rep_->allocated_size = old_rep->allocated_size;
+
+    const size_t old_size =
+        old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize;
+    if (arena == nullptr) {
+      internal::SizedDelete(old_rep, old_size);
+    } else {
+      arena_->ReturnArrayMemory(old_rep, old_size);
+    }
+  } else {
+    rep_->allocated_size = 0;
+  }
+  return &rep_->elements[current_size_];
+}
+
+void RepeatedPtrFieldBase::Reserve(int new_size) {
+  if (new_size > current_size_) {
+    InternalExtend(new_size - current_size_);
+  }
+}
+
+void RepeatedPtrFieldBase::DestroyProtos() {
+  GOOGLE_DCHECK(rep_);
+  GOOGLE_DCHECK(arena_ == nullptr);
+  int n = rep_->allocated_size;
+  void* const* elements = rep_->elements;
+  for (int i = 0; i < n; i++) {
+    delete static_cast<MessageLite*>(elements[i]);
+  }
+  const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
+  internal::SizedDelete(rep_, size);
+  rep_ = nullptr;
+}
+
+void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) {
+  if (!rep_ || rep_->allocated_size == total_size_) {
+    InternalExtend(1);  // Equivalent to "Reserve(total_size_ + 1)"
+  }
+  ++rep_->allocated_size;
+  rep_->elements[current_size_++] = obj;
+  return obj;
+}
+
+void RepeatedPtrFieldBase::CloseGap(int start, int num) {
+  if (rep_ == nullptr) return;
+  // Close up a gap of "num" elements starting at offset "start".
+  for (int i = start + num; i < rep_->allocated_size; ++i)
+    rep_->elements[i - num] = rep_->elements[i];
+  current_size_ -= num;
+  rep_->allocated_size -= num;
+}
+
+MessageLite* RepeatedPtrFieldBase::AddWeak(const MessageLite* prototype) {
+  if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+    return reinterpret_cast<MessageLite*>(rep_->elements[current_size_++]);
+  }
+  if (!rep_ || rep_->allocated_size == total_size_) {
+    Reserve(total_size_ + 1);
+  }
+  ++rep_->allocated_size;
+  MessageLite* result = prototype
+                            ? prototype->New(arena_)
+                            : Arena::CreateMessage<ImplicitWeakMessage>(arena_);
+  rep_->elements[current_size_++] = result;
+  return result;
+}
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/service.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/service.cpp
new file mode 100644
index 0000000..5394568
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/service.cpp
@@ -0,0 +1,45 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/service.h>
+
+namespace google {
+namespace protobuf {
+
+Service::~Service() {}
+RpcChannel::~RpcChannel() {}
+RpcController::~RpcController() {}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/source_context.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/source_context.pb.cpp
new file mode 100644
index 0000000..e7525e9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/source_context.pb.cpp
@@ -0,0 +1,297 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#include <google/protobuf/source_context.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR SourceContext::SourceContext(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.file_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct SourceContextDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR SourceContextDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~SourceContextDefaultTypeInternal() {}
+  union {
+    SourceContext _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceContextDefaultTypeInternal _SourceContext_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceContext, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceContext, _impl_.file_name_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceContext)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n$google/protobuf/source_context.proto\022\017"
+  "google.protobuf\"\"\n\rSourceContext\022\021\n\tfile"
+  "_name\030\001 \001(\tB\212\001\n\023com.google.protobufB\022Sou"
+  "rceContextProtoP\001Z6google.golang.org/pro"
+  "tobuf/types/known/sourcecontextpb\242\002\003GPB\252"
+  "\002\036Google.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+    false, false, 240, descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto,
+    "google/protobuf/source_context.proto",
+    &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fsource_5fcontext_2eproto(&descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class SourceContext::_Internal {
+ public:
+};
+
+SourceContext::SourceContext(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceContext)
+}
+SourceContext::SourceContext(const SourceContext& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  SourceContext* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_name_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.file_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.file_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_file_name().empty()) {
+    _this->_impl_.file_name_.Set(from._internal_file_name(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceContext)
+}
+
+inline void SourceContext::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.file_name_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.file_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.file_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+SourceContext::~SourceContext() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceContext)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void SourceContext::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.file_name_.Destroy();
+}
+
+void SourceContext::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void SourceContext::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceContext)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.file_name_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* SourceContext::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string file_name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_file_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.SourceContext.file_name"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* SourceContext::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string file_name = 1;
+  if (!this->_internal_file_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_file_name().data(), static_cast<int>(this->_internal_file_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.SourceContext.file_name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_file_name(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceContext)
+  return target;
+}
+
+size_t SourceContext::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceContext)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string file_name = 1;
+  if (!this->_internal_file_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_file_name());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData SourceContext::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    SourceContext::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceContext::GetClassData() const { return &_class_data_; }
+
+
+void SourceContext::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<SourceContext*>(&to_msg);
+  auto& from = static_cast<const SourceContext&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceContext)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_file_name().empty()) {
+    _this->_internal_set_file_name(from._internal_file_name());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void SourceContext::CopyFrom(const SourceContext& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceContext)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceContext::IsInitialized() const {
+  return true;
+}
+
+void SourceContext::InternalSwap(SourceContext* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.file_name_, lhs_arena,
+      &other->_impl_.file_name_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata SourceContext::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter, &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceContext*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceContext >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceContext >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/struct.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/struct.pb.cpp
new file mode 100644
index 0000000..87c72d4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/struct.pb.cpp
@@ -0,0 +1,1057 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#include <google/protobuf/struct.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse(
+    ::_pbi::ConstantInitialized) {}
+struct Struct_FieldsEntry_DoNotUseDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR Struct_FieldsEntry_DoNotUseDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~Struct_FieldsEntry_DoNotUseDefaultTypeInternal() {}
+  union {
+    Struct_FieldsEntry_DoNotUse _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Struct_FieldsEntry_DoNotUseDefaultTypeInternal _Struct_FieldsEntry_DoNotUse_default_instance_;
+PROTOBUF_CONSTEXPR Struct::Struct(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.fields_)*/{::_pbi::ConstantInitialized()}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct StructDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR StructDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~StructDefaultTypeInternal() {}
+  union {
+    Struct _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StructDefaultTypeInternal _Struct_default_instance_;
+PROTOBUF_CONSTEXPR Value::Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.kind_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}
+  , /*decltype(_impl_._oneof_case_)*/{}} {}
+struct ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ValueDefaultTypeInternal() {}
+  union {
+    Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ValueDefaultTypeInternal _Value_default_instance_;
+PROTOBUF_CONSTEXPR ListValue::ListValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.values_)*/{}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct ListValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR ListValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~ListValueDefaultTypeInternal() {}
+  union {
+    ListValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ListValueDefaultTypeInternal _ListValue_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fstruct_2eproto[4];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[1];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, _has_bits_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, key_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, value_),
+  0,
+  1,
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct, _impl_.fields_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _impl_._oneof_case_[0]),
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _impl_.kind_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ListValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ListValue, _impl_.values_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, 8, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse)},
+  { 10, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Struct)},
+  { 17, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Value)},
+  { 30, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ListValue)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Struct_FieldsEntry_DoNotUse_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ListValue_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\034google/protobuf/struct.proto\022\017google.p"
+  "rotobuf\"\204\001\n\006Struct\0223\n\006fields\030\001 \003(\0132#.goo"
+  "gle.protobuf.Struct.FieldsEntry\032E\n\013Field"
+  "sEntry\022\013\n\003key\030\001 \001(\t\022%\n\005value\030\002 \001(\0132\026.goo"
+  "gle.protobuf.Value:\0028\001\"\352\001\n\005Value\0220\n\nnull"
+  "_value\030\001 \001(\0162\032.google.protobuf.NullValue"
+  "H\000\022\026\n\014number_value\030\002 \001(\001H\000\022\026\n\014string_val"
+  "ue\030\003 \001(\tH\000\022\024\n\nbool_value\030\004 \001(\010H\000\022/\n\014stru"
+  "ct_value\030\005 \001(\0132\027.google.protobuf.StructH"
+  "\000\0220\n\nlist_value\030\006 \001(\0132\032.google.protobuf."
+  "ListValueH\000B\006\n\004kind\"3\n\tListValue\022&\n\006valu"
+  "es\030\001 \003(\0132\026.google.protobuf.Value*\033\n\tNull"
+  "Value\022\016\n\nNULL_VALUE\020\000B\177\n\023com.google.prot"
+  "obufB\013StructProtoP\001Z/google.golang.org/p"
+  "rotobuf/types/known/structpb\370\001\001\242\002\003GPB\252\002\036"
+  "Google.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fstruct_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
+    false, false, 638, descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto,
+    "google/protobuf/struct.proto",
+    &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once, nullptr, 0, 4,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fstruct_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fstruct_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fstruct_2eproto(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* NullValue_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[0];
+}
+bool NullValue_IsValid(int value) {
+  switch (value) {
+    case 0:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// ===================================================================
+
+Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse() {}
+Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse(::PROTOBUF_NAMESPACE_ID::Arena* arena)
+    : SuperType(arena) {}
+void Struct_FieldsEntry_DoNotUse::MergeFrom(const Struct_FieldsEntry_DoNotUse& other) {
+  MergeFromInternal(other);
+}
+::PROTOBUF_NAMESPACE_ID::Metadata Struct_FieldsEntry_DoNotUse::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[0]);
+}
+
+// ===================================================================
+
+class Struct::_Internal {
+ public:
+};
+
+Struct::Struct(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  if (arena != nullptr && !is_message_owned) {
+    arena->OwnCustomDestructor(this, &Struct::ArenaDtor);
+  }
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Struct)
+}
+Struct::Struct(const Struct& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Struct* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_.fields_)*/{}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.fields_.MergeFrom(from._impl_.fields_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Struct)
+}
+
+inline void Struct::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      /*decltype(_impl_.fields_)*/{::_pbi::ArenaInitialized(), arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Struct::~Struct() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Struct)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    ArenaDtor(this);
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Struct::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.fields_.Destruct();
+  _impl_.fields_.~MapField();
+}
+
+void Struct::ArenaDtor(void* object) {
+  Struct* _this = reinterpret_cast< Struct* >(object);
+  _this->_impl_.fields_.Destruct();
+}
+void Struct::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Struct::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Struct)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.fields_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Struct::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // map<string, .google.protobuf.Value> fields = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(&_impl_.fields_, ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Struct::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // map<string, .google.protobuf.Value> fields = 1;
+  if (!this->_internal_fields().empty()) {
+    using MapType = ::_pb::Map<std::string, ::PROTOBUF_NAMESPACE_ID::Value>;
+    using WireHelper = Struct_FieldsEntry_DoNotUse::Funcs;
+    const auto& map_field = this->_internal_fields();
+    auto check_utf8 = [](const MapType::value_type& entry) {
+      (void)entry;
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+        entry.first.data(), static_cast<int>(entry.first.length()),
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+        "google.protobuf.Struct.FieldsEntry.key");
+    };
+
+    if (stream->IsSerializationDeterministic() && map_field.size() > 1) {
+      for (const auto& entry : ::_pbi::MapSorterPtr<MapType>(map_field)) {
+        target = WireHelper::InternalSerialize(1, entry.first, entry.second, target, stream);
+        check_utf8(entry);
+      }
+    } else {
+      for (const auto& entry : map_field) {
+        target = WireHelper::InternalSerialize(1, entry.first, entry.second, target, stream);
+        check_utf8(entry);
+      }
+    }
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Struct)
+  return target;
+}
+
+size_t Struct::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Struct)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // map<string, .google.protobuf.Value> fields = 1;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->_internal_fields_size());
+  for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >::const_iterator
+      it = this->_internal_fields().begin();
+      it != this->_internal_fields().end(); ++it) {
+    total_size += Struct_FieldsEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Struct::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Struct::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Struct::GetClassData() const { return &_class_data_; }
+
+
+void Struct::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Struct*>(&to_msg);
+  auto& from = static_cast<const Struct&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Struct)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.fields_.MergeFrom(from._impl_.fields_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Struct::CopyFrom(const Struct& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Struct)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Struct::IsInitialized() const {
+  return true;
+}
+
+void Struct::InternalSwap(Struct* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.fields_.InternalSwap(&other->_impl_.fields_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Struct::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[1]);
+}
+
+// ===================================================================
+
+class Value::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::Struct& struct_value(const Value* msg);
+  static const ::PROTOBUF_NAMESPACE_ID::ListValue& list_value(const Value* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::Struct&
+Value::_Internal::struct_value(const Value* msg) {
+  return *msg->_impl_.kind_.struct_value_;
+}
+const ::PROTOBUF_NAMESPACE_ID::ListValue&
+Value::_Internal::list_value(const Value* msg) {
+  return *msg->_impl_.kind_.list_value_;
+}
+void Value::set_allocated_struct_value(::PROTOBUF_NAMESPACE_ID::Struct* struct_value) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  clear_kind();
+  if (struct_value) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+      ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(struct_value);
+    if (message_arena != submessage_arena) {
+      struct_value = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, struct_value, submessage_arena);
+    }
+    set_has_struct_value();
+    _impl_.kind_.struct_value_ = struct_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.struct_value)
+}
+void Value::set_allocated_list_value(::PROTOBUF_NAMESPACE_ID::ListValue* list_value) {
+  ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
+  clear_kind();
+  if (list_value) {
+    ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
+      ::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(list_value);
+    if (message_arena != submessage_arena) {
+      list_value = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
+          message_arena, list_value, submessage_arena);
+    }
+    set_has_list_value();
+    _impl_.kind_.list_value_ = list_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value)
+}
+Value::Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Value)
+}
+Value::Value(const Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.kind_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._oneof_case_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  clear_has_kind();
+  switch (from.kind_case()) {
+    case kNullValue: {
+      _this->_internal_set_null_value(from._internal_null_value());
+      break;
+    }
+    case kNumberValue: {
+      _this->_internal_set_number_value(from._internal_number_value());
+      break;
+    }
+    case kStringValue: {
+      _this->_internal_set_string_value(from._internal_string_value());
+      break;
+    }
+    case kBoolValue: {
+      _this->_internal_set_bool_value(from._internal_bool_value());
+      break;
+    }
+    case kStructValue: {
+      _this->_internal_mutable_struct_value()->::PROTOBUF_NAMESPACE_ID::Struct::MergeFrom(
+          from._internal_struct_value());
+      break;
+    }
+    case kListValue: {
+      _this->_internal_mutable_list_value()->::PROTOBUF_NAMESPACE_ID::ListValue::MergeFrom(
+          from._internal_list_value());
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Value)
+}
+
+inline void Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.kind_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+    , /*decltype(_impl_._oneof_case_)*/{}
+  };
+  clear_has_kind();
+}
+
+Value::~Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  if (has_kind()) {
+    clear_kind();
+  }
+}
+
+void Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Value::clear_kind() {
+// @@protoc_insertion_point(one_of_clear_start:google.protobuf.Value)
+  switch (kind_case()) {
+    case kNullValue: {
+      // No need to clear
+      break;
+    }
+    case kNumberValue: {
+      // No need to clear
+      break;
+    }
+    case kStringValue: {
+      _impl_.kind_.string_value_.Destroy();
+      break;
+    }
+    case kBoolValue: {
+      // No need to clear
+      break;
+    }
+    case kStructValue: {
+      if (GetArenaForAllocation() == nullptr) {
+        delete _impl_.kind_.struct_value_;
+      }
+      break;
+    }
+    case kListValue: {
+      if (GetArenaForAllocation() == nullptr) {
+        delete _impl_.kind_.list_value_;
+      }
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  _impl_._oneof_case_[0] = KIND_NOT_SET;
+}
+
+
+void Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  clear_kind();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // .google.protobuf.NullValue null_value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_null_value(static_cast<::PROTOBUF_NAMESPACE_ID::NullValue>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      // double number_value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 17)) {
+          _internal_set_number_value(::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr));
+          ptr += sizeof(double);
+        } else
+          goto handle_unusual;
+        continue;
+      // string string_value = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          auto str = _internal_mutable_string_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Value.string_value"));
+        } else
+          goto handle_unusual;
+        continue;
+      // bool bool_value = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 32)) {
+          _internal_set_bool_value(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr));
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Struct struct_value = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr = ctx->ParseMessage(_internal_mutable_struct_value(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.ListValue list_value = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          ptr = ctx->ParseMessage(_internal_mutable_list_value(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // .google.protobuf.NullValue null_value = 1;
+  if (_internal_has_null_value()) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      1, this->_internal_null_value(), target);
+  }
+
+  // double number_value = 2;
+  if (_internal_has_number_value()) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(2, this->_internal_number_value(), target);
+  }
+
+  // string string_value = 3;
+  if (_internal_has_string_value()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_string_value().data(), static_cast<int>(this->_internal_string_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Value.string_value");
+    target = stream->WriteStringMaybeAliased(
+        3, this->_internal_string_value(), target);
+  }
+
+  // bool bool_value = 4;
+  if (_internal_has_bool_value()) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(4, this->_internal_bool_value(), target);
+  }
+
+  // .google.protobuf.Struct struct_value = 5;
+  if (_internal_has_struct_value()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(5, _Internal::struct_value(this),
+        _Internal::struct_value(this).GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.ListValue list_value = 6;
+  if (_internal_has_list_value()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(6, _Internal::list_value(this),
+        _Internal::list_value(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
+  return target;
+}
+
+size_t Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  switch (kind_case()) {
+    // .google.protobuf.NullValue null_value = 1;
+    case kNullValue: {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_null_value());
+      break;
+    }
+    // double number_value = 2;
+    case kNumberValue: {
+      total_size += 1 + 8;
+      break;
+    }
+    // string string_value = 3;
+    case kStringValue: {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+          this->_internal_string_value());
+      break;
+    }
+    // bool bool_value = 4;
+    case kBoolValue: {
+      total_size += 1 + 1;
+      break;
+    }
+    // .google.protobuf.Struct struct_value = 5;
+    case kStructValue: {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.kind_.struct_value_);
+      break;
+    }
+    // .google.protobuf.ListValue list_value = 6;
+    case kListValue: {
+      total_size += 1 +
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+          *_impl_.kind_.list_value_);
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Value::GetClassData() const { return &_class_data_; }
+
+
+void Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Value*>(&to_msg);
+  auto& from = static_cast<const Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  switch (from.kind_case()) {
+    case kNullValue: {
+      _this->_internal_set_null_value(from._internal_null_value());
+      break;
+    }
+    case kNumberValue: {
+      _this->_internal_set_number_value(from._internal_number_value());
+      break;
+    }
+    case kStringValue: {
+      _this->_internal_set_string_value(from._internal_string_value());
+      break;
+    }
+    case kBoolValue: {
+      _this->_internal_set_bool_value(from._internal_bool_value());
+      break;
+    }
+    case kStructValue: {
+      _this->_internal_mutable_struct_value()->::PROTOBUF_NAMESPACE_ID::Struct::MergeFrom(
+          from._internal_struct_value());
+      break;
+    }
+    case kListValue: {
+      _this->_internal_mutable_list_value()->::PROTOBUF_NAMESPACE_ID::ListValue::MergeFrom(
+          from._internal_list_value());
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Value::CopyFrom(const Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Value::IsInitialized() const {
+  return true;
+}
+
+void Value::InternalSwap(Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.kind_, other->_impl_.kind_);
+  swap(_impl_._oneof_case_[0], other->_impl_._oneof_case_[0]);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[2]);
+}
+
+// ===================================================================
+
+class ListValue::_Internal {
+ public:
+};
+
+ListValue::ListValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.ListValue)
+}
+ListValue::ListValue(const ListValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  ListValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.values_){from._impl_.values_}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ListValue)
+}
+
+inline void ListValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.values_){arena}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+ListValue::~ListValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ListValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void ListValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.values_.~RepeatedPtrField();
+}
+
+void ListValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void ListValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ListValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.values_.Clear();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* ListValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // repeated .google.protobuf.Value values = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_values(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* ListValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ListValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Value values = 1;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_values_size()); i < n; i++) {
+    const auto& repfield = this->_internal_values(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
+  return target;
+}
+
+size_t ListValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ListValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Value values = 1;
+  total_size += 1UL * this->_internal_values_size();
+  for (const auto& msg : this->_impl_.values_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ListValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    ListValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ListValue::GetClassData() const { return &_class_data_; }
+
+
+void ListValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<ListValue*>(&to_msg);
+  auto& from = static_cast<const ListValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ListValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.values_.MergeFrom(from._impl_.values_);
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void ListValue::CopyFrom(const ListValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ListValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ListValue::IsInitialized() const {
+  return true;
+}
+
+void ListValue::InternalSwap(ListValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.values_.InternalSwap(&other->_impl_.values_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata ListValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fstruct_2eproto[3]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Struct >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ListValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ListValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ListValue >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/bytestream.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/bytestream.cpp
new file mode 100644
index 0000000..980d6f6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/bytestream.cpp
@@ -0,0 +1,194 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/stubs/bytestream.h>
+
+#include <string.h>
+#include <algorithm>
+
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+void ByteSource::CopyTo(ByteSink* sink, size_t n) {
+  while (n > 0) {
+    StringPiece fragment = Peek();
+    if (fragment.empty()) {
+      GOOGLE_LOG(DFATAL) << "ByteSource::CopyTo() overran input.";
+      break;
+    }
+    std::size_t fragment_size = std::min<std::size_t>(n, fragment.size());
+    sink->Append(fragment.data(), fragment_size);
+    Skip(fragment_size);
+    n -= fragment_size;
+  }
+}
+
+void ByteSink::Flush() {}
+
+void UncheckedArrayByteSink::Append(const char* data, size_t n) {
+  if (data != dest_) {
+    // Catch cases where the pointer returned by GetAppendBuffer() was modified.
+    GOOGLE_DCHECK(!(dest_ <= data && data < (dest_ + n)))
+        << "Append() data[] overlaps with dest_[]";
+    memcpy(dest_, data, n);
+  }
+  dest_ += n;
+}
+
+CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, size_t capacity)
+    : outbuf_(outbuf), capacity_(capacity), size_(0), overflowed_(false) {
+}
+
+void CheckedArrayByteSink::Append(const char* bytes, size_t n) {
+  size_t available = capacity_ - size_;
+  if (n > available) {
+    n = available;
+    overflowed_ = true;
+  }
+  if (n > 0 && bytes != (outbuf_ + size_)) {
+    // Catch cases where the pointer returned by GetAppendBuffer() was modified.
+    GOOGLE_DCHECK(!(outbuf_ <= bytes && bytes < (outbuf_ + capacity_)))
+        << "Append() bytes[] overlaps with outbuf_[]";
+    memcpy(outbuf_ + size_, bytes, n);
+  }
+  size_ += n;
+}
+
+GrowingArrayByteSink::GrowingArrayByteSink(size_t estimated_size)
+    : capacity_(estimated_size),
+      buf_(new char[estimated_size]),
+      size_(0) {
+}
+
+GrowingArrayByteSink::~GrowingArrayByteSink() {
+  delete[] buf_;  // Just in case the user didn't call GetBuffer.
+}
+
+void GrowingArrayByteSink::Append(const char* bytes, size_t n) {
+  size_t available = capacity_ - size_;
+  if (bytes != (buf_ + size_)) {
+    // Catch cases where the pointer returned by GetAppendBuffer() was modified.
+    // We need to test for this before calling Expand() which may reallocate.
+    GOOGLE_DCHECK(!(buf_ <= bytes && bytes < (buf_ + capacity_)))
+        << "Append() bytes[] overlaps with buf_[]";
+  }
+  if (n > available) {
+    Expand(n - available);
+  }
+  if (n > 0 && bytes != (buf_ + size_)) {
+    memcpy(buf_ + size_, bytes, n);
+  }
+  size_ += n;
+}
+
+char* GrowingArrayByteSink::GetBuffer(size_t* nbytes) {
+  ShrinkToFit();
+  char* b = buf_;
+  *nbytes = size_;
+  buf_ = nullptr;
+  size_ = capacity_ = 0;
+  return b;
+}
+
+void GrowingArrayByteSink::Expand(size_t amount) {  // Expand by at least 50%.
+  size_t new_capacity = std::max(capacity_ + amount, (3 * capacity_) / 2);
+  char* bigger = new char[new_capacity];
+  memcpy(bigger, buf_, size_);
+  delete[] buf_;
+  buf_ = bigger;
+  capacity_ = new_capacity;
+}
+
+void GrowingArrayByteSink::ShrinkToFit() {
+  // Shrink only if the buffer is large and size_ is less than 3/4
+  // of capacity_.
+  if (capacity_ > 256 && size_ < (3 * capacity_) / 4) {
+    char* just_enough = new char[size_];
+    memcpy(just_enough, buf_, size_);
+    delete[] buf_;
+    buf_ = just_enough;
+    capacity_ = size_;
+  }
+}
+
+void StringByteSink::Append(const char* data, size_t n) {
+  dest_->append(data, n);
+}
+
+size_t ArrayByteSource::Available() const {
+  return input_.size();
+}
+
+StringPiece ArrayByteSource::Peek() {
+  return input_;
+}
+
+void ArrayByteSource::Skip(size_t n) {
+  GOOGLE_DCHECK_LE(n, input_.size());
+  input_.remove_prefix(n);
+}
+
+LimitByteSource::LimitByteSource(ByteSource *source, size_t limit)
+  : source_(source),
+    limit_(limit) {
+}
+
+size_t LimitByteSource::Available() const {
+  size_t available = source_->Available();
+  if (available > limit_) {
+    available = limit_;
+  }
+
+  return available;
+}
+
+StringPiece LimitByteSource::Peek() {
+  StringPiece piece = source_->Peek();
+  return StringPiece(piece.data(), std::min(piece.size(), limit_));
+}
+
+void LimitByteSource::Skip(size_t n) {
+  GOOGLE_DCHECK_LE(n, limit_);
+  source_->Skip(n);
+  limit_ -= n;
+}
+
+void LimitByteSource::CopyTo(ByteSink *sink, size_t n) {
+  GOOGLE_DCHECK_LE(n, limit_);
+  source_->CopyTo(sink, n);
+  limit_ -= n;
+}
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/common.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/common.cpp
new file mode 100644
index 0000000..1423021
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/common.cpp
@@ -0,0 +1,324 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/common.h>
+
+#include <atomic>
+#include <errno.h>
+#include <sstream>
+#include <stdio.h>
+#include <vector>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN  // We only need minimal includes
+#endif
+#include <windows.h>
+#define snprintf _snprintf    // see comment in strutil.cc
+#endif
+#if defined(__ANDROID__)
+#include <android/log.h>
+#endif
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/int128.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+void VerifyVersion(int headerVersion,
+                   int minLibraryVersion,
+                   const char* filename) {
+  if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) {
+    // Library is too old for headers.
+    GOOGLE_LOG(FATAL)
+      << "This program requires version " << VersionString(minLibraryVersion)
+      << " of the Protocol Buffer runtime library, but the installed version "
+         "is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ".  Please update "
+         "your library.  If you compiled the program yourself, make sure that "
+         "your headers are from the same version of Protocol Buffers as your "
+         "link-time library.  (Version verification failed in \""
+      << filename << "\".)";
+  }
+  if (headerVersion < kMinHeaderVersionForLibrary) {
+    // Headers are too old for library.
+    GOOGLE_LOG(FATAL)
+      << "This program was compiled against version "
+      << VersionString(headerVersion) << " of the Protocol Buffer runtime "
+         "library, which is not compatible with the installed version ("
+      << VersionString(GOOGLE_PROTOBUF_VERSION) <<  ").  Contact the program "
+         "author for an update.  If you compiled the program yourself, make "
+         "sure that your headers are from the same version of Protocol Buffers "
+         "as your link-time library.  (Version verification failed in \""
+      << filename << "\".)";
+  }
+}
+
+std::string VersionString(int version) {
+  int major = version / 1000000;
+  int minor = (version / 1000) % 1000;
+  int micro = version % 1000;
+
+  // 128 bytes should always be enough, but we use snprintf() anyway to be
+  // safe.
+  char buffer[128];
+  snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro);
+
+  // Guard against broken MSVC snprintf().
+  buffer[sizeof(buffer)-1] = '\0';
+
+  return buffer;
+}
+
+}  // namespace internal
+
+// ===================================================================
+// emulates google3/base/logging.cc
+
+// If the minimum logging level is not set, we default to logging messages for
+// all levels.
+#ifndef GOOGLE_PROTOBUF_MIN_LOG_LEVEL
+#define GOOGLE_PROTOBUF_MIN_LOG_LEVEL LOGLEVEL_INFO
+#endif
+
+namespace internal {
+
+#if defined(__ANDROID__)
+inline void DefaultLogHandler(LogLevel level, const char* filename, int line,
+                              const std::string& message) {
+  if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
+    return;
+  }
+  static const char* level_names[] = {"INFO", "WARNING", "ERROR", "FATAL"};
+
+  static const int android_log_levels[] = {
+      ANDROID_LOG_INFO,   // LOG(INFO),
+      ANDROID_LOG_WARN,   // LOG(WARNING)
+      ANDROID_LOG_ERROR,  // LOG(ERROR)
+      ANDROID_LOG_FATAL,  // LOG(FATAL)
+  };
+
+  // Bound the logging level.
+  const int android_log_level = android_log_levels[level];
+  ::std::ostringstream ostr;
+  ostr << "[libprotobuf " << level_names[level] << " " << filename << ":"
+       << line << "] " << message.c_str();
+
+  // Output the log string the Android log at the appropriate level.
+  __android_log_write(android_log_level, "libprotobuf-native",
+                      ostr.str().c_str());
+  // Also output to std::cerr.
+  fprintf(stderr, "%s", ostr.str().c_str());
+  fflush(stderr);
+
+  // Indicate termination if needed.
+  if (android_log_level == ANDROID_LOG_FATAL) {
+    __android_log_write(ANDROID_LOG_FATAL, "libprotobuf-native",
+                        "terminating.\n");
+  }
+}
+
+#else
+void DefaultLogHandler(LogLevel level, const char* filename, int line,
+                       const std::string& message) {
+  if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
+    return;
+  }
+  static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
+
+  // We use fprintf() instead of cerr because we want this to work at static
+  // initialization time.
+  fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
+          level_names[level], filename, line, message.c_str());
+  fflush(stderr);  // Needed on MSVC.
+}
+#endif
+
+void NullLogHandler(LogLevel /* level */, const char* /* filename */,
+                    int /* line */, const std::string& /* message */) {
+  // Nothing.
+}
+
+static LogHandler* log_handler_ = &DefaultLogHandler;
+static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0);
+
+LogMessage& LogMessage::operator<<(const std::string& value) {
+  message_ += value;
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const char* value) {
+  message_ += value;
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const StringPiece& value) {
+  message_ += value.ToString();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const util::Status& status) {
+  message_ += status.ToString();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const uint128& value) {
+  std::ostringstream str;
+  str << value;
+  message_ += str.str();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(char value) {
+  return *this << StringPiece(&value, 1);
+}
+
+LogMessage& LogMessage::operator<<(void* value) {
+  StrAppend(&message_, strings::Hex(reinterpret_cast<uintptr_t>(value)));
+  return *this;
+}
+
+#undef DECLARE_STREAM_OPERATOR
+#define DECLARE_STREAM_OPERATOR(TYPE)              \
+  LogMessage& LogMessage::operator<<(TYPE value) { \
+    StrAppend(&message_, value);                   \
+    return *this;                                  \
+  }
+
+DECLARE_STREAM_OPERATOR(int)
+DECLARE_STREAM_OPERATOR(unsigned int)
+DECLARE_STREAM_OPERATOR(long)           // NOLINT(runtime/int)
+DECLARE_STREAM_OPERATOR(unsigned long)  // NOLINT(runtime/int)
+DECLARE_STREAM_OPERATOR(double)
+DECLARE_STREAM_OPERATOR(long long)           // NOLINT(runtime/int)
+DECLARE_STREAM_OPERATOR(unsigned long long)  // NOLINT(runtime/int)
+#undef DECLARE_STREAM_OPERATOR
+
+LogMessage::LogMessage(LogLevel level, const char* filename, int line)
+  : level_(level), filename_(filename), line_(line) {}
+LogMessage::~LogMessage() {}
+
+void LogMessage::Finish() {
+  bool suppress = false;
+
+  if (level_ != LOGLEVEL_FATAL) {
+    suppress = log_silencer_count_ > 0;
+  }
+
+  if (!suppress) {
+    log_handler_(level_, filename_, line_, message_);
+  }
+
+  if (level_ == LOGLEVEL_FATAL) {
+#if PROTOBUF_USE_EXCEPTIONS
+    throw FatalException(filename_, line_, message_);
+#else
+    abort();
+#endif
+  }
+}
+
+void LogFinisher::operator=(LogMessage& other) {
+  other.Finish();
+}
+
+}  // namespace internal
+
+LogHandler* SetLogHandler(LogHandler* new_func) {
+  LogHandler* old = internal::log_handler_;
+  if (old == &internal::NullLogHandler) {
+    old = nullptr;
+  }
+  if (new_func == nullptr) {
+    internal::log_handler_ = &internal::NullLogHandler;
+  } else {
+    internal::log_handler_ = new_func;
+  }
+  return old;
+}
+
+LogSilencer::LogSilencer() {
+  ++internal::log_silencer_count_;
+}
+
+LogSilencer::~LogSilencer() {
+  --internal::log_silencer_count_;
+}
+
+// ===================================================================
+// emulates google3/base/callback.cc
+
+Closure::~Closure() {}
+
+namespace internal { FunctionClosure0::~FunctionClosure0() {} }
+
+void DoNothing() {}
+
+// ===================================================================
+// emulates google3/util/endian/endian.h
+//
+// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in
+// google/protobuf/io/coded_stream.h and therefore can not be used here.
+// Maybe move that macro definition here in the future.
+uint32_t ghtonl(uint32_t x) {
+  union {
+    uint32_t result;
+    uint8_t result_array[4];
+  };
+  result_array[0] = static_cast<uint8_t>(x >> 24);
+  result_array[1] = static_cast<uint8_t>((x >> 16) & 0xFF);
+  result_array[2] = static_cast<uint8_t>((x >> 8) & 0xFF);
+  result_array[3] = static_cast<uint8_t>(x & 0xFF);
+  return result;
+}
+
+#if PROTOBUF_USE_EXCEPTIONS
+FatalException::~FatalException() throw() {}
+
+const char* FatalException::what() const throw() {
+  return message_.c_str();
+}
+#endif
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/int128.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/int128.cpp
new file mode 100644
index 0000000..a151cfb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/int128.cpp
@@ -0,0 +1,193 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/stubs/int128.h>
+
+#include <iomanip>
+#include <ostream>  // NOLINT(readability/streams)
+#include <sstream>
+
+#include <google/protobuf/stubs/logging.h>
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+const uint128_pod kuint128max = {uint64_t{0xFFFFFFFFFFFFFFFFu},
+                                 uint64_t{0xFFFFFFFFFFFFFFFFu}};
+
+// Returns the 0-based position of the last set bit (i.e., most significant bit)
+// in the given uint64. The argument may not be 0.
+//
+// For example:
+//   Given: 5 (decimal) == 101 (binary)
+//   Returns: 2
+#define STEP(T, n, pos, sh)                   \
+  do {                                        \
+    if ((n) >= (static_cast<T>(1) << (sh))) { \
+      (n) = (n) >> (sh);                      \
+      (pos) |= (sh);                          \
+    }                                         \
+  } while (0)
+static inline int Fls64(uint64_t n) {
+  GOOGLE_DCHECK_NE(0, n);
+  int pos = 0;
+  STEP(uint64_t, n, pos, 0x20);
+  uint32_t n32 = n;
+  STEP(uint32_t, n32, pos, 0x10);
+  STEP(uint32_t, n32, pos, 0x08);
+  STEP(uint32_t, n32, pos, 0x04);
+  return pos + ((uint64_t{0x3333333322221100u} >> (n32 << 2)) & 0x3);
+}
+#undef STEP
+
+// Like Fls64() above, but returns the 0-based position of the last set bit
+// (i.e., most significant bit) in the given uint128. The argument may not be 0.
+static inline int Fls128(uint128 n) {
+  if (uint64_t hi = Uint128High64(n)) {
+    return Fls64(hi) + 64;
+  }
+  return Fls64(Uint128Low64(n));
+}
+
+void uint128::DivModImpl(uint128 dividend, uint128 divisor,
+                         uint128* quotient_ret, uint128* remainder_ret) {
+  if (divisor == 0) {
+    GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
+                      << ", lo=" << dividend.lo_;
+  } else if (dividend < divisor) {
+    *quotient_ret = 0;
+    *remainder_ret = dividend;
+    return;
+  } else {
+    int dividend_bit_length = Fls128(dividend);
+    int divisor_bit_length = Fls128(divisor);
+    int difference = dividend_bit_length - divisor_bit_length;
+    uint128 quotient = 0;
+    while (difference >= 0) {
+      quotient <<= 1;
+      uint128 shifted_divisor = divisor << difference;
+      if (shifted_divisor <= dividend) {
+        dividend -= shifted_divisor;
+        quotient += 1;
+      }
+      difference -= 1;
+    }
+    //record the final quotient and remainder
+    *quotient_ret = quotient;
+    *remainder_ret = dividend;
+  }
+}
+
+
+uint128& uint128::operator/=(const uint128& divisor) {
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(*this, divisor, &quotient, &remainder);
+  *this = quotient;
+  return *this;
+}
+uint128& uint128::operator%=(const uint128& divisor) {
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(*this, divisor, &quotient, &remainder);
+  *this = remainder;
+  return *this;
+}
+
+std::ostream& operator<<(std::ostream& o, const uint128& b) {
+  std::ios_base::fmtflags flags = o.flags();
+
+  // Select a divisor which is the largest power of the base < 2^64.
+  uint128 div;
+  std::streamsize div_base_log;
+  switch (flags & std::ios::basefield) {
+    case std::ios::hex:
+      div =
+          static_cast<uint64_t>(uint64_t{0x1000000000000000u});  // 16^15
+      div_base_log = 15;
+      break;
+    case std::ios::oct:
+      div = static_cast<uint64_t>(
+          uint64_t{01000000000000000000000u});  // 8^21
+      div_base_log = 21;
+      break;
+    default:  // std::ios::dec
+      div = static_cast<uint64_t>(
+          uint64_t{10000000000000000000u});  // 10^19
+      div_base_log = 19;
+      break;
+  }
+
+  // Now piece together the uint128 representation from three chunks of
+  // the original value, each less than "div" and therefore representable
+  // as a uint64.
+  std::ostringstream os;
+  std::ios_base::fmtflags copy_mask =
+      std::ios::basefield | std::ios::showbase | std::ios::uppercase;
+  os.setf(flags & copy_mask, copy_mask);
+  uint128 high = b;
+  uint128 low;
+  uint128::DivModImpl(high, div, &high, &low);
+  uint128 mid;
+  uint128::DivModImpl(high, div, &high, &mid);
+  if (high.lo_ != 0) {
+    os << high.lo_;
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+    os << mid.lo_;
+    os << std::setw(div_base_log);
+  } else if (mid.lo_ != 0) {
+    os << mid.lo_;
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+  }
+  os << low.lo_;
+  std::string rep = os.str();
+
+  // Add the requisite padding.
+  std::streamsize width = o.width(0);
+  auto repSize = static_cast<std::streamsize>(rep.size());
+  if (width > repSize) {
+    if ((flags & std::ios::adjustfield) == std::ios::left) {
+      rep.append(width - repSize, o.fill());
+    } else {
+      rep.insert(static_cast<std::string::size_type>(0), width - repSize,
+                 o.fill());
+    }
+  }
+
+  // Stream the final representation in a single "<<" call.
+  return o << rep;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>  // NOLINT
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/status.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/status.cpp
new file mode 100644
index 0000000..f5c0fa4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/status.cpp
@@ -0,0 +1,262 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <google/protobuf/stubs/status.h>
+
+#include <ostream>
+#include <stdio.h>
+#include <string>
+#include <utility>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace status_internal {
+namespace {
+
+inline std::string StatusCodeToString(StatusCode code) {
+  switch (code) {
+    case StatusCode::kOk:
+      return "OK";
+    case StatusCode::kCancelled:
+      return "CANCELLED";
+    case StatusCode::kUnknown:
+      return "UNKNOWN";
+    case StatusCode::kInvalidArgument:
+      return "INVALID_ARGUMENT";
+    case StatusCode::kDeadlineExceeded:
+      return "DEADLINE_EXCEEDED";
+    case StatusCode::kNotFound:
+      return "NOT_FOUND";
+    case StatusCode::kAlreadyExists:
+      return "ALREADY_EXISTS";
+    case StatusCode::kPermissionDenied:
+      return "PERMISSION_DENIED";
+    case StatusCode::kUnauthenticated:
+      return "UNAUTHENTICATED";
+    case StatusCode::kResourceExhausted:
+      return "RESOURCE_EXHAUSTED";
+    case StatusCode::kFailedPrecondition:
+      return "FAILED_PRECONDITION";
+    case StatusCode::kAborted:
+      return "ABORTED";
+    case StatusCode::kOutOfRange:
+      return "OUT_OF_RANGE";
+    case StatusCode::kUnimplemented:
+      return "UNIMPLEMENTED";
+    case StatusCode::kInternal:
+      return "INTERNAL";
+    case StatusCode::kUnavailable:
+      return "UNAVAILABLE";
+    case StatusCode::kDataLoss:
+      return "DATA_LOSS";
+  }
+
+  // No default clause, clang will abort if a code is missing from
+  // above switch.
+  return "UNKNOWN";
+}
+
+}  // namespace
+
+Status::Status() : error_code_(StatusCode::kOk) {}
+
+Status::Status(StatusCode error_code, StringPiece error_message)
+    : error_code_(error_code) {
+  if (error_code != StatusCode::kOk) {
+    error_message_ = error_message.ToString();
+  }
+}
+
+Status::Status(const Status& other)
+    : error_code_(other.error_code_), error_message_(other.error_message_) {
+}
+
+Status& Status::operator=(const Status& other) {
+  error_code_ = other.error_code_;
+  error_message_ = other.error_message_;
+  return *this;
+}
+
+bool Status::operator==(const Status& x) const {
+  return error_code_ == x.error_code_ &&
+      error_message_ == x.error_message_;
+}
+
+std::string Status::ToString() const {
+  if (error_code_ == StatusCode::kOk) {
+    return "OK";
+  } else {
+    if (error_message_.empty()) {
+      return StatusCodeToString(error_code_);
+    } else {
+      return StatusCodeToString(error_code_) + ":" + error_message_;
+    }
+  }
+}
+
+Status OkStatus() { return Status(); }
+
+std::ostream& operator<<(std::ostream& os, const Status& x) {
+  os << x.ToString();
+  return os;
+}
+
+bool IsAborted(const Status& status) {
+  return status.code() == StatusCode::kAborted;
+}
+
+bool IsAlreadyExists(const Status& status) {
+  return status.code() == StatusCode::kAlreadyExists;
+}
+
+bool IsCancelled(const Status& status) {
+  return status.code() == StatusCode::kCancelled;
+}
+
+bool IsDataLoss(const Status& status) {
+  return status.code() == StatusCode::kDataLoss;
+}
+
+bool IsDeadlineExceeded(const Status& status) {
+  return status.code() == StatusCode::kDeadlineExceeded;
+}
+
+bool IsFailedPrecondition(const Status& status) {
+  return status.code() == StatusCode::kFailedPrecondition;
+}
+
+bool IsInternal(const Status& status) {
+  return status.code() == StatusCode::kInternal;
+}
+
+bool IsInvalidArgument(const Status& status) {
+  return status.code() == StatusCode::kInvalidArgument;
+}
+
+bool IsNotFound(const Status& status) {
+  return status.code() == StatusCode::kNotFound;
+}
+
+bool IsOutOfRange(const Status& status) {
+  return status.code() == StatusCode::kOutOfRange;
+}
+
+bool IsPermissionDenied(const Status& status) {
+  return status.code() == StatusCode::kPermissionDenied;
+}
+
+bool IsResourceExhausted(const Status& status) {
+  return status.code() == StatusCode::kResourceExhausted;
+}
+
+bool IsUnauthenticated(const Status& status) {
+  return status.code() == StatusCode::kUnauthenticated;
+}
+
+bool IsUnavailable(const Status& status) {
+  return status.code() == StatusCode::kUnavailable;
+}
+
+bool IsUnimplemented(const Status& status) {
+  return status.code() == StatusCode::kUnimplemented;
+}
+
+bool IsUnknown(const Status& status) {
+  return status.code() == StatusCode::kUnknown;
+}
+
+Status AbortedError(StringPiece message) {
+  return Status(StatusCode::kAborted, message);
+}
+
+Status AlreadyExistsError(StringPiece message) {
+  return Status(StatusCode::kAlreadyExists, message);
+}
+
+Status CancelledError(StringPiece message) {
+  return Status(StatusCode::kCancelled, message);
+}
+
+Status DataLossError(StringPiece message) {
+  return Status(StatusCode::kDataLoss, message);
+}
+
+Status DeadlineExceededError(StringPiece message) {
+  return Status(StatusCode::kDeadlineExceeded, message);
+}
+
+Status FailedPreconditionError(StringPiece message) {
+  return Status(StatusCode::kFailedPrecondition, message);
+}
+
+Status InternalError(StringPiece message) {
+  return Status(StatusCode::kInternal, message);
+}
+
+Status InvalidArgumentError(StringPiece message) {
+  return Status(StatusCode::kInvalidArgument, message);
+}
+
+Status NotFoundError(StringPiece message) {
+  return Status(StatusCode::kNotFound, message);
+}
+
+Status OutOfRangeError(StringPiece message) {
+  return Status(StatusCode::kOutOfRange, message);
+}
+
+Status PermissionDeniedError(StringPiece message) {
+  return Status(StatusCode::kPermissionDenied, message);
+}
+
+Status ResourceExhaustedError(StringPiece message) {
+  return Status(StatusCode::kResourceExhausted, message);
+}
+
+Status UnauthenticatedError(StringPiece message) {
+  return Status(StatusCode::kUnauthenticated, message);
+}
+
+Status UnavailableError(StringPiece message) {
+  return Status(StatusCode::kUnavailable, message);
+}
+
+Status UnimplementedError(StringPiece message) {
+  return Status(StatusCode::kUnimplemented, message);
+}
+
+Status UnknownError(StringPiece message) {
+  return Status(StatusCode::kUnknown, message);
+}
+
+}  // namespace status_internal
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/statusor.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/statusor.cpp
new file mode 100644
index 0000000..9c0a178
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/statusor.cpp
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/stubs/statusor.h>
+
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace statusor_internal {
+
+void StatusOrHelper::Crash(const Status& status) {
+  GOOGLE_LOG(FATAL) << "Attempting to fetch value instead of handling error "
+                    << status.ToString();
+}
+
+}  // namespace statusor_internal
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/stringpiece.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/stringpiece.cpp
new file mode 100644
index 0000000..7188046
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/stringpiece.cpp
@@ -0,0 +1,256 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <string.h>
+#include <algorithm>
+#include <climits>
+#include <string>
+#include <ostream>
+
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+namespace stringpiece_internal {
+
+std::ostream& operator<<(std::ostream& o, StringPiece piece) {
+  o.write(piece.data(), piece.size());
+  return o;
+}
+
+void StringPiece::LogFatalSizeTooBig(size_t size, const char* details) {
+  GOOGLE_LOG(FATAL) << "size too big: " << size << " details: " << details;
+}
+
+void StringPiece::CopyToString(std::string* target) const {
+  target->assign(ptr_, length_);
+}
+
+void StringPiece::AppendToString(std::string* target) const {
+  target->append(ptr_, length_);
+}
+
+bool StringPiece::Consume(StringPiece x) {
+  if (starts_with(x)) {
+    ptr_ += x.length_;
+    length_ -= x.length_;
+    return true;
+  }
+  return false;
+}
+
+bool StringPiece::ConsumeFromEnd(StringPiece x) {
+  if (ends_with(x)) {
+    length_ -= x.length_;
+    return true;
+  }
+  return false;
+}
+
+StringPiece::size_type StringPiece::copy(char* buf, size_type n,
+                                         size_type pos) const {
+  size_type ret = std::min(length_ - pos, n);
+  memcpy(buf, ptr_ + pos, ret);
+  return ret;
+}
+
+bool StringPiece::contains(StringPiece s) const {
+  return find(s, 0) != npos;
+}
+
+StringPiece::size_type StringPiece::find(StringPiece s, size_type pos) const {
+  if (length_ <= 0 || pos > static_cast<size_type>(length_)) {
+    if (length_ == 0 && pos == 0 && s.length_ == 0) return 0;
+    return npos;
+  }
+  const char *result = std::search(ptr_ + pos, ptr_ + length_,
+                                   s.ptr_, s.ptr_ + s.length_);
+  return result == ptr_ + length_ ? npos : result - ptr_;
+}
+
+StringPiece::size_type StringPiece::find(char c, size_type pos) const {
+  if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
+    return npos;
+  }
+  const char* result = static_cast<const char*>(
+      memchr(ptr_ + pos, c, length_ - pos));
+  return result != nullptr ? result - ptr_ : npos;
+}
+
+StringPiece::size_type StringPiece::rfind(StringPiece s, size_type pos) const {
+  if (length_ < s.length_) return npos;
+  const size_t ulen = length_;
+  if (s.length_ == 0) return std::min(ulen, pos);
+
+  const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
+  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
+  return result != last ? result - ptr_ : npos;
+}
+
+// Search range is [0..pos] inclusive.  If pos == npos, search everything.
+StringPiece::size_type StringPiece::rfind(char c, size_type pos) const {
+  // Note: memrchr() is not available on Windows.
+  if (empty()) return npos;
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (ptr_[i] == c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+// For each character in characters_wanted, sets the index corresponding
+// to the ASCII code of that character to 1 in table.  This is used by
+// the find_.*_of methods below to tell whether or not a character is in
+// the lookup table in constant time.
+// The argument `table' must be an array that is large enough to hold all
+// the possible values of an unsigned char.  Thus it should be be declared
+// as follows:
+//   bool table[UCHAR_MAX + 1]
+static inline void BuildLookupTable(StringPiece characters_wanted,
+                                    bool* table) {
+  const StringPiece::size_type length = characters_wanted.length();
+  const char* const data = characters_wanted.data();
+  for (StringPiece::size_type i = 0; i < length; ++i) {
+    table[static_cast<unsigned char>(data[i])] = true;
+  }
+}
+
+StringPiece::size_type StringPiece::find_first_of(StringPiece s,
+                                                  size_type pos) const {
+  if (empty() || s.empty()) {
+    return npos;
+  }
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_type i = pos; i < length_; ++i) {
+    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_first_not_of(StringPiece s,
+                                                      size_type pos) const {
+  if (empty()) return npos;
+  if (s.empty()) return 0;
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_type i = pos; i < length_; ++i) {
+    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_first_not_of(char c,
+                                                      size_type pos) const {
+  if (empty()) return npos;
+
+  for (; pos < static_cast<size_type>(length_); ++pos) {
+    if (ptr_[pos] != c) {
+      return pos;
+    }
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_last_of(StringPiece s,
+                                                 size_type pos) const {
+  if (empty() || s.empty()) return npos;
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_last_not_of(StringPiece s,
+                                                     size_type pos) const {
+  if (empty()) return npos;
+
+  size_type i = std::min(pos, length() - 1);
+  if (s.empty()) return i;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (;; --i) {
+    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+StringPiece::size_type StringPiece::find_last_not_of(char c,
+                                                     size_type pos) const {
+  if (empty()) return npos;
+  size_type i = std::min(pos, length_ - 1);
+  for (;; --i) {
+    if (ptr_[i] != c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+StringPiece StringPiece::substr(size_type pos, size_type n) const {
+  if (pos > length()) pos = length();
+  if (n > length_ - pos) n = length() - pos;
+  return StringPiece(ptr_ + pos, n);
+}
+
+const StringPiece::size_type StringPiece::npos = size_type(-1);
+
+}  // namespace stringpiece_internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/stringprintf.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/stringprintf.cpp
new file mode 100644
index 0000000..8b890f4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/stringprintf.cpp
@@ -0,0 +1,175 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/base/stringprintf.cc
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include <errno.h>
+#include <stdarg.h> // For va_list and related operations
+#include <stdio.h> // MSVC requires this for _vsnprintf
+#include <vector>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+
+namespace google {
+namespace protobuf {
+
+#ifdef _MSC_VER
+#ifndef va_copy
+// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
+// pointer into the stack and is safe to copy.
+#define va_copy(dest, src) ((dest) = (src))
+#endif
+#endif
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+  // First try with a small fixed size buffer
+  static const int kSpaceLength = 1024;
+  char space[kSpaceLength];
+
+  // It's possible for methods that use a va_list to invalidate
+  // the data in it upon use.  The fix is to make a copy
+  // of the structure before using it and use that copy instead.
+  va_list backup_ap;
+  va_copy(backup_ap, ap);
+  int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result < kSpaceLength) {
+    if (result >= 0) {
+      // Normal case -- everything fit.
+      dst->append(space, result);
+      return;
+    }
+
+#ifdef _MSC_VER
+    {
+      // Error or MSVC running out of space.  MSVC 8.0 and higher
+      // can be asked about space needed with the special idiom below:
+      va_copy(backup_ap, ap);
+      result = vsnprintf(nullptr, 0, format, backup_ap);
+      va_end(backup_ap);
+    }
+#endif
+
+    if (result < 0) {
+      // Just an error.
+      return;
+    }
+  }
+
+  // Increase the buffer size to the size requested by vsnprintf,
+  // plus one for the closing \0.
+  int length = result+1;
+  char* buf = new char[length];
+
+  // Restore the va_list before we use it again
+  va_copy(backup_ap, ap);
+  result = vsnprintf(buf, length, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result >= 0 && result < length) {
+    // It fit
+    dst->append(buf, result);
+  }
+  delete[] buf;
+}
+
+std::string StringPrintf(const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+
+// Max arguments supported by StringPrintVector
+const int kStringPrintfVectorMaxArgs = 32;
+
+// An empty block of zero for filler arguments.  This is const so that if
+// printf tries to write to it (via %n) then the program gets a SIGSEGV
+// and we can fix the problem or protect against an attack.
+static const char string_printf_empty_block[256] = { '\0' };
+
+std::string StringPrintfVector(const char* format,
+                               const std::vector<std::string>& v) {
+  GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs)
+      << "StringPrintfVector currently only supports up to "
+      << kStringPrintfVectorMaxArgs << " arguments. "
+      << "Feel free to add support for more if you need it.";
+
+  // Add filler arguments so that bogus format+args have a harder time
+  // crashing the program, corrupting the program (%n),
+  // or displaying random chunks of memory to users.
+
+  const char* cstr[kStringPrintfVectorMaxArgs];
+  for (size_t i = 0; i < v.size(); ++i) {
+    cstr[i] = v[i].c_str();
+  }
+  for (size_t i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) {
+    cstr[i] = &string_printf_empty_block[0];
+  }
+
+  // I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
+  // or any way to build a va_list by hand, or any API for printf
+  // that accepts an array of arguments.  The best I can do is stick
+  // this COMPILE_ASSERT right next to the actual statement.
+
+  static_assert(kStringPrintfVectorMaxArgs == 32, "arg_count_mismatch");
+  return StringPrintf(format,
+                      cstr[0], cstr[1], cstr[2], cstr[3], cstr[4],
+                      cstr[5], cstr[6], cstr[7], cstr[8], cstr[9],
+                      cstr[10], cstr[11], cstr[12], cstr[13], cstr[14],
+                      cstr[15], cstr[16], cstr[17], cstr[18], cstr[19],
+                      cstr[20], cstr[21], cstr[22], cstr[23], cstr[24],
+                      cstr[25], cstr[26], cstr[27], cstr[28], cstr[29],
+                      cstr[30], cstr[31]);
+}
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/structurally_valid.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/structurally_valid.cpp
new file mode 100644
index 0000000..a535736
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/structurally_valid.cpp
@@ -0,0 +1,617 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jrm@google.com (Jim Meehan)
+
+#include <google/protobuf/stubs/common.h>
+
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// These four-byte entries compactly encode how many bytes 0..255 to delete
+// in making a string replacement, how many bytes to add 0..255, and the offset
+// 0..64k-1 of the replacement string in remap_string.
+struct RemapEntry {
+  uint8_t delete_bytes;
+  uint8_t add_bytes;
+  uint16_t bytes_offset;
+};
+
+// Exit type codes for state tables. All but the first get stuffed into
+// signed one-byte entries. The first is only generated by executable code.
+// To distinguish from next-state entries, these must be contiguous and
+// all <= kExitNone
+typedef enum {
+  kExitDstSpaceFull = 239,
+  kExitIllegalStructure,  // 240
+  kExitOK,                // 241
+  kExitReject,            // ...
+  kExitReplace1,
+  kExitReplace2,
+  kExitReplace3,
+  kExitReplace21,
+  kExitReplace31,
+  kExitReplace32,
+  kExitReplaceOffset1,
+  kExitReplaceOffset2,
+  kExitReplace1S0,
+  kExitSpecial,
+  kExitDoAgain,
+  kExitRejectAlt,
+  kExitNone               // 255
+} ExitReason;
+
+
+// This struct represents one entire state table. The three initialized byte
+// areas are state_table, remap_base, and remap_string. state0 and state0_size
+// give the byte offset and length within state_table of the initial state --
+// table lookups are expected to start and end in this state, but for
+// truncated UTF-8 strings, may end in a different state. These allow a quick
+// test for that condition. entry_shift is 8 for tables subscripted by a full
+// byte value and 6 for space-optimized tables subscripted by only six
+// significant bits in UTF-8 continuation bytes.
+typedef struct {
+  const uint32_t state0;
+  const uint32_t state0_size;
+  const uint32_t total_size;
+  const int max_expand;
+  const int entry_shift;
+  const int bytes_per_entry;
+  const uint32_t losub;
+  const uint32_t hiadd;
+  const uint8_t* state_table;
+  const RemapEntry* remap_base;
+  const uint8_t* remap_string;
+  const uint8_t* fast_state;
+} UTF8StateMachineObj;
+
+typedef UTF8StateMachineObj UTF8ScanObj;
+
+#define X__ (kExitIllegalStructure)
+#define RJ_ (kExitReject)
+#define S1_ (kExitReplace1)
+#define S2_ (kExitReplace2)
+#define S3_ (kExitReplace3)
+#define S21 (kExitReplace21)
+#define S31 (kExitReplace31)
+#define S32 (kExitReplace32)
+#define T1_ (kExitReplaceOffset1)
+#define T2_ (kExitReplaceOffset2)
+#define S11 (kExitReplace1S0)
+#define SP_ (kExitSpecial)
+#define D__ (kExitDoAgain)
+#define RJA (kExitRejectAlt)
+
+//  Entire table has 9 state blocks of 256 entries each
+static const unsigned int utf8acceptnonsurrogates_STATE0 = 0;     // state[0]
+static const unsigned int utf8acceptnonsurrogates_STATE0_SIZE = 256;  // =[1]
+static const unsigned int utf8acceptnonsurrogates_TOTAL_SIZE = 2304;
+static const unsigned int utf8acceptnonsurrogates_MAX_EXPAND_X4 = 0;
+static const unsigned int utf8acceptnonsurrogates_SHIFT = 8;
+static const unsigned int utf8acceptnonsurrogates_BYTES = 1;
+static const unsigned int utf8acceptnonsurrogates_LOSUB = 0x20202020;
+static const unsigned int utf8acceptnonsurrogates_HIADD = 0x00000000;
+
+static const uint8_t utf8acceptnonsurrogates[] = {
+// state[0] 0x000000 Byte 1
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  2,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   7,   3,   3,
+  4,   5,   5,   5,   6, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[1] 0x000080 Byte 2 of 2
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[2] 0x000000 Byte 2 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[3] 0x001000 Byte 2 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[4] 0x000000 Byte 2 of 4
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[5] 0x040000 Byte 2 of 4
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[6] 0x100000 Byte 2 of 4
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  3,   3,   3,   3,   3,   3,   3,   3,    3,   3,   3,   3,   3,   3,   3,   3,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[7] 0x00d000 Byte 2 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   1,   1,   1,   1,   1,    1,   1,   1,   1,   1,   1,   1,   1,
+  8,   8,   8,   8,   8,   8,   8,   8,    8,   8,   8,   8,   8,   8,   8,   8,
+  8,   8,   8,   8,   8,   8,   8,   8,    8,   8,   8,   8,   8,   8,   8,   8,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+// state[8] 0x00d800 Byte 3 of 3
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,  RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
+
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+X__, X__, X__, X__, X__, X__, X__, X__,  X__, X__, X__, X__, X__, X__, X__, X__,
+};
+
+// Remap base[0] = (del, add, string_offset)
+static const RemapEntry utf8acceptnonsurrogates_remap_base[] = {
+{0, 0, 0} };
+
+// Remap string[0]
+static const unsigned char utf8acceptnonsurrogates_remap_string[] = {
+0 };
+
+static const unsigned char utf8acceptnonsurrogates_fast[256] = {
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
+
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static const UTF8ScanObj utf8acceptnonsurrogates_obj = {
+  utf8acceptnonsurrogates_STATE0,
+  utf8acceptnonsurrogates_STATE0_SIZE,
+  utf8acceptnonsurrogates_TOTAL_SIZE,
+  utf8acceptnonsurrogates_MAX_EXPAND_X4,
+  utf8acceptnonsurrogates_SHIFT,
+  utf8acceptnonsurrogates_BYTES,
+  utf8acceptnonsurrogates_LOSUB,
+  utf8acceptnonsurrogates_HIADD,
+  utf8acceptnonsurrogates,
+  utf8acceptnonsurrogates_remap_base,
+  utf8acceptnonsurrogates_remap_string,
+  utf8acceptnonsurrogates_fast
+};
+
+
+#undef X__
+#undef RJ_
+#undef S1_
+#undef S2_
+#undef S3_
+#undef S21
+#undef S31
+#undef S32
+#undef T1_
+#undef T2_
+#undef S11
+#undef SP_
+#undef D__
+#undef RJA
+
+// Return true if current Tbl pointer is within state0 range
+// Note that unsigned compare checks both ends of range simultaneously
+static inline bool InStateZero(const UTF8ScanObj* st, const uint8_t* Tbl) {
+  const uint8_t* Tbl0 = &st->state_table[st->state0];
+  return (static_cast<uint32_t>(Tbl - Tbl0) < st->state0_size);
+}
+
+namespace {
+
+// Scan a UTF-8 string based on state table.
+// Always scan complete UTF-8 characters
+// Set number of bytes scanned. Return reason for exiting
+int UTF8GenericScan(const UTF8ScanObj* st,
+                    const char * str,
+                    int str_length,
+                    int* bytes_consumed) {
+  *bytes_consumed = 0;
+  if (str_length == 0) return kExitOK;
+
+  int eshift = st->entry_shift;
+  const uint8_t* isrc = reinterpret_cast<const uint8_t*>(str);
+  const uint8_t* src = isrc;
+  const uint8_t* srclimit = isrc + str_length;
+  const uint8_t* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
+  const uint8_t* Tbl_0 = &st->state_table[st->state0];
+
+ DoAgain:
+  // Do state-table scan
+  int e = 0;
+  uint8_t c;
+  const uint8_t* Tbl2 = &st->fast_state[0];
+  const uint32_t losub = st->losub;
+  const uint32_t hiadd = st->hiadd;
+  // Check initial few bytes one at a time until 8-byte aligned
+  //----------------------------
+  while ((((uintptr_t)src & 0x07) != 0) &&
+         (src < srclimit) &&
+         Tbl2[src[0]] == 0) {
+    src++;
+  }
+  if (((uintptr_t)src & 0x07) == 0) {
+    // Do fast for groups of 8 identity bytes.
+    // This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop,
+    // including slowing slightly on cr/lf/ht
+    //----------------------------
+    while (src < srclimit8) {
+      uint32_t s0123 = (reinterpret_cast<const uint32_t *>(src))[0];
+      uint32_t s4567 = (reinterpret_cast<const uint32_t *>(src))[1];
+      src += 8;
+      // This is a fast range check for all bytes in [lowsub..0x80-hiadd)
+      uint32_t temp = (s0123 - losub) | (s0123 + hiadd) |
+                      (s4567 - losub) | (s4567 + hiadd);
+      if ((temp & 0x80808080) != 0) {
+        // We typically end up here on cr/lf/ht; src was incremented
+        int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) |
+                    (Tbl2[src[-6]] | Tbl2[src[-5]]);
+        if (e0123 != 0) {
+          src -= 8;
+          break;
+        }    // Exit on Non-interchange
+        e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) |
+                (Tbl2[src[-2]] | Tbl2[src[-1]]);
+        if (e0123 != 0) {
+          src -= 4;
+          break;
+        }    // Exit on Non-interchange
+        // Else OK, go around again
+      }
+    }
+  }
+  //----------------------------
+
+  // Byte-at-a-time scan
+  //----------------------------
+  const uint8_t* Tbl = Tbl_0;
+  while (src < srclimit) {
+    c = *src;
+    e = Tbl[c];
+    src++;
+    if (e >= kExitIllegalStructure) {break;}
+    Tbl = &Tbl_0[e << eshift];
+  }
+  //----------------------------
+
+  // Exit possibilities:
+  //  Some exit code, !state0, back up over last char
+  //  Some exit code, state0, back up one byte exactly
+  //  source consumed, !state0, back up over partial char
+  //  source consumed, state0, exit OK
+  // For illegal byte in state0, avoid backup up over PREVIOUS char
+  // For truncated last char, back up to beginning of it
+
+  if (e >= kExitIllegalStructure) {
+    // Back up over exactly one byte of rejected/illegal UTF-8 character
+    src--;
+    // Back up more if needed
+    if (!InStateZero(st, Tbl)) {
+      do {
+        src--;
+      } while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
+    }
+  } else if (!InStateZero(st, Tbl)) {
+    // Back up over truncated UTF-8 character
+    e = kExitIllegalStructure;
+    do {
+      src--;
+    } while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
+  } else {
+    // Normal termination, source fully consumed
+    e = kExitOK;
+  }
+
+  if (e == kExitDoAgain) {
+    // Loop back up to the fast scan
+    goto DoAgain;
+  }
+
+  *bytes_consumed = src - isrc;
+  return e;
+}
+
+int UTF8GenericScanFastAscii(const UTF8ScanObj* st,
+                    const char * str,
+                    int str_length,
+                    int* bytes_consumed) {
+  *bytes_consumed = 0;
+  if (str_length == 0) return kExitOK;
+
+  const uint8_t* isrc =  reinterpret_cast<const uint8_t*>(str);
+  const uint8_t* src = isrc;
+  const uint8_t* srclimit = isrc + str_length;
+  const uint8_t* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
+  int n;
+  int rest_consumed;
+  int exit_reason;
+  do {
+    // Check initial few bytes one at a time until 8-byte aligned
+    while ((((uintptr_t)src & 0x07) != 0) &&
+           (src < srclimit) && (src[0] < 0x80)) {
+      src++;
+    }
+    if (((uintptr_t)src & 0x07) == 0) {
+      while ((src < srclimit8) &&
+             (((reinterpret_cast<const uint32_t*>(src)[0] |
+                reinterpret_cast<const uint32_t*>(src)[1]) &
+               0x80808080) == 0)) {
+        src += 8;
+      }
+    }
+    while ((src < srclimit) && (src[0] < 0x80)) {
+      src++;
+    }
+    // Run state table on the rest
+    n = src - isrc;
+    exit_reason = UTF8GenericScan(st, str + n, str_length - n, &rest_consumed);
+    src += rest_consumed;
+  } while ( exit_reason == kExitDoAgain );
+
+  *bytes_consumed = src - isrc;
+  return exit_reason;
+}
+
+// Hack:  On some compilers the static tables are initialized at startup.
+//   We can't use them until they are initialized.  However, some Protocol
+//   Buffer parsing happens at static init time and may try to validate
+//   UTF-8 strings.  Since UTF-8 validation is only used for debugging
+//   anyway, we simply always return success if initialization hasn't
+//   occurred yet.
+
+bool module_initialized_ = false;
+
+struct InitDetector {
+  InitDetector() {
+    module_initialized_ = true;
+  }
+};
+InitDetector init_detector;
+
+}  // namespace
+
+bool IsStructurallyValidUTF8(const char* buf, int len) {
+  if (!module_initialized_) return true;
+
+  int bytes_consumed = 0;
+  UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
+                           buf, len, &bytes_consumed);
+  return (bytes_consumed == len);
+}
+
+int UTF8SpnStructurallyValid(StringPiece str) {
+  if (!module_initialized_) return str.size();
+
+  int bytes_consumed = 0;
+  UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
+                           str.data(), str.size(), &bytes_consumed);
+  return bytes_consumed;
+}
+
+// Coerce UTF-8 byte string in src_str to be
+// a structurally-valid equal-length string by selectively
+// overwriting illegal bytes with replace_char (typically blank).
+// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
+// src_str is read-only. If any overwriting is needed, a modified byte string
+// is created in idst, length isrclen.
+//
+// Returns pointer to output buffer, isrc if no changes were made,
+//  or idst if some bytes were changed.
+//
+// Fast case: all is structurally valid and no byte copying is done.
+//
+char* UTF8CoerceToStructurallyValid(StringPiece src_str, char* idst,
+                                    const char replace_char) {
+  const char* isrc = src_str.data();
+  const int len = src_str.length();
+  int n = UTF8SpnStructurallyValid(src_str);
+  if (n == len) {               // Normal case -- all is cool, return
+    return const_cast<char*>(isrc);
+  } else {                      // Unusual case -- copy w/o bad bytes
+    const char* src = isrc;
+    const char* srclimit = isrc + len;
+    char* dst = idst;
+    memmove(dst, src, n);       // Copy initial good chunk
+    src += n;
+    dst += n;
+    while (src < srclimit) {    // src points to bogus byte or is off the end
+      dst[0] = replace_char;                    // replace one bad byte
+      src++;
+      dst++;
+      StringPiece str2(src, srclimit - src);
+      n = UTF8SpnStructurallyValid(str2);       // scan the remainder
+      memmove(dst, src, n);                     // copy next good chunk
+      src += n;
+      dst += n;
+    }
+  }
+  return idst;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/strutil.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/strutil.cpp
new file mode 100644
index 0000000..58e03d0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/strutil.cpp
@@ -0,0 +1,2487 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// from google3/strings/strutil.cc
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <errno.h>
+#include <float.h>    // FLT_DIG and DBL_DIG
+#include <limits.h>
+#include <stdio.h>
+#include <cmath>
+#include <iterator>
+#include <limits>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+#ifdef _WIN32
+// MSVC has only _snprintf, not snprintf.
+//
+// MinGW has both snprintf and _snprintf, but they appear to be different
+// functions.  The former is buggy.  When invoked like so:
+//   char buffer[32];
+//   snprintf(buffer, 32, "%.*g\n", FLT_DIG, 1.23e10f);
+// it prints "1.23000e+10".  This is plainly wrong:  %g should never print
+// trailing zeros after the decimal point.  For some reason this bug only
+// occurs with some input values, not all.  In any case, _snprintf does the
+// right thing, so we use it.
+#define snprintf _snprintf
+#endif
+
+namespace google {
+namespace protobuf {
+
+// These are defined as macros on some platforms.  #undef them so that we can
+// redefine them.
+#undef isxdigit
+#undef isprint
+
+// The definitions of these in ctype.h change based on locale.  Since our
+// string manipulation is all in relation to the protocol buffer and C++
+// languages, we always want to use the C locale.  So, we re-define these
+// exactly as we want them.
+inline bool isxdigit(char c) {
+  return ('0' <= c && c <= '9') ||
+         ('a' <= c && c <= 'f') ||
+         ('A' <= c && c <= 'F');
+}
+
+inline bool isprint(char c) {
+  return c >= 0x20 && c <= 0x7E;
+}
+
+// ----------------------------------------------------------------------
+// ReplaceCharacters
+//    Replaces any occurrence of the character 'remove' (or the characters
+//    in 'remove') with the character 'replacewith'.
+// ----------------------------------------------------------------------
+void ReplaceCharacters(std::string *s, const char *remove, char replacewith) {
+  const char *str_start = s->c_str();
+  const char *str = str_start;
+  for (str = strpbrk(str, remove);
+       str != nullptr;
+       str = strpbrk(str + 1, remove)) {
+    (*s)[str - str_start] = replacewith;
+  }
+}
+
+void StripWhitespace(std::string *str) {
+  int str_length = str->length();
+
+  // Strip off leading whitespace.
+  int first = 0;
+  while (first < str_length && ascii_isspace(str->at(first))) {
+    ++first;
+  }
+  // If entire string is white space.
+  if (first == str_length) {
+    str->clear();
+    return;
+  }
+  if (first > 0) {
+    str->erase(0, first);
+    str_length -= first;
+  }
+
+  // Strip off trailing whitespace.
+  int last = str_length - 1;
+  while (last >= 0 && ascii_isspace(str->at(last))) {
+    --last;
+  }
+  if (last != (str_length - 1) && last >= 0) {
+    str->erase(last + 1, std::string::npos);
+  }
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+//    Replace the "old" pattern with the "new" pattern in a string,
+//    and append the result to "res".  If replace_all is false,
+//    it only replaces the first instance of "old."
+// ----------------------------------------------------------------------
+
+void StringReplace(const std::string &s, const std::string &oldsub,
+                   const std::string &newsub, bool replace_all,
+                   std::string *res) {
+  if (oldsub.empty()) {
+    res->append(s);  // if empty, append the given string.
+    return;
+  }
+
+  std::string::size_type start_pos = 0;
+  std::string::size_type pos;
+  do {
+    pos = s.find(oldsub, start_pos);
+    if (pos == std::string::npos) {
+      break;
+    }
+    res->append(s, start_pos, pos - start_pos);
+    res->append(newsub);
+    start_pos = pos + oldsub.size();  // start searching again after the "old"
+  } while (replace_all);
+  res->append(s, start_pos, s.length() - start_pos);
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+//    Give me a string and two patterns "old" and "new", and I replace
+//    the first instance of "old" in the string with "new", if it
+//    exists.  If "global" is true; call this repeatedly until it
+//    fails.  RETURN a new string, regardless of whether the replacement
+//    happened or not.
+// ----------------------------------------------------------------------
+
+std::string StringReplace(const std::string &s, const std::string &oldsub,
+                          const std::string &newsub, bool replace_all) {
+  std::string ret;
+  StringReplace(s, oldsub, newsub, replace_all, &ret);
+  return ret;
+}
+
+// ----------------------------------------------------------------------
+// SplitStringUsing()
+//    Split a string using a character delimiter. Append the components
+//    to 'result'.
+//
+// Note: For multi-character delimiters, this routine will split on *ANY* of
+// the characters in the string, not the entire string as a single delimiter.
+// ----------------------------------------------------------------------
+template <typename ITR>
+static inline void SplitStringToIteratorUsing(StringPiece full,
+                                              const char *delim, ITR &result) {
+  // Optimize the common case where delim is a single character.
+  if (delim[0] != '\0' && delim[1] == '\0') {
+    char c = delim[0];
+    const char* p = full.data();
+    const char* end = p + full.size();
+    while (p != end) {
+      if (*p == c) {
+        ++p;
+      } else {
+        const char* start = p;
+        while (++p != end && *p != c);
+        *result++ = std::string(start, p - start);
+      }
+    }
+    return;
+  }
+
+  std::string::size_type begin_index, end_index;
+  begin_index = full.find_first_not_of(delim);
+  while (begin_index != std::string::npos) {
+    end_index = full.find_first_of(delim, begin_index);
+    if (end_index == std::string::npos) {
+      *result++ = std::string(full.substr(begin_index));
+      return;
+    }
+    *result++ =
+        std::string(full.substr(begin_index, (end_index - begin_index)));
+    begin_index = full.find_first_not_of(delim, end_index);
+  }
+}
+
+void SplitStringUsing(StringPiece full, const char *delim,
+                      std::vector<std::string> *result) {
+  std::back_insert_iterator<std::vector<std::string> > it(*result);
+  SplitStringToIteratorUsing(full, delim, it);
+}
+
+// Split a string using a character delimiter. Append the components
+// to 'result'.  If there are consecutive delimiters, this function
+// will return corresponding empty strings. The string is split into
+// at most the specified number of pieces greedily. This means that the
+// last piece may possibly be split further. To split into as many pieces
+// as possible, specify 0 as the number of pieces.
+//
+// If "full" is the empty string, yields an empty string as the only value.
+//
+// If "pieces" is negative for some reason, it returns the whole string
+// ----------------------------------------------------------------------
+template <typename ITR>
+static inline void SplitStringToIteratorAllowEmpty(StringPiece full,
+                                                   const char *delim,
+                                                   int pieces, ITR &result) {
+  std::string::size_type begin_index, end_index;
+  begin_index = 0;
+
+  for (int i = 0; (i < pieces-1) || (pieces == 0); i++) {
+    end_index = full.find_first_of(delim, begin_index);
+    if (end_index == std::string::npos) {
+      *result++ = std::string(full.substr(begin_index));
+      return;
+    }
+    *result++ =
+        std::string(full.substr(begin_index, (end_index - begin_index)));
+    begin_index = end_index + 1;
+  }
+  *result++ = std::string(full.substr(begin_index));
+}
+
+void SplitStringAllowEmpty(StringPiece full, const char *delim,
+                           std::vector<std::string> *result) {
+  std::back_insert_iterator<std::vector<std::string> > it(*result);
+  SplitStringToIteratorAllowEmpty(full, delim, 0, it);
+}
+
+// ----------------------------------------------------------------------
+// JoinStrings()
+//    This merges a vector of string components with delim inserted
+//    as separaters between components.
+//
+// ----------------------------------------------------------------------
+template <class ITERATOR>
+static void JoinStringsIterator(const ITERATOR &start, const ITERATOR &end,
+                                const char *delim, std::string *result) {
+  GOOGLE_CHECK(result != nullptr);
+  result->clear();
+  int delim_length = strlen(delim);
+
+  // Precompute resulting length so we can reserve() memory in one shot.
+  int length = 0;
+  for (ITERATOR iter = start; iter != end; ++iter) {
+    if (iter != start) {
+      length += delim_length;
+    }
+    length += iter->size();
+  }
+  result->reserve(length);
+
+  // Now combine everything.
+  for (ITERATOR iter = start; iter != end; ++iter) {
+    if (iter != start) {
+      result->append(delim, delim_length);
+    }
+    result->append(iter->data(), iter->size());
+  }
+}
+
+void JoinStrings(const std::vector<std::string> &components, const char *delim,
+                 std::string *result) {
+  JoinStringsIterator(components.begin(), components.end(), delim, result);
+}
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeSequences()
+//    This does all the unescaping that C does: \ooo, \r, \n, etc
+//    Returns length of resulting string.
+//    The implementation of \x parses any positive number of hex digits,
+//    but it is an error if the value requires more than 8 bits, and the
+//    result is truncated to 8 bits.
+//
+//    The second call stores its errors in a supplied string vector.
+//    If the string vector pointer is nullptr, it reports the errors with LOG().
+// ----------------------------------------------------------------------
+
+#define IS_OCTAL_DIGIT(c) (((c) >= '0') && ((c) <= '7'))
+
+// Protocol buffers doesn't ever care about errors, but I don't want to remove
+// the code.
+#define LOG_STRING(LEVEL, VECTOR) GOOGLE_LOG_IF(LEVEL, false)
+
+int UnescapeCEscapeSequences(const char* source, char* dest) {
+  return UnescapeCEscapeSequences(source, dest, nullptr);
+}
+
+int UnescapeCEscapeSequences(const char *source, char *dest,
+                             std::vector<std::string> *errors) {
+  GOOGLE_DCHECK(errors == nullptr) << "Error reporting not implemented.";
+
+  char* d = dest;
+  const char* p = source;
+
+  // Small optimization for case where source = dest and there's no escaping
+  while ( p == d && *p != '\0' && *p != '\\' )
+    p++, d++;
+
+  while (*p != '\0') {
+    if (*p != '\\') {
+      *d++ = *p++;
+    } else {
+      switch ( *++p ) {                    // skip past the '\\'
+        case '\0':
+          LOG_STRING(ERROR, errors) << "String cannot end with \\";
+          *d = '\0';
+          return d - dest;   // we're done with p
+        case 'a':  *d++ = '\a';  break;
+        case 'b':  *d++ = '\b';  break;
+        case 'f':  *d++ = '\f';  break;
+        case 'n':  *d++ = '\n';  break;
+        case 'r':  *d++ = '\r';  break;
+        case 't':  *d++ = '\t';  break;
+        case 'v':  *d++ = '\v';  break;
+        case '\\': *d++ = '\\';  break;
+        case '?':  *d++ = '\?';  break;    // \?  Who knew?
+        case '\'': *d++ = '\'';  break;
+        case '"':  *d++ = '\"';  break;
+        case '0': case '1': case '2': case '3':  // octal digit: 1 to 3 digits
+        case '4': case '5': case '6': case '7': {
+          char ch = *p - '0';
+          if ( IS_OCTAL_DIGIT(p[1]) )
+            ch = ch * 8 + *++p - '0';
+          if ( IS_OCTAL_DIGIT(p[1]) )      // safe (and easy) to do this twice
+            ch = ch * 8 + *++p - '0';      // now points at last digit
+          *d++ = ch;
+          break;
+        }
+        case 'x': case 'X': {
+          if (!isxdigit(p[1])) {
+            if (p[1] == '\0') {
+              LOG_STRING(ERROR, errors) << "String cannot end with \\x";
+            } else {
+              LOG_STRING(ERROR, errors) <<
+                "\\x cannot be followed by non-hex digit: \\" << *p << p[1];
+            }
+            break;
+          }
+          unsigned int ch = 0;
+          const char *hex_start = p;
+          while (isxdigit(p[1]))  // arbitrarily many hex digits
+            ch = (ch << 4) + hex_digit_to_int(*++p);
+          if (ch > 0xFF)
+            LOG_STRING(ERROR, errors)
+                << "Value of "
+                << "\\" << std::string(hex_start, p + 1 - hex_start)
+                << " exceeds 8 bits";
+          *d++ = ch;
+          break;
+        }
+#if 0  // TODO(kenton):  Support \u and \U?  Requires runetochar().
+        case 'u': {
+          // \uhhhh => convert 4 hex digits to UTF-8
+          char32 rune = 0;
+          const char *hex_start = p;
+          for (int i = 0; i < 4; ++i) {
+            if (isxdigit(p[1])) {  // Look one char ahead.
+              rune = (rune << 4) + hex_digit_to_int(*++p);  // Advance p.
+            } else {
+              LOG_STRING(ERROR, errors)
+                << "\\u must be followed by 4 hex digits: \\"
+                <<  std::string(hex_start, p+1-hex_start);
+              break;
+            }
+          }
+          d += runetochar(d, &rune);
+          break;
+        }
+        case 'U': {
+          // \Uhhhhhhhh => convert 8 hex digits to UTF-8
+          char32 rune = 0;
+          const char *hex_start = p;
+          for (int i = 0; i < 8; ++i) {
+            if (isxdigit(p[1])) {  // Look one char ahead.
+              // Don't change rune until we're sure this
+              // is within the Unicode limit, but do advance p.
+              char32 newrune = (rune << 4) + hex_digit_to_int(*++p);
+              if (newrune > 0x10FFFF) {
+                LOG_STRING(ERROR, errors)
+                  << "Value of \\"
+                  << std::string(hex_start, p + 1 - hex_start)
+                  << " exceeds Unicode limit (0x10FFFF)";
+                break;
+              } else {
+                rune = newrune;
+              }
+            } else {
+              LOG_STRING(ERROR, errors)
+                << "\\U must be followed by 8 hex digits: \\"
+                <<  std::string(hex_start, p+1-hex_start);
+              break;
+            }
+          }
+          d += runetochar(d, &rune);
+          break;
+        }
+#endif
+        default:
+          LOG_STRING(ERROR, errors) << "Unknown escape sequence: \\" << *p;
+      }
+      p++;                                 // read past letter we escaped
+    }
+  }
+  *d = '\0';
+  return d - dest;
+}
+
+// ----------------------------------------------------------------------
+// UnescapeCEscapeString()
+//    This does the same thing as UnescapeCEscapeSequences, but creates
+//    a new string. The caller does not need to worry about allocating
+//    a dest buffer. This should be used for non performance critical
+//    tasks such as printing debug messages. It is safe for src and dest
+//    to be the same.
+//
+//    The second call stores its errors in a supplied string vector.
+//    If the string vector pointer is nullptr, it reports the errors with LOG().
+//
+//    In the first and second calls, the length of dest is returned. In the
+//    the third call, the new string is returned.
+// ----------------------------------------------------------------------
+int UnescapeCEscapeString(const std::string &src, std::string *dest) {
+  return UnescapeCEscapeString(src, dest, nullptr);
+}
+
+int UnescapeCEscapeString(const std::string &src, std::string *dest,
+                          std::vector<std::string> *errors) {
+  std::unique_ptr<char[]> unescaped(new char[src.size() + 1]);
+  int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), errors);
+  GOOGLE_CHECK(dest);
+  dest->assign(unescaped.get(), len);
+  return len;
+}
+
+std::string UnescapeCEscapeString(const std::string &src) {
+  std::unique_ptr<char[]> unescaped(new char[src.size() + 1]);
+  int len = UnescapeCEscapeSequences(src.c_str(), unescaped.get(), nullptr);
+  return std::string(unescaped.get(), len);
+}
+
+// ----------------------------------------------------------------------
+// CEscapeString()
+// CHexEscapeString()
+//    Copies 'src' to 'dest', escaping dangerous characters using
+//    C-style escape sequences. This is very useful for preparing query
+//    flags. 'src' and 'dest' should not overlap. The 'Hex' version uses
+//    hexadecimal rather than octal sequences.
+//    Returns the number of bytes written to 'dest' (not including the \0)
+//    or -1 if there was insufficient space.
+//
+//    Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// ----------------------------------------------------------------------
+int CEscapeInternal(const char* src, int src_len, char* dest,
+                    int dest_len, bool use_hex, bool utf8_safe) {
+  const char* src_end = src + src_len;
+  int used = 0;
+  bool last_hex_escape = false; // true if last output char was \xNN
+
+  for (; src < src_end; src++) {
+    if (dest_len - used < 2)   // Need space for two letter escape
+      return -1;
+
+    bool is_hex_escape = false;
+    switch (*src) {
+      case '\n': dest[used++] = '\\'; dest[used++] = 'n';  break;
+      case '\r': dest[used++] = '\\'; dest[used++] = 'r';  break;
+      case '\t': dest[used++] = '\\'; dest[used++] = 't';  break;
+      case '\"': dest[used++] = '\\'; dest[used++] = '\"'; break;
+      case '\'': dest[used++] = '\\'; dest[used++] = '\''; break;
+      case '\\': dest[used++] = '\\'; dest[used++] = '\\'; break;
+      default:
+        // Note that if we emit \xNN and the src character after that is a hex
+        // digit then that digit must be escaped too to prevent it being
+        // interpreted as part of the character code by C.
+        if ((!utf8_safe || static_cast<uint8_t>(*src) < 0x80) &&
+            (!isprint(*src) ||
+             (last_hex_escape && isxdigit(*src)))) {
+          if (dest_len - used < 4) // need space for 4 letter escape
+            return -1;
+          dest[used++] = '\\';
+          if (use_hex) {
+            constexpr char hexdigits[] = "0123456789abcdef";
+            dest[used++] = 'x';
+            dest[used++] = hexdigits[(static_cast<uint8_t>(*src) >> 4) & 0xf];
+            dest[used++] = hexdigits[static_cast<uint8_t>(*src) & 0xf];
+          } else {
+            dest[used++] = '0' + ((static_cast<uint8_t>(*src) >> 6) & 0x3);
+            dest[used++] = '0' + ((static_cast<uint8_t>(*src) >> 3) & 0x7);
+            dest[used++] = '0' + (static_cast<uint8_t>(*src) & 0x7);
+          }
+          is_hex_escape = use_hex;
+        } else {
+          dest[used++] = *src; break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+
+  if (dest_len - used < 1)   // make sure that there is room for \0
+    return -1;
+
+  dest[used] = '\0';   // doesn't count towards return value though
+  return used;
+}
+
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+static inline size_t CEscapedLength(StringPiece src) {
+  static char c_escaped_len[256] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4,  // \t, \n, \r
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,  // ", '
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  };
+
+  size_t escaped_len = 0;
+  for (StringPiece::size_type i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    escaped_len += c_escaped_len[c];
+  }
+  return escaped_len;
+}
+
+// ----------------------------------------------------------------------
+// Escapes 'src' using C-style escape sequences, and appends the escaped string
+// to 'dest'. This version is faster than calling CEscapeInternal as it computes
+// the required space using a lookup table, and also does not do any special
+// handling for Hex or UTF-8 characters.
+// ----------------------------------------------------------------------
+void CEscapeAndAppend(StringPiece src, std::string *dest) {
+  size_t escaped_len = CEscapedLength(src);
+  if (escaped_len == src.size()) {
+    dest->append(src.data(), src.size());
+    return;
+  }
+
+  size_t cur_dest_len = dest->size();
+  dest->resize(cur_dest_len + escaped_len);
+  char* append_ptr = &(*dest)[cur_dest_len];
+
+  for (StringPiece::size_type i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    switch (c) {
+      case '\n': *append_ptr++ = '\\'; *append_ptr++ = 'n'; break;
+      case '\r': *append_ptr++ = '\\'; *append_ptr++ = 'r'; break;
+      case '\t': *append_ptr++ = '\\'; *append_ptr++ = 't'; break;
+      case '\"': *append_ptr++ = '\\'; *append_ptr++ = '\"'; break;
+      case '\'': *append_ptr++ = '\\'; *append_ptr++ = '\''; break;
+      case '\\': *append_ptr++ = '\\'; *append_ptr++ = '\\'; break;
+      default:
+        if (!isprint(c)) {
+          *append_ptr++ = '\\';
+          *append_ptr++ = '0' + c / 64;
+          *append_ptr++ = '0' + (c % 64) / 8;
+          *append_ptr++ = '0' + c % 8;
+        } else {
+          *append_ptr++ = c;
+        }
+        break;
+    }
+  }
+}
+
+std::string CEscape(const std::string &src) {
+  std::string dest;
+  CEscapeAndAppend(src, &dest);
+  return dest;
+}
+
+namespace strings {
+
+std::string Utf8SafeCEscape(const std::string &src) {
+  const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
+  std::unique_ptr<char[]> dest(new char[dest_length]);
+  const int len = CEscapeInternal(src.data(), src.size(),
+                                  dest.get(), dest_length, false, true);
+  GOOGLE_DCHECK_GE(len, 0);
+  return std::string(dest.get(), len);
+}
+
+std::string CHexEscape(const std::string &src) {
+  const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
+  std::unique_ptr<char[]> dest(new char[dest_length]);
+  const int len = CEscapeInternal(src.data(), src.size(),
+                                  dest.get(), dest_length, true, false);
+  GOOGLE_DCHECK_GE(len, 0);
+  return std::string(dest.get(), len);
+}
+
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// strto32_adaptor()
+// strtou32_adaptor()
+//    Implementation of strto[u]l replacements that have identical
+//    overflow and underflow characteristics for both ILP-32 and LP-64
+//    platforms, including errno preservation in error-free calls.
+// ----------------------------------------------------------------------
+
+int32_t strto32_adaptor(const char *nptr, char **endptr, int base) {
+  const int saved_errno = errno;
+  errno = 0;
+  const long result = strtol(nptr, endptr, base);
+  if (errno == ERANGE && result == LONG_MIN) {
+    return std::numeric_limits<int32_t>::min();
+  } else if (errno == ERANGE && result == LONG_MAX) {
+    return std::numeric_limits<int32_t>::max();
+  } else if (errno == 0 && result < std::numeric_limits<int32_t>::min()) {
+    errno = ERANGE;
+    return std::numeric_limits<int32_t>::min();
+  } else if (errno == 0 && result > std::numeric_limits<int32_t>::max()) {
+    errno = ERANGE;
+    return std::numeric_limits<int32_t>::max();
+  }
+  if (errno == 0)
+    errno = saved_errno;
+  return static_cast<int32_t>(result);
+}
+
+uint32_t strtou32_adaptor(const char *nptr, char **endptr, int base) {
+  const int saved_errno = errno;
+  errno = 0;
+  const unsigned long result = strtoul(nptr, endptr, base);
+  if (errno == ERANGE && result == ULONG_MAX) {
+    return std::numeric_limits<uint32_t>::max();
+  } else if (errno == 0 && result > std::numeric_limits<uint32_t>::max()) {
+    errno = ERANGE;
+    return std::numeric_limits<uint32_t>::max();
+  }
+  if (errno == 0)
+    errno = saved_errno;
+  return static_cast<uint32_t>(result);
+}
+
+inline bool safe_parse_sign(std::string *text /*inout*/,
+                            bool *negative_ptr /*output*/) {
+  const char* start = text->data();
+  const char* end = start + text->size();
+
+  // Consume whitespace.
+  while (start < end && (start[0] == ' ')) {
+    ++start;
+  }
+  while (start < end && (end[-1] == ' ')) {
+    --end;
+  }
+  if (start >= end) {
+    return false;
+  }
+
+  // Consume sign.
+  *negative_ptr = (start[0] == '-');
+  if (*negative_ptr || start[0] == '+') {
+    ++start;
+    if (start >= end) {
+      return false;
+    }
+  }
+  *text = text->substr(start - text->data(), end - start);
+  return true;
+}
+
+template <typename IntType>
+bool safe_parse_positive_int(std::string text, IntType *value_p) {
+  int base = 10;
+  IntType value = 0;
+  const IntType vmax = std::numeric_limits<IntType>::max();
+  assert(vmax > 0);
+  assert(static_cast<int>(vmax) >= base);
+  const IntType vmax_over_base = vmax / base;
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = c - '0';
+    if (digit >= base || digit < 0) {
+      *value_p = value;
+      return false;
+    }
+    if (value > vmax_over_base) {
+      *value_p = vmax;
+      return false;
+    }
+    value *= base;
+    if (value > vmax - digit) {
+      *value_p = vmax;
+      return false;
+    }
+    value += digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+template <typename IntType>
+bool safe_parse_negative_int(const std::string &text, IntType *value_p) {
+  int base = 10;
+  IntType value = 0;
+  const IntType vmin = std::numeric_limits<IntType>::min();
+  assert(vmin < 0);
+  assert(vmin <= 0 - base);
+  IntType vmin_over_base = vmin / base;
+  // 2003 c++ standard [expr.mul]
+  // "... the sign of the remainder is implementation-defined."
+  // Although (vmin/base)*base + vmin%base is always vmin.
+  // 2011 c++ standard tightens the spec but we cannot rely on it.
+  if (vmin % base > 0) {
+    vmin_over_base += 1;
+  }
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = c - '0';
+    if (digit >= base || digit < 0) {
+      *value_p = value;
+      return false;
+    }
+    if (value < vmin_over_base) {
+      *value_p = vmin;
+      return false;
+    }
+    value *= base;
+    if (value < vmin + digit) {
+      *value_p = vmin;
+      return false;
+    }
+    value -= digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+template <typename IntType>
+bool safe_int_internal(std::string text, IntType *value_p) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign(&text, &negative)) {
+    return false;
+  }
+  if (!negative) {
+    return safe_parse_positive_int(text, value_p);
+  } else {
+    return safe_parse_negative_int(text, value_p);
+  }
+}
+
+template <typename IntType>
+bool safe_uint_internal(std::string text, IntType *value_p) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign(&text, &negative) || negative) {
+    return false;
+  }
+  return safe_parse_positive_int(text, value_p);
+}
+
+// ----------------------------------------------------------------------
+// FastIntToBuffer()
+// FastInt64ToBuffer()
+// FastHexToBuffer()
+// FastHex64ToBuffer()
+// FastHex32ToBuffer()
+// ----------------------------------------------------------------------
+
+// Offset into buffer where FastInt64ToBuffer places the end of string
+// null character.  Also used by FastInt64ToBufferLeft.
+static const int kFastInt64ToBufferOffset = 21;
+
+char *FastInt64ToBuffer(int64_t i, char* buffer) {
+  // We could collapse the positive and negative sections, but that
+  // would be slightly slower for positive numbers...
+  // 22 bytes is enough to store -2**64, -18446744073709551616.
+  char* p = buffer + kFastInt64ToBufferOffset;
+  *p-- = '\0';
+  if (i >= 0) {
+    do {
+      *p-- = '0' + i % 10;
+      i /= 10;
+    } while (i > 0);
+    return p + 1;
+  } else {
+    // On different platforms, % and / have different behaviors for
+    // negative numbers, so we need to jump through hoops to make sure
+    // we don't divide negative numbers.
+    if (i > -10) {
+      i = -i;
+      *p-- = '0' + i;
+      *p = '-';
+      return p;
+    } else {
+      // Make sure we aren't at MIN_INT, in which case we can't say i = -i
+      i = i + 10;
+      i = -i;
+      *p-- = '0' + i % 10;
+      // Undo what we did a moment ago
+      i = i / 10 + 1;
+      do {
+        *p-- = '0' + i % 10;
+        i /= 10;
+      } while (i > 0);
+      *p = '-';
+      return p;
+    }
+  }
+}
+
+// Offset into buffer where FastInt32ToBuffer places the end of string
+// null character.  Also used by FastInt32ToBufferLeft
+static const int kFastInt32ToBufferOffset = 11;
+
+// Yes, this is a duplicate of FastInt64ToBuffer.  But, we need this for the
+// compiler to generate 32 bit arithmetic instructions.  It's much faster, at
+// least with 32 bit binaries.
+char *FastInt32ToBuffer(int32_t i, char* buffer) {
+  // We could collapse the positive and negative sections, but that
+  // would be slightly slower for positive numbers...
+  // 12 bytes is enough to store -2**32, -4294967296.
+  char* p = buffer + kFastInt32ToBufferOffset;
+  *p-- = '\0';
+  if (i >= 0) {
+    do {
+      *p-- = '0' + i % 10;
+      i /= 10;
+    } while (i > 0);
+    return p + 1;
+  } else {
+    // On different platforms, % and / have different behaviors for
+    // negative numbers, so we need to jump through hoops to make sure
+    // we don't divide negative numbers.
+    if (i > -10) {
+      i = -i;
+      *p-- = '0' + i;
+      *p = '-';
+      return p;
+    } else {
+      // Make sure we aren't at MIN_INT, in which case we can't say i = -i
+      i = i + 10;
+      i = -i;
+      *p-- = '0' + i % 10;
+      // Undo what we did a moment ago
+      i = i / 10 + 1;
+      do {
+        *p-- = '0' + i % 10;
+        i /= 10;
+      } while (i > 0);
+      *p = '-';
+      return p;
+    }
+  }
+}
+
+char *FastHexToBuffer(int i, char* buffer) {
+  GOOGLE_CHECK(i >= 0) << "FastHexToBuffer() wants non-negative integers, not " << i;
+
+  static const char *hexdigits = "0123456789abcdef";
+  char *p = buffer + 21;
+  *p-- = '\0';
+  do {
+    *p-- = hexdigits[i & 15];   // mod by 16
+    i >>= 4;                    // divide by 16
+  } while (i > 0);
+  return p + 1;
+}
+
+char *InternalFastHexToBuffer(uint64_t value, char* buffer, int num_byte) {
+  static const char *hexdigits = "0123456789abcdef";
+  buffer[num_byte] = '\0';
+  for (int i = num_byte - 1; i >= 0; i--) {
+#ifdef _M_X64
+    // MSVC x64 platform has a bug optimizing the uint32(value) in the #else
+    // block. Given that the uint32 cast was to improve performance on 32-bit
+    // platforms, we use 64-bit '&' directly.
+    buffer[i] = hexdigits[value & 0xf];
+#else
+    buffer[i] = hexdigits[uint32_t(value) & 0xf];
+#endif
+    value >>= 4;
+  }
+  return buffer;
+}
+
+char *FastHex64ToBuffer(uint64_t value, char* buffer) {
+  return InternalFastHexToBuffer(value, buffer, 16);
+}
+
+char *FastHex32ToBuffer(uint32_t value, char* buffer) {
+  return InternalFastHexToBuffer(value, buffer, 8);
+}
+
+// ----------------------------------------------------------------------
+// FastInt32ToBufferLeft()
+// FastUInt32ToBufferLeft()
+// FastInt64ToBufferLeft()
+// FastUInt64ToBufferLeft()
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer (hence the name, as the
+// output is left-aligned).  The caller is responsible for ensuring that
+// the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the string (i.e. the null character
+// terminating the string).
+// ----------------------------------------------------------------------
+
+static const char two_ASCII_digits[100][2] = {
+  {'0','0'}, {'0','1'}, {'0','2'}, {'0','3'}, {'0','4'},
+  {'0','5'}, {'0','6'}, {'0','7'}, {'0','8'}, {'0','9'},
+  {'1','0'}, {'1','1'}, {'1','2'}, {'1','3'}, {'1','4'},
+  {'1','5'}, {'1','6'}, {'1','7'}, {'1','8'}, {'1','9'},
+  {'2','0'}, {'2','1'}, {'2','2'}, {'2','3'}, {'2','4'},
+  {'2','5'}, {'2','6'}, {'2','7'}, {'2','8'}, {'2','9'},
+  {'3','0'}, {'3','1'}, {'3','2'}, {'3','3'}, {'3','4'},
+  {'3','5'}, {'3','6'}, {'3','7'}, {'3','8'}, {'3','9'},
+  {'4','0'}, {'4','1'}, {'4','2'}, {'4','3'}, {'4','4'},
+  {'4','5'}, {'4','6'}, {'4','7'}, {'4','8'}, {'4','9'},
+  {'5','0'}, {'5','1'}, {'5','2'}, {'5','3'}, {'5','4'},
+  {'5','5'}, {'5','6'}, {'5','7'}, {'5','8'}, {'5','9'},
+  {'6','0'}, {'6','1'}, {'6','2'}, {'6','3'}, {'6','4'},
+  {'6','5'}, {'6','6'}, {'6','7'}, {'6','8'}, {'6','9'},
+  {'7','0'}, {'7','1'}, {'7','2'}, {'7','3'}, {'7','4'},
+  {'7','5'}, {'7','6'}, {'7','7'}, {'7','8'}, {'7','9'},
+  {'8','0'}, {'8','1'}, {'8','2'}, {'8','3'}, {'8','4'},
+  {'8','5'}, {'8','6'}, {'8','7'}, {'8','8'}, {'8','9'},
+  {'9','0'}, {'9','1'}, {'9','2'}, {'9','3'}, {'9','4'},
+  {'9','5'}, {'9','6'}, {'9','7'}, {'9','8'}, {'9','9'}
+};
+
+char* FastUInt32ToBufferLeft(uint32_t u, char* buffer) {
+  uint32_t digits;
+  const char *ASCII_digits = nullptr;
+  // The idea of this implementation is to trim the number of divides to as few
+  // as possible by using multiplication and subtraction rather than mod (%),
+  // and by outputting two digits at a time rather than one.
+  // The huge-number case is first, in the hopes that the compiler will output
+  // that case in one branch-free block of code, and only output conditional
+  // branches into it from below.
+  if (u >= 1000000000) {  // >= 1,000,000,000
+    digits = u / 100000000;  // 100,000,000
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt100_000_000:
+    u -= digits * 100000000;  // 100,000,000
+lt100_000_000:
+    digits = u / 1000000;  // 1,000,000
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt1_000_000:
+    u -= digits * 1000000;  // 1,000,000
+lt1_000_000:
+    digits = u / 10000;  // 10,000
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt10_000:
+    u -= digits * 10000;  // 10,000
+lt10_000:
+    digits = u / 100;
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+sublt100:
+    u -= digits * 100;
+lt100:
+    digits = u;
+    ASCII_digits = two_ASCII_digits[digits];
+    buffer[0] = ASCII_digits[0];
+    buffer[1] = ASCII_digits[1];
+    buffer += 2;
+done:
+    *buffer = 0;
+    return buffer;
+  }
+
+  if (u < 100) {
+    digits = u;
+    if (u >= 10) goto lt100;
+    *buffer++ = '0' + digits;
+    goto done;
+  }
+  if (u  <  10000) {   // 10,000
+    if (u >= 1000) goto lt10_000;
+    digits = u / 100;
+    *buffer++ = '0' + digits;
+    goto sublt100;
+  }
+  if (u  <  1000000) {   // 1,000,000
+    if (u >= 100000) goto lt1_000_000;
+    digits = u / 10000;  //    10,000
+    *buffer++ = '0' + digits;
+    goto sublt10_000;
+  }
+  if (u  <  100000000) {   // 100,000,000
+    if (u >= 10000000) goto lt100_000_000;
+    digits = u / 1000000;  //   1,000,000
+    *buffer++ = '0' + digits;
+    goto sublt1_000_000;
+  }
+  // we already know that u < 1,000,000,000
+  digits = u / 100000000;   // 100,000,000
+  *buffer++ = '0' + digits;
+  goto sublt100_000_000;
+}
+
+char* FastInt32ToBufferLeft(int32_t i, char* buffer) {
+  uint32_t u = 0;
+  if (i < 0) {
+    *buffer++ = '-';
+    u -= i;
+  } else {
+    u = i;
+  }
+  return FastUInt32ToBufferLeft(u, buffer);
+}
+
+char* FastUInt64ToBufferLeft(uint64_t u64, char* buffer) {
+  int digits;
+  const char *ASCII_digits = nullptr;
+
+  uint32_t u = static_cast<uint32_t>(u64);
+  if (u == u64) return FastUInt32ToBufferLeft(u, buffer);
+
+  uint64_t top_11_digits = u64 / 1000000000;
+  buffer = FastUInt64ToBufferLeft(top_11_digits, buffer);
+  u = u64 - (top_11_digits * 1000000000);
+
+  digits = u / 10000000;  // 10,000,000
+  GOOGLE_DCHECK_LT(digits, 100);
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 10000000;  // 10,000,000
+  digits = u / 100000;  // 100,000
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 100000;  // 100,000
+  digits = u / 1000;  // 1,000
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 1000;  // 1,000
+  digits = u / 10;
+  ASCII_digits = two_ASCII_digits[digits];
+  buffer[0] = ASCII_digits[0];
+  buffer[1] = ASCII_digits[1];
+  buffer += 2;
+  u -= digits * 10;
+  digits = u;
+  *buffer++ = '0' + digits;
+  *buffer = 0;
+  return buffer;
+}
+
+char* FastInt64ToBufferLeft(int64_t i, char* buffer) {
+  uint64_t u = 0;
+  if (i < 0) {
+    *buffer++ = '-';
+    u -= i;
+  } else {
+    u = i;
+  }
+  return FastUInt64ToBufferLeft(u, buffer);
+}
+
+// ----------------------------------------------------------------------
+// SimpleItoa()
+//    Description: converts an integer to a string.
+//
+//    Return value: string
+// ----------------------------------------------------------------------
+
+std::string SimpleItoa(int i) {
+  char buffer[kFastToBufferSize];
+  return (sizeof(i) == 4) ?
+    FastInt32ToBuffer(i, buffer) :
+    FastInt64ToBuffer(i, buffer);
+}
+
+std::string SimpleItoa(unsigned int i) {
+  char buffer[kFastToBufferSize];
+  return std::string(buffer, (sizeof(i) == 4)
+                                 ? FastUInt32ToBufferLeft(i, buffer)
+                                 : FastUInt64ToBufferLeft(i, buffer));
+}
+
+std::string SimpleItoa(long i) {
+  char buffer[kFastToBufferSize];
+  return (sizeof(i) == 4) ?
+    FastInt32ToBuffer(i, buffer) :
+    FastInt64ToBuffer(i, buffer);
+}
+
+std::string SimpleItoa(unsigned long i) {
+  char buffer[kFastToBufferSize];
+  return std::string(buffer, (sizeof(i) == 4)
+                                 ? FastUInt32ToBufferLeft(i, buffer)
+                                 : FastUInt64ToBufferLeft(i, buffer));
+}
+
+std::string SimpleItoa(long long i) {
+  char buffer[kFastToBufferSize];
+  return (sizeof(i) == 4) ?
+    FastInt32ToBuffer(i, buffer) :
+    FastInt64ToBuffer(i, buffer);
+}
+
+std::string SimpleItoa(unsigned long long i) {
+  char buffer[kFastToBufferSize];
+  return std::string(buffer, (sizeof(i) == 4)
+                                 ? FastUInt32ToBufferLeft(i, buffer)
+                                 : FastUInt64ToBufferLeft(i, buffer));
+}
+
+// ----------------------------------------------------------------------
+// SimpleDtoa()
+// SimpleFtoa()
+// DoubleToBuffer()
+// FloatToBuffer()
+//    We want to print the value without losing precision, but we also do
+//    not want to print more digits than necessary.  This turns out to be
+//    trickier than it sounds.  Numbers like 0.2 cannot be represented
+//    exactly in binary.  If we print 0.2 with a very large precision,
+//    e.g. "%.50g", we get "0.2000000000000000111022302462515654042363167".
+//    On the other hand, if we set the precision too low, we lose
+//    significant digits when printing numbers that actually need them.
+//    It turns out there is no precision value that does the right thing
+//    for all numbers.
+//
+//    Our strategy is to first try printing with a precision that is never
+//    over-precise, then parse the result with strtod() to see if it
+//    matches.  If not, we print again with a precision that will always
+//    give a precise result, but may use more digits than necessary.
+//
+//    An arguably better strategy would be to use the algorithm described
+//    in "How to Print Floating-Point Numbers Accurately" by Steele &
+//    White, e.g. as implemented by David M. Gay's dtoa().  It turns out,
+//    however, that the following implementation is about as fast as
+//    DMG's code.  Furthermore, DMG's code locks mutexes, which means it
+//    will not scale well on multi-core machines.  DMG's code is slightly
+//    more accurate (in that it will never use more digits than
+//    necessary), but this is probably irrelevant for most users.
+//
+//    Rob Pike and Ken Thompson also have an implementation of dtoa() in
+//    third_party/fmt/fltfmt.cc.  Their implementation is similar to this
+//    one in that it makes guesses and then uses strtod() to check them.
+//    Their implementation is faster because they use their own code to
+//    generate the digits in the first place rather than use snprintf(),
+//    thus avoiding format string parsing overhead.  However, this makes
+//    it considerably more complicated than the following implementation,
+//    and it is embedded in a larger library.  If speed turns out to be
+//    an issue, we could re-implement this in terms of their
+//    implementation.
+// ----------------------------------------------------------------------
+
+std::string SimpleDtoa(double value) {
+  char buffer[kDoubleToBufferSize];
+  return DoubleToBuffer(value, buffer);
+}
+
+std::string SimpleFtoa(float value) {
+  char buffer[kFloatToBufferSize];
+  return FloatToBuffer(value, buffer);
+}
+
+static inline bool IsValidFloatChar(char c) {
+  return ('0' <= c && c <= '9') ||
+         c == 'e' || c == 'E' ||
+         c == '+' || c == '-';
+}
+
+void DelocalizeRadix(char* buffer) {
+  // Fast check:  if the buffer has a normal decimal point, assume no
+  // translation is needed.
+  if (strchr(buffer, '.') != nullptr) return;
+
+  // Find the first unknown character.
+  while (IsValidFloatChar(*buffer)) ++buffer;
+
+  if (*buffer == '\0') {
+    // No radix character found.
+    return;
+  }
+
+  // We are now pointing at the locale-specific radix character.  Replace it
+  // with '.'.
+  *buffer = '.';
+  ++buffer;
+
+  if (!IsValidFloatChar(*buffer) && *buffer != '\0') {
+    // It appears the radix was a multi-byte character.  We need to remove the
+    // extra bytes.
+    char* target = buffer;
+    do { ++buffer; } while (!IsValidFloatChar(*buffer) && *buffer != '\0');
+    memmove(target, buffer, strlen(buffer) + 1);
+  }
+}
+
+char* DoubleToBuffer(double value, char* buffer) {
+  // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all
+  // platforms these days.  Just in case some system exists where DBL_DIG
+  // is significantly larger -- and risks overflowing our buffer -- we have
+  // this assert.
+  static_assert(DBL_DIG < 20, "DBL_DIG_is_too_big");
+
+  if (value == std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "inf");
+    return buffer;
+  } else if (value == -std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "-inf");
+    return buffer;
+  } else if (std::isnan(value)) {
+    strcpy(buffer, "nan");
+    return buffer;
+  }
+
+  int snprintf_result =
+    snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG, value);
+
+  // The snprintf should never overflow because the buffer is significantly
+  // larger than the precision we asked for.
+  GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
+
+  // We need to make parsed_value volatile in order to force the compiler to
+  // write it out to the stack.  Otherwise, it may keep the value in a
+  // register, and if it does that, it may keep it as a long double instead
+  // of a double.  This long double may have extra bits that make it compare
+  // unequal to "value" even though it would be exactly equal if it were
+  // truncated to a double.
+  volatile double parsed_value = internal::NoLocaleStrtod(buffer, nullptr);
+  if (parsed_value != value) {
+    snprintf_result =
+        snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG + 2, value);
+
+    // Should never overflow; see above.
+    GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
+  }
+
+  DelocalizeRadix(buffer);
+  return buffer;
+}
+
+static int memcasecmp(const char *s1, const char *s2, size_t len) {
+  const unsigned char *us1 = reinterpret_cast<const unsigned char *>(s1);
+  const unsigned char *us2 = reinterpret_cast<const unsigned char *>(s2);
+
+  for (size_t i = 0; i < len; i++) {
+    const int diff =
+      static_cast<int>(static_cast<unsigned char>(ascii_tolower(us1[i]))) -
+      static_cast<int>(static_cast<unsigned char>(ascii_tolower(us2[i])));
+    if (diff != 0) return diff;
+  }
+  return 0;
+}
+
+inline bool CaseEqual(StringPiece s1, StringPiece s2) {
+  if (s1.size() != s2.size()) return false;
+  return memcasecmp(s1.data(), s2.data(), s1.size()) == 0;
+}
+
+bool safe_strtob(StringPiece str, bool* value) {
+  GOOGLE_CHECK(value != nullptr) << "nullptr output boolean given.";
+  if (CaseEqual(str, "true") || CaseEqual(str, "t") ||
+      CaseEqual(str, "yes") || CaseEqual(str, "y") ||
+      CaseEqual(str, "1")) {
+    *value = true;
+    return true;
+  }
+  if (CaseEqual(str, "false") || CaseEqual(str, "f") ||
+      CaseEqual(str, "no") || CaseEqual(str, "n") ||
+      CaseEqual(str, "0")) {
+    *value = false;
+    return true;
+  }
+  return false;
+}
+
+bool safe_strtof(const char* str, float* value) {
+  char* endptr;
+  errno = 0;  // errno only gets set on errors
+#if defined(_WIN32) || defined (__hpux)  // has no strtof()
+  *value = internal::NoLocaleStrtod(str, &endptr);
+#else
+  *value = strtof(str, &endptr);
+#endif
+  return *str != 0 && *endptr == 0 && errno == 0;
+}
+
+bool safe_strtod(const char* str, double* value) {
+  char* endptr;
+  *value = internal::NoLocaleStrtod(str, &endptr);
+  if (endptr != str) {
+    while (ascii_isspace(*endptr)) ++endptr;
+  }
+  // Ignore range errors from strtod.  The values it
+  // returns on underflow and overflow are the right
+  // fallback in a robust setting.
+  return *str != '\0' && *endptr == '\0';
+}
+
+bool safe_strto32(const std::string &str, int32_t *value) {
+  return safe_int_internal(str, value);
+}
+
+bool safe_strtou32(const std::string &str, uint32_t *value) {
+  return safe_uint_internal(str, value);
+}
+
+bool safe_strto64(const std::string &str, int64_t *value) {
+  return safe_int_internal(str, value);
+}
+
+bool safe_strtou64(const std::string &str, uint64_t *value) {
+  return safe_uint_internal(str, value);
+}
+
+char* FloatToBuffer(float value, char* buffer) {
+  // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all
+  // platforms these days.  Just in case some system exists where FLT_DIG
+  // is significantly larger -- and risks overflowing our buffer -- we have
+  // this assert.
+  static_assert(FLT_DIG < 10, "FLT_DIG_is_too_big");
+
+  if (value == std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "inf");
+    return buffer;
+  } else if (value == -std::numeric_limits<double>::infinity()) {
+    strcpy(buffer, "-inf");
+    return buffer;
+  } else if (std::isnan(value)) {
+    strcpy(buffer, "nan");
+    return buffer;
+  }
+
+  int snprintf_result =
+    snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG, value);
+
+  // The snprintf should never overflow because the buffer is significantly
+  // larger than the precision we asked for.
+  GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
+
+  float parsed_value;
+  if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
+    snprintf_result =
+        snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG + 3, value);
+
+    // Should never overflow; see above.
+    GOOGLE_DCHECK(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
+  }
+
+  DelocalizeRadix(buffer);
+  return buffer;
+}
+
+namespace strings {
+
+AlphaNum::AlphaNum(strings::Hex hex) {
+  char *const end = &digits[kFastToBufferSize];
+  char *writer = end;
+  uint64_t value = hex.value;
+  uint64_t width = hex.spec;
+  // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
+  // where 0x10000 is the smallest hex number that is as wide as the user
+  // asked for.
+  uint64_t mask = (static_cast<uint64_t>(1) << ((width - 1) * 4)) | value;
+  static const char hexdigits[] = "0123456789abcdef";
+  do {
+    *--writer = hexdigits[value & 0xF];
+    value >>= 4;
+    mask >>= 4;
+  } while (mask != 0);
+  piece_data_ = writer;
+  piece_size_ = end - writer;
+}
+
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or integers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, C++ strings, and integer values.
+// ----------------------------------------------------------------------
+
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten.  It comes in multiple flavors to minimize
+// call overhead.
+static char *Append1(char *out, const AlphaNum &x) {
+  if (x.size() > 0) {
+    memcpy(out, x.data(), x.size());
+    out += x.size();
+  }
+  return out;
+}
+
+static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
+  if (x1.size() > 0) {
+    memcpy(out, x1.data(), x1.size());
+    out += x1.size();
+  }
+  if (x2.size() > 0) {
+    memcpy(out, x2.data(), x2.size());
+    out += x2.size();
+  }
+  return out;
+}
+
+static char *Append4(char *out, const AlphaNum &x1, const AlphaNum &x2,
+                     const AlphaNum &x3, const AlphaNum &x4) {
+  if (x1.size() > 0) {
+    memcpy(out, x1.data(), x1.size());
+    out += x1.size();
+  }
+  if (x2.size() > 0) {
+    memcpy(out, x2.data(), x2.size());
+    out += x2.size();
+  }
+  if (x3.size() > 0) {
+    memcpy(out, x3.data(), x3.size());
+    out += x3.size();
+  }
+  if (x4.size() > 0) {
+    memcpy(out, x4.data(), x4.size());
+    out += x4.size();
+  }
+  return out;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b) {
+  std::string result;
+  result.resize(a.size() + b.size());
+  char *const begin = &*result.begin();
+  char *out = Append2(begin, a, b);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size());
+  char *const begin = &*result.begin();
+  char *out = Append2(begin, a, b);
+  out = Append1(out, c);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append1(out, e);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append2(out, e, f);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+                   const AlphaNum &g) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append2(out, e, f);
+  out = Append1(out, g);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+                   const AlphaNum &g, const AlphaNum &h) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size() + h.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append4(out, e, f, g, h);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+                   const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+                   const AlphaNum &g, const AlphaNum &h, const AlphaNum &i) {
+  std::string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size() + h.size() + i.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append4(out, e, f, g, h);
+  out = Append1(out, i);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+// It's possible to call StrAppend with a char * pointer that is partway into
+// the string we're appending to.  However the results of this are random.
+// Therefore, check for this in debug mode.  Use unsigned math so we only have
+// to do one comparison.
+#define GOOGLE_DCHECK_NO_OVERLAP(dest, src) \
+    GOOGLE_DCHECK_GT(uintptr_t((src).data() - (dest).data()), \
+                     uintptr_t((dest).size()))
+
+void StrAppend(std::string *result, const AlphaNum &a) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  result->append(a.data(), a.size());
+}
+
+void StrAppend(std::string *result, const AlphaNum &a, const AlphaNum &b) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  std::string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size());
+  char *const begin = &*result->begin();
+  char *out = Append2(begin + old_size, a, b);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(std::string *result, const AlphaNum &a, const AlphaNum &b,
+               const AlphaNum &c) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+  std::string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size() + c.size());
+  char *const begin = &*result->begin();
+  char *out = Append2(begin + old_size, a, b);
+  out = Append1(out, c);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(std::string *result, const AlphaNum &a, const AlphaNum &b,
+               const AlphaNum &c, const AlphaNum &d) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, d);
+  std::string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size() + c.size() + d.size());
+  char *const begin = &*result->begin();
+  char *out = Append4(begin + old_size, a, b, c, d);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+int GlobalReplaceSubstring(const std::string &substring,
+                           const std::string &replacement, std::string *s) {
+  GOOGLE_CHECK(s != nullptr);
+  if (s->empty() || substring.empty())
+    return 0;
+  std::string tmp;
+  int num_replacements = 0;
+  int pos = 0;
+  for (StringPiece::size_type match_pos =
+           s->find(substring.data(), pos, substring.length());
+       match_pos != std::string::npos; pos = match_pos + substring.length(),
+                              match_pos = s->find(substring.data(), pos,
+                                                  substring.length())) {
+    ++num_replacements;
+    // Append the original content before the match.
+    tmp.append(*s, pos, match_pos - pos);
+    // Append the replacement for the match.
+    tmp.append(replacement.begin(), replacement.end());
+  }
+  // Append the content after the last match. If no replacements were made, the
+  // original string is left untouched.
+  if (num_replacements > 0) {
+    tmp.append(*s, pos, s->length() - pos);
+    s->swap(tmp);
+  }
+  return num_replacements;
+}
+
+int CalculateBase64EscapedLen(int input_len, bool do_padding) {
+  // Base64 encodes three bytes of input at a time. If the input is not
+  // divisible by three, we pad as appropriate.
+  //
+  // (from http://tools.ietf.org/html/rfc3548)
+  // Special processing is performed if fewer than 24 bits are available
+  // at the end of the data being encoded.  A full encoding quantum is
+  // always completed at the end of a quantity.  When fewer than 24 input
+  // bits are available in an input group, zero bits are added (on the
+  // right) to form an integral number of 6-bit groups.  Padding at the
+  // end of the data is performed using the '=' character.  Since all base
+  // 64 input is an integral number of octets, only the following cases
+  // can arise:
+
+
+  // Base64 encodes each three bytes of input into four bytes of output.
+  int len = (input_len / 3) * 4;
+
+  if (input_len % 3 == 0) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (1) the final quantum of encoding input is an integral multiple of 24
+    // bits; here, the final unit of encoded output will be an integral
+    // multiple of 4 characters with no "=" padding,
+  } else if (input_len % 3 == 1) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (2) the final quantum of encoding input is exactly 8 bits; here, the
+    // final unit of encoded output will be two characters followed by two
+    // "=" padding characters, or
+    len += 2;
+    if (do_padding) {
+      len += 2;
+    }
+  } else {  // (input_len % 3 == 2)
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (3) the final quantum of encoding input is exactly 16 bits; here, the
+    // final unit of encoded output will be three characters followed by one
+    // "=" padding character.
+    len += 3;
+    if (do_padding) {
+      len += 1;
+    }
+  }
+
+  assert(len >= input_len);  // make sure we didn't overflow
+  return len;
+}
+
+// Base64Escape does padding, so this calculation includes padding.
+int CalculateBase64EscapedLen(int input_len) {
+  return CalculateBase64EscapedLen(input_len, true);
+}
+
+// ----------------------------------------------------------------------
+// int Base64Unescape() - base64 decoder
+// int Base64Escape() - base64 encoder
+// int WebSafeBase64Unescape() - Google's variation of base64 decoder
+// int WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://tools.ietf.org/html/rfc2045 for formal description, but what we
+// care about is that...
+//   Take the encoded stuff in groups of 4 characters and turn each
+//   character into a code 0 to 63 thus:
+//           A-Z map to 0 to 25
+//           a-z map to 26 to 51
+//           0-9 map to 52 to 61
+//           +(- for WebSafe) maps to 62
+//           /(_ for WebSafe) maps to 63
+//   There will be four numbers, all less than 64 which can be represented
+//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+//   Arrange the 6 digit binary numbers into three bytes as such:
+//   aaaaaabb bbbbcccc ccdddddd
+//   Equals signs (one or two) are used at the end of the encoded block to
+//   indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+int Base64UnescapeInternal(const char *src_param, int szsrc,
+                           char *dest, int szdest,
+                           const signed char* unbase64) {
+  static const char kPad64Equals = '=';
+  static const char kPad64Dot = '.';
+
+  int decode = 0;
+  int destidx = 0;
+  int state = 0;
+  unsigned int ch = 0;
+  unsigned int temp = 0;
+
+  // If "char" is signed by default, using *src as an array index results in
+  // accessing negative array elements. Treat the input as a pointer to
+  // unsigned char to avoid this.
+  const unsigned char *src = reinterpret_cast<const unsigned char*>(src_param);
+
+  // The GET_INPUT macro gets the next input character, skipping
+  // over any whitespace, and stopping when we reach the end of the
+  // string or when we read any non-data character.  The arguments are
+  // an arbitrary identifier (used as a label for goto) and the number
+  // of data bytes that must remain in the input to avoid aborting the
+  // loop.
+#define GET_INPUT(label, remain)                 \
+  label:                                         \
+    --szsrc;                                     \
+    ch = *src++;                                 \
+    decode = unbase64[ch];                       \
+    if (decode < 0) {                            \
+      if (ascii_isspace(ch) && szsrc >= remain)  \
+        goto label;                              \
+      state = 4 - remain;                        \
+      break;                                     \
+    }
+
+  // if dest is null, we're just checking to see if it's legal input
+  // rather than producing output.  (I suspect this could just be done
+  // with a regexp...).  We duplicate the loop so this test can be
+  // outside it instead of in every iteration.
+
+  if (dest) {
+    // This loop consumes 4 input bytes and produces 3 output bytes
+    // per iteration.  We can't know at the start that there is enough
+    // data left in the string for a full iteration, so the loop may
+    // break out in the middle; if so 'state' will be set to the
+    // number of input bytes read.
+
+    while (szsrc >= 4)  {
+      // We'll start by optimistically assuming that the next four
+      // bytes of the string (src[0..3]) are four good data bytes
+      // (that is, no nulls, whitespace, padding chars, or illegal
+      // chars).  We need to test src[0..2] for nulls individually
+      // before constructing temp to preserve the property that we
+      // never read past a null in the string (no matter how long
+      // szsrc claims the string is).
+
+      if (!src[0] || !src[1] || !src[2] ||
+          (temp = ((unsigned(unbase64[src[0]]) << 18) |
+                   (unsigned(unbase64[src[1]]) << 12) |
+                   (unsigned(unbase64[src[2]]) << 6) |
+                   (unsigned(unbase64[src[3]])))) & 0x80000000) {
+        // Iff any of those four characters was bad (null, illegal,
+        // whitespace, padding), then temp's high bit will be set
+        // (because unbase64[] is -1 for all bad characters).
+        //
+        // We'll back up and resort to the slower decoder, which knows
+        // how to handle those cases.
+
+        GET_INPUT(first, 4);
+        temp = decode;
+        GET_INPUT(second, 3);
+        temp = (temp << 6) | decode;
+        GET_INPUT(third, 2);
+        temp = (temp << 6) | decode;
+        GET_INPUT(fourth, 1);
+        temp = (temp << 6) | decode;
+      } else {
+        // We really did have four good data bytes, so advance four
+        // characters in the string.
+
+        szsrc -= 4;
+        src += 4;
+        decode = -1;
+        ch = '\0';
+      }
+
+      // temp has 24 bits of input, so write that out as three bytes.
+
+      if (destidx+3 > szdest) return -1;
+      dest[destidx+2] = temp;
+      temp >>= 8;
+      dest[destidx+1] = temp;
+      temp >>= 8;
+      dest[destidx] = temp;
+      destidx += 3;
+    }
+  } else {
+    while (szsrc >= 4)  {
+      if (!src[0] || !src[1] || !src[2] ||
+          (temp = ((unsigned(unbase64[src[0]]) << 18) |
+                   (unsigned(unbase64[src[1]]) << 12) |
+                   (unsigned(unbase64[src[2]]) << 6) |
+                   (unsigned(unbase64[src[3]])))) & 0x80000000) {
+        GET_INPUT(first_no_dest, 4);
+        GET_INPUT(second_no_dest, 3);
+        GET_INPUT(third_no_dest, 2);
+        GET_INPUT(fourth_no_dest, 1);
+      } else {
+        szsrc -= 4;
+        src += 4;
+        decode = -1;
+        ch = '\0';
+      }
+      destidx += 3;
+    }
+  }
+
+#undef GET_INPUT
+
+  // if the loop terminated because we read a bad character, return
+  // now.
+  if (decode < 0 && ch != '\0' &&
+      ch != kPad64Equals && ch != kPad64Dot && !ascii_isspace(ch))
+    return -1;
+
+  if (ch == kPad64Equals || ch == kPad64Dot) {
+    // if we stopped by hitting an '=' or '.', un-read that character -- we'll
+    // look at it again when we count to check for the proper number of
+    // equals signs at the end.
+    ++szsrc;
+    --src;
+  } else {
+    // This loop consumes 1 input byte per iteration.  It's used to
+    // clean up the 0-3 input bytes remaining when the first, faster
+    // loop finishes.  'temp' contains the data from 'state' input
+    // characters read by the first loop.
+    while (szsrc > 0)  {
+      --szsrc;
+      ch = *src++;
+      decode = unbase64[ch];
+      if (decode < 0) {
+        if (ascii_isspace(ch)) {
+          continue;
+        } else if (ch == '\0') {
+          break;
+        } else if (ch == kPad64Equals || ch == kPad64Dot) {
+          // back up one character; we'll read it again when we check
+          // for the correct number of pad characters at the end.
+          ++szsrc;
+          --src;
+          break;
+        } else {
+          return -1;
+        }
+      }
+
+      // Each input character gives us six bits of output.
+      temp = (temp << 6) | decode;
+      ++state;
+      if (state == 4) {
+        // If we've accumulated 24 bits of output, write that out as
+        // three bytes.
+        if (dest) {
+          if (destidx+3 > szdest) return -1;
+          dest[destidx+2] = temp;
+          temp >>= 8;
+          dest[destidx+1] = temp;
+          temp >>= 8;
+          dest[destidx] = temp;
+        }
+        destidx += 3;
+        state = 0;
+        temp = 0;
+      }
+    }
+  }
+
+  // Process the leftover data contained in 'temp' at the end of the input.
+  int expected_equals = 0;
+  switch (state) {
+    case 0:
+      // Nothing left over; output is a multiple of 3 bytes.
+      break;
+
+    case 1:
+      // Bad input; we have 6 bits left over.
+      return -1;
+
+    case 2:
+      // Produce one more output byte from the 12 input bits we have left.
+      if (dest) {
+        if (destidx+1 > szdest) return -1;
+        temp >>= 4;
+        dest[destidx] = temp;
+      }
+      ++destidx;
+      expected_equals = 2;
+      break;
+
+    case 3:
+      // Produce two more output bytes from the 18 input bits we have left.
+      if (dest) {
+        if (destidx+2 > szdest) return -1;
+        temp >>= 2;
+        dest[destidx+1] = temp;
+        temp >>= 8;
+        dest[destidx] = temp;
+      }
+      destidx += 2;
+      expected_equals = 1;
+      break;
+
+    default:
+      // state should have no other values at this point.
+      GOOGLE_LOG(FATAL) << "This can't happen; base64 decoder state = " << state;
+  }
+
+  // The remainder of the string should be all whitespace, mixed with
+  // exactly 0 equals signs, or exactly 'expected_equals' equals
+  // signs.  (Always accepting 0 equals signs is a google extension
+  // not covered in the RFC, as is accepting dot as the pad character.)
+
+  int equals = 0;
+  while (szsrc > 0 && *src) {
+    if (*src == kPad64Equals || *src == kPad64Dot)
+      ++equals;
+    else if (!ascii_isspace(*src))
+      return -1;
+    --szsrc;
+    ++src;
+  }
+
+  return (equals == 0 || equals == expected_equals) ? destidx : -1;
+}
+
+// The arrays below were generated by the following code
+// #include <sys/time.h>
+// #include <stdlib.h>
+// #include <string.h>
+// #include <stdio.h>
+// main()
+// {
+//   static const char Base64[] =
+//     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+//   const char *pos;
+//   int idx, i, j;
+//   printf("    ");
+//   for (i = 0; i < 255; i += 8) {
+//     for (j = i; j < i + 8; j++) {
+//       pos = strchr(Base64, j);
+//       if ((pos == nullptr) || (j == 0))
+//         idx = -1;
+//       else
+//         idx = pos - Base64;
+//       if (idx == -1)
+//         printf(" %2d,     ", idx);
+//       else
+//         printf(" %2d/""*%c*""/,", idx, j);
+//     }
+//     printf("\n    ");
+//   }
+// }
+//
+// where the value of "Base64[]" was replaced by one of the base-64 conversion
+// tables from the functions below.
+static const signed char kUnBase64[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+   7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+static const signed char kUnWebSafeBase64[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      62/*-*/, -1,      -1,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+   7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      63/*_*/,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+  return Base64UnescapeInternal(src, szsrc, dest, szdest, kUnWebSafeBase64);
+}
+
+static bool Base64UnescapeInternal(const char *src, int slen, std::string *dest,
+                                   const signed char *unbase64) {
+  // Determine the size of the output string.  Base64 encodes every 3 bytes into
+  // 4 characters.  any leftover chars are added directly for good measure.
+  // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
+  const int dest_len = 3 * (slen / 4) + (slen % 4);
+
+  dest->resize(dest_len);
+
+  // We are getting the destination buffer by getting the beginning of the
+  // string and converting it into a char *.
+  const int len = Base64UnescapeInternal(src, slen, string_as_array(dest),
+                                         dest_len, unbase64);
+  if (len < 0) {
+    dest->clear();
+    return false;
+  }
+
+  // could be shorter if there was padding
+  GOOGLE_DCHECK_LE(len, dest_len);
+  dest->erase(len);
+
+  return true;
+}
+
+bool Base64Unescape(StringPiece src, std::string *dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
+}
+
+bool WebSafeBase64Unescape(StringPiece src, std::string *dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
+}
+
+int Base64EscapeInternal(const unsigned char *src, int szsrc,
+                         char *dest, int szdest, const char *base64,
+                         bool do_padding) {
+  static const char kPad64 = '=';
+
+  if (szsrc <= 0) return 0;
+
+  if (szsrc * 4 > szdest * 3) return 0;
+
+  char *cur_dest = dest;
+  const unsigned char *cur_src = src;
+
+  char *limit_dest = dest + szdest;
+  const unsigned char *limit_src = src + szsrc;
+
+  // Three bytes of data encodes to four characters of ciphertext.
+  // So we can pump through three-byte chunks atomically.
+  while (cur_src < limit_src - 3) {  // keep going as long as we have >= 32 bits
+    uint32_t in = BigEndian::Load32(cur_src) >> 8;
+
+    cur_dest[0] = base64[in >> 18];
+    in &= 0x3FFFF;
+    cur_dest[1] = base64[in >> 12];
+    in &= 0xFFF;
+    cur_dest[2] = base64[in >> 6];
+    in &= 0x3F;
+    cur_dest[3] = base64[in];
+
+    cur_dest += 4;
+    cur_src += 3;
+  }
+  // To save time, we didn't update szdest or szsrc in the loop.  So do it now.
+  szdest = limit_dest - cur_dest;
+  szsrc = limit_src - cur_src;
+
+  /* now deal with the tail (<=3 bytes) */
+  switch (szsrc) {
+    case 0:
+      // Nothing left; nothing more to do.
+      break;
+    case 1: {
+      // One byte left: this encodes to two characters, and (optionally)
+      // two pad characters to round out the four-character cipherblock.
+      if ((szdest -= 2) < 0) return 0;
+      uint32_t in = cur_src[0];
+      cur_dest[0] = base64[in >> 2];
+      in &= 0x3;
+      cur_dest[1] = base64[in << 4];
+      cur_dest += 2;
+      if (do_padding) {
+        if ((szdest -= 2) < 0) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest[1] = kPad64;
+        cur_dest += 2;
+      }
+      break;
+    }
+    case 2: {
+      // Two bytes left: this encodes to three characters, and (optionally)
+      // one pad character to round out the four-character cipherblock.
+      if ((szdest -= 3) < 0) return 0;
+      uint32_t in = BigEndian::Load16(cur_src);
+      cur_dest[0] = base64[in >> 10];
+      in &= 0x3FF;
+      cur_dest[1] = base64[in >> 4];
+      in &= 0x00F;
+      cur_dest[2] = base64[in << 2];
+      cur_dest += 3;
+      if (do_padding) {
+        if ((szdest -= 1) < 0) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest += 1;
+      }
+      break;
+    }
+    case 3: {
+      // Three bytes left: same as in the big loop above.  We can't do this in
+      // the loop because the loop above always reads 4 bytes, and the fourth
+      // byte is past the end of the input.
+      if ((szdest -= 4) < 0) return 0;
+      uint32_t in = (cur_src[0] << 16) + BigEndian::Load16(cur_src + 1);
+      cur_dest[0] = base64[in >> 18];
+      in &= 0x3FFFF;
+      cur_dest[1] = base64[in >> 12];
+      in &= 0xFFF;
+      cur_dest[2] = base64[in >> 6];
+      in &= 0x3F;
+      cur_dest[3] = base64[in];
+      cur_dest += 4;
+      break;
+    }
+    default:
+      // Should not be reached: blocks of 4 bytes are handled
+      // in the while loop before this switch statement.
+      GOOGLE_LOG(FATAL) << "Logic problem? szsrc = " << szsrc;
+      break;
+  }
+  return (cur_dest - dest);
+}
+
+static const char kBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const char kWebSafeBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
+  return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
+}
+int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
+                        int szdest, bool do_padding) {
+  return Base64EscapeInternal(src, szsrc, dest, szdest,
+                              kWebSafeBase64Chars, do_padding);
+}
+
+void Base64EscapeInternal(const unsigned char *src, int szsrc,
+                          std::string *dest, bool do_padding,
+                          const char *base64_chars) {
+  const int calc_escaped_size =
+    CalculateBase64EscapedLen(szsrc, do_padding);
+  dest->resize(calc_escaped_size);
+  const int escaped_len = Base64EscapeInternal(src, szsrc,
+                                               string_as_array(dest),
+                                               dest->size(),
+                                               base64_chars,
+                                               do_padding);
+  GOOGLE_DCHECK_EQ(calc_escaped_size, escaped_len);
+  dest->erase(escaped_len);
+}
+
+void Base64Escape(const unsigned char *src, int szsrc, std::string *dest,
+                  bool do_padding) {
+  Base64EscapeInternal(src, szsrc, dest, do_padding, kBase64Chars);
+}
+
+void WebSafeBase64Escape(const unsigned char *src, int szsrc, std::string *dest,
+                         bool do_padding) {
+  Base64EscapeInternal(src, szsrc, dest, do_padding, kWebSafeBase64Chars);
+}
+
+void Base64Escape(StringPiece src, std::string *dest) {
+  Base64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+               src.size(), dest, true);
+}
+
+void WebSafeBase64Escape(StringPiece src, std::string *dest) {
+  WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+                      src.size(), dest, false);
+}
+
+void WebSafeBase64EscapeWithPadding(StringPiece src, std::string *dest) {
+  WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+                      src.size(), dest, true);
+}
+
+// Helper to append a Unicode code point to a string as UTF8, without bringing
+// in any external dependencies.
+int EncodeAsUTF8Char(uint32_t code_point, char* output) {
+  uint32_t tmp = 0;
+  int len = 0;
+  if (code_point <= 0x7f) {
+    tmp = code_point;
+    len = 1;
+  } else if (code_point <= 0x07ff) {
+    tmp = 0x0000c080 |
+        ((code_point & 0x07c0) << 2) |
+        (code_point & 0x003f);
+    len = 2;
+  } else if (code_point <= 0xffff) {
+    tmp = 0x00e08080 |
+        ((code_point & 0xf000) << 4) |
+        ((code_point & 0x0fc0) << 2) |
+        (code_point & 0x003f);
+    len = 3;
+  } else {
+    // UTF-16 is only defined for code points up to 0x10FFFF, and UTF-8 is
+    // normally only defined up to there as well.
+    tmp = 0xf0808080 |
+        ((code_point & 0x1c0000) << 6) |
+        ((code_point & 0x03f000) << 4) |
+        ((code_point & 0x000fc0) << 2) |
+        (code_point & 0x003f);
+    len = 4;
+  }
+  tmp = ghtonl(tmp);
+  memcpy(output, reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+  return len;
+}
+
+// Table of UTF-8 character lengths, based on first byte
+static const unsigned char kUTF8LenTbl[256] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+
+// Return length of a single UTF-8 source character
+int UTF8FirstLetterNumBytes(const char* src, int len) {
+  if (len == 0) {
+    return 0;
+  }
+  return kUTF8LenTbl[*reinterpret_cast<const uint8_t*>(src)];
+}
+
+// ----------------------------------------------------------------------
+// CleanStringLineEndings()
+//   Clean up a multi-line string to conform to Unix line endings.
+//   Reads from src and appends to dst, so usually dst should be empty.
+//
+//   If there is no line ending at the end of a non-empty string, it can
+//   be added automatically.
+//
+//   Four different types of input are correctly handled:
+//
+//     - Unix/Linux files: line ending is LF: pass through unchanged
+//
+//     - DOS/Windows files: line ending is CRLF: convert to LF
+//
+//     - Legacy Mac files: line ending is CR: convert to LF
+//
+//     - Garbled files: random line endings: convert gracefully
+//                      lonely CR, lonely LF, CRLF: convert to LF
+//
+//   @param src The multi-line string to convert
+//   @param dst The converted string is appended to this string
+//   @param auto_end_last_line Automatically terminate the last line
+//
+//   Limitations:
+//
+//     This does not do the right thing for CRCRLF files created by
+//     broken programs that do another Unix->DOS conversion on files
+//     that are already in CRLF format.  For this, a two-pass approach
+//     brute-force would be needed that
+//
+//       (1) determines the presence of LF (first one is ok)
+//       (2) if yes, removes any CR, else convert every CR to LF
+
+void CleanStringLineEndings(const std::string &src, std::string *dst,
+                            bool auto_end_last_line) {
+  if (dst->empty()) {
+    dst->append(src);
+    CleanStringLineEndings(dst, auto_end_last_line);
+  } else {
+    std::string tmp = src;
+    CleanStringLineEndings(&tmp, auto_end_last_line);
+    dst->append(tmp);
+  }
+}
+
+void CleanStringLineEndings(std::string *str, bool auto_end_last_line) {
+  ptrdiff_t output_pos = 0;
+  bool r_seen = false;
+  ptrdiff_t len = str->size();
+
+  char *p = &(*str)[0];
+
+  for (ptrdiff_t input_pos = 0; input_pos < len;) {
+    if (!r_seen && input_pos + 8 < len) {
+      uint64_t v = GOOGLE_UNALIGNED_LOAD64(p + input_pos);
+      // Loop over groups of 8 bytes at a time until we come across
+      // a word that has a byte whose value is less than or equal to
+      // '\r' (i.e. could contain a \n (0x0a) or a \r (0x0d) ).
+      //
+      // We use a has_less macro that quickly tests a whole 64-bit
+      // word to see if any of the bytes has a value < N.
+      //
+      // For more details, see:
+      //   http://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
+#define has_less(x, n) (((x) - ~0ULL / 255 * (n)) & ~(x) & ~0ULL / 255 * 128)
+      if (!has_less(v, '\r' + 1)) {
+#undef has_less
+        // No byte in this word has a value that could be a \r or a \n
+        if (output_pos != input_pos) {
+          GOOGLE_UNALIGNED_STORE64(p + output_pos, v);
+        }
+        input_pos += 8;
+        output_pos += 8;
+        continue;
+      }
+    }
+    std::string::const_reference in = p[input_pos];
+    if (in == '\r') {
+      if (r_seen) p[output_pos++] = '\n';
+      r_seen = true;
+    } else if (in == '\n') {
+      if (input_pos != output_pos)
+        p[output_pos++] = '\n';
+      else
+        output_pos++;
+      r_seen = false;
+    } else {
+      if (r_seen) p[output_pos++] = '\n';
+      r_seen = false;
+      if (input_pos != output_pos)
+        p[output_pos++] = in;
+      else
+        output_pos++;
+    }
+    input_pos++;
+  }
+  if (r_seen ||
+      (auto_end_last_line && output_pos > 0 && p[output_pos - 1] != '\n')) {
+    str->resize(output_pos + 1);
+    str->operator[](output_pos) = '\n';
+  } else if (output_pos < len) {
+    str->resize(output_pos);
+  }
+}
+
+namespace internal {
+
+// ----------------------------------------------------------------------
+// NoLocaleStrtod()
+//   This code will make you cry.
+// ----------------------------------------------------------------------
+
+namespace {
+
+// Returns a string identical to *input except that the character pointed to
+// by radix_pos (which should be '.') is replaced with the locale-specific
+// radix character.
+std::string LocalizeRadix(const char *input, const char *radix_pos) {
+  // Determine the locale-specific radix character by calling sprintf() to
+  // print the number 1.5, then stripping off the digits.  As far as I can
+  // tell, this is the only portable, thread-safe way to get the C library
+  // to divuldge the locale's radix character.  No, localeconv() is NOT
+  // thread-safe.
+  char temp[16];
+  int size = snprintf(temp, sizeof(temp), "%.1f", 1.5);
+  GOOGLE_CHECK_EQ(temp[0], '1');
+  GOOGLE_CHECK_EQ(temp[size - 1], '5');
+  GOOGLE_CHECK_LE(size, 6);
+
+  // Now replace the '.' in the input with it.
+  std::string result;
+  result.reserve(strlen(input) + size - 3);
+  result.append(input, radix_pos);
+  result.append(temp + 1, size - 2);
+  result.append(radix_pos + 1);
+  return result;
+}
+
+}  // namespace
+
+double NoLocaleStrtod(const char *str, char **endptr) {
+  // We cannot simply set the locale to "C" temporarily with setlocale()
+  // as this is not thread-safe.  Instead, we try to parse in the current
+  // locale first.  If parsing stops at a '.' character, then this is a
+  // pretty good hint that we're actually in some other locale in which
+  // '.' is not the radix character.
+
+  char *temp_endptr;
+  double result = strtod(str, &temp_endptr);
+  if (endptr != NULL) *endptr = temp_endptr;
+  if (*temp_endptr != '.') return result;
+
+  // Parsing halted on a '.'.  Perhaps we're in a different locale?  Let's
+  // try to replace the '.' with a locale-specific radix character and
+  // try again.
+  std::string localized = LocalizeRadix(str, temp_endptr);
+  const char *localized_cstr = localized.c_str();
+  char *localized_endptr;
+  result = strtod(localized_cstr, &localized_endptr);
+  if ((localized_endptr - localized_cstr) > (temp_endptr - str)) {
+    // This attempt got further, so replacing the decimal must have helped.
+    // Update endptr to point at the right location.
+    if (endptr != NULL) {
+      // size_diff is non-zero if the localized radix has multiple bytes.
+      int size_diff = localized.size() - strlen(str);
+      // const_cast is necessary to match the strtod() interface.
+      *endptr = const_cast<char *>(
+          str + (localized_endptr - localized_cstr - size_diff));
+    }
+  }
+
+  return result;
+}
+
+}  // namespace internal
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/substitute.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/substitute.cpp
new file mode 100644
index 0000000..8c75b25
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/substitute.cpp
@@ -0,0 +1,136 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+using internal::SubstituteArg;
+
+// Returns the number of args in arg_array which were passed explicitly
+// to Substitute().
+static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
+  int count = 0;
+  while (args_array[count] != nullptr && args_array[count]->size() != -1) {
+    ++count;
+  }
+  return count;
+}
+
+std::string Substitute(const std::string& format, const SubstituteArg& arg0,
+                       const SubstituteArg& arg1, const SubstituteArg& arg2,
+                       const SubstituteArg& arg3, const SubstituteArg& arg4,
+                       const SubstituteArg& arg5, const SubstituteArg& arg6,
+                       const SubstituteArg& arg7, const SubstituteArg& arg8,
+                       const SubstituteArg& arg9) {
+  std::string result;
+  SubstituteAndAppend(&result, format.c_str(), arg0, arg1, arg2, arg3, arg4,
+                      arg5, arg6, arg7, arg8, arg9);
+  return result;
+}
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const SubstituteArg& arg0, const SubstituteArg& arg1,
+                         const SubstituteArg& arg2, const SubstituteArg& arg3,
+                         const SubstituteArg& arg4, const SubstituteArg& arg5,
+                         const SubstituteArg& arg6, const SubstituteArg& arg7,
+                         const SubstituteArg& arg8, const SubstituteArg& arg9) {
+  const SubstituteArg* const args_array[] = {
+    &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, nullptr
+  };
+
+  // Determine total size needed.
+  int size = 0;
+  for (int i = 0; format[i] != '\0'; i++) {
+    if (format[i] == '$') {
+      if (ascii_isdigit(format[i+1])) {
+        int index = format[i+1] - '0';
+        if (args_array[index]->size() == -1) {
+          GOOGLE_LOG(DFATAL)
+            << "strings::Substitute format string invalid: asked for \"$"
+            << index << "\", but only " << CountSubstituteArgs(args_array)
+            << " args were given.  Full format string was: \""
+            << CEscape(format) << "\".";
+          return;
+        }
+        size += args_array[index]->size();
+        ++i;  // Skip next char.
+      } else if (format[i+1] == '$') {
+        ++size;
+        ++i;  // Skip next char.
+      } else {
+        GOOGLE_LOG(DFATAL)
+          << "Invalid strings::Substitute() format string: \""
+          << CEscape(format) << "\".";
+        return;
+      }
+    } else {
+      ++size;
+    }
+  }
+
+  if (size == 0) return;
+
+  // Build the string.
+  int original_size = output->size();
+  STLStringResizeUninitialized(output, original_size + size);
+  char* target = string_as_array(output) + original_size;
+  for (int i = 0; format[i] != '\0'; i++) {
+    if (format[i] == '$') {
+      if (ascii_isdigit(format[i+1])) {
+        unsigned int index = format[i+1] - '0';
+        assert(index < 10);
+        const SubstituteArg* src = args_array[index];
+        memcpy(target, src->data(), src->size());
+        target += src->size();
+        ++i;  // Skip next char.
+      } else if (format[i+1] == '$') {
+        *target++ = '$';
+        ++i;  // Skip next char.
+      }
+    } else {
+      *target++ = format[i];
+    }
+  }
+
+  GOOGLE_DCHECK_EQ(target - output->data(), static_cast<int>(output->size()));
+}
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/time.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/time.cpp
new file mode 100644
index 0000000..692cb82
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/stubs/time.cpp
@@ -0,0 +1,365 @@
+#include <google/protobuf/stubs/time.h>
+
+#include <ctime>
+
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+static const int64_t kSecondsPerMinute = 60;
+static const int64_t kSecondsPerHour = 3600;
+static const int64_t kSecondsPerDay = kSecondsPerHour * 24;
+static const int64_t kSecondsPer400Years =
+    kSecondsPerDay * (400 * 365 + 400 / 4 - 3);
+// Seconds from 0001-01-01T00:00:00 to 1970-01-01T:00:00:00
+static const int64_t kSecondsFromEraToEpoch = 62135596800LL;
+// The range of timestamp values we support.
+static const int64_t kMinTime = -62135596800LL;  // 0001-01-01T00:00:00
+static const int64_t kMaxTime = 253402300799LL;  // 9999-12-31T23:59:59
+
+static const int kNanosPerMillisecond = 1000000;
+static const int kNanosPerMicrosecond = 1000;
+
+// Count the seconds from the given year (start at Jan 1, 00:00) to 100 years
+// after.
+int64_t SecondsPer100Years(int year) {
+  if (year % 400 == 0 || year % 400 > 300) {
+    return kSecondsPerDay * (100 * 365 + 100 / 4);
+  } else {
+    return kSecondsPerDay * (100 * 365 + 100 / 4 - 1);
+  }
+}
+
+// Count the seconds from the given year (start at Jan 1, 00:00) to 4 years
+// after.
+int64_t SecondsPer4Years(int year) {
+  if ((year % 100 == 0 || year % 100 > 96) &&
+      !(year % 400 == 0 || year % 400 > 396)) {
+    // No leap years.
+    return kSecondsPerDay * (4 * 365);
+  } else {
+    // One leap years.
+    return kSecondsPerDay * (4 * 365 + 1);
+  }
+}
+
+bool IsLeapYear(int year) {
+  return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
+}
+
+int64_t SecondsPerYear(int year) {
+  return kSecondsPerDay * (IsLeapYear(year) ? 366 : 365);
+}
+
+static const int kDaysInMonth[13] = {
+  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+int64_t SecondsPerMonth(int month, bool leap) {
+  if (month == 2 && leap) {
+    return kSecondsPerDay * (kDaysInMonth[month] + 1);
+  }
+  return kSecondsPerDay * kDaysInMonth[month];
+}
+
+static const int kDaysSinceJan[13] = {
+  0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+};
+
+bool ValidateDateTime(const DateTime& time) {
+  if (time.year < 1 || time.year > 9999 ||
+      time.month < 1 || time.month > 12 ||
+      time.day < 1 || time.day > 31 ||
+      time.hour < 0 || time.hour > 23 ||
+      time.minute < 0 || time.minute > 59 ||
+      time.second < 0 || time.second > 59) {
+    return false;
+  }
+  if (time.month == 2 && IsLeapYear(time.year)) {
+    return time.day <= kDaysInMonth[time.month] + 1;
+  } else {
+    return time.day <= kDaysInMonth[time.month];
+  }
+}
+
+// Count the number of seconds elapsed from 0001-01-01T00:00:00 to the given
+// time.
+int64_t SecondsSinceCommonEra(const DateTime& time) {
+  int64_t result = 0;
+  // Years should be between 1 and 9999.
+  assert(time.year >= 1 && time.year <= 9999);
+  int year = 1;
+  if ((time.year - year) >= 400) {
+    int count_400years = (time.year - year) / 400;
+    result += kSecondsPer400Years * count_400years;
+    year += count_400years * 400;
+  }
+  while ((time.year - year) >= 100) {
+    result += SecondsPer100Years(year);
+    year += 100;
+  }
+  while ((time.year - year) >= 4) {
+    result += SecondsPer4Years(year);
+    year += 4;
+  }
+  while (time.year > year) {
+    result += SecondsPerYear(year);
+    ++year;
+  }
+  // Months should be between 1 and 12.
+  assert(time.month >= 1 && time.month <= 12);
+  int month = time.month;
+  result += kSecondsPerDay * kDaysSinceJan[month];
+  if (month > 2 && IsLeapYear(year)) {
+    result += kSecondsPerDay;
+  }
+  assert(time.day >= 1 &&
+         time.day <= (month == 2 && IsLeapYear(year)
+                          ? kDaysInMonth[month] + 1
+                          : kDaysInMonth[month]));
+  result += kSecondsPerDay * (time.day - 1);
+  result += kSecondsPerHour * time.hour +
+      kSecondsPerMinute * time.minute +
+      time.second;
+  return result;
+}
+
+// Format nanoseconds with either 3, 6, or 9 digits depending on the required
+// precision to represent the exact value.
+std::string FormatNanos(int32_t nanos) {
+  if (nanos % kNanosPerMillisecond == 0) {
+    return StringPrintf("%03d", nanos / kNanosPerMillisecond);
+  } else if (nanos % kNanosPerMicrosecond == 0) {
+    return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
+  } else {
+    return StringPrintf("%09d", nanos);
+  }
+}
+
+// Parses an integer from a null-terminated char sequence. The method
+// consumes at most "width" chars. Returns a pointer after the consumed
+// integer, or nullptr if the data does not start with an integer or the
+// integer value does not fall in the range of [min_value, max_value].
+const char* ParseInt(const char* data, int width, int min_value,
+                     int max_value, int* result) {
+  if (!ascii_isdigit(*data)) {
+    return nullptr;
+  }
+  int value = 0;
+  for (int i = 0; i < width; ++i, ++data) {
+    if (ascii_isdigit(*data)) {
+      value = value * 10 + (*data - '0');
+    } else {
+      break;
+    }
+  }
+  if (value >= min_value && value <= max_value) {
+    *result = value;
+    return data;
+  } else {
+    return nullptr;
+  }
+}
+
+// Consumes the fractional parts of a second into nanos. For example,
+// "010" will be parsed to 10000000 nanos.
+const char* ParseNanos(const char* data, int32_t* nanos) {
+  if (!ascii_isdigit(*data)) {
+    return nullptr;
+  }
+  int value = 0;
+  int len = 0;
+  // Consume as many digits as there are but only take the first 9 into
+  // account.
+  while (ascii_isdigit(*data)) {
+    if (len < 9) {
+      value = value * 10 + *data - '0';
+    }
+    ++len;
+    ++data;
+  }
+  while (len < 9) {
+    value = value * 10;
+    ++len;
+  }
+  *nanos = value;
+  return data;
+}
+
+const char* ParseTimezoneOffset(const char* data, int64_t* offset) {
+  // Accept format "HH:MM". E.g., "08:00"
+  int hour;
+  if ((data = ParseInt(data, 2, 0, 23, &hour)) == nullptr) {
+    return nullptr;
+  }
+  if (*data++ != ':') {
+    return nullptr;
+  }
+  int minute;
+  if ((data = ParseInt(data, 2, 0, 59, &minute)) == nullptr) {
+    return nullptr;
+  }
+  *offset = (hour * 60 + minute) * 60;
+  return data;
+}
+}  // namespace
+
+bool SecondsToDateTime(int64_t seconds, DateTime* time) {
+  if (seconds < kMinTime || seconds > kMaxTime) {
+    return false;
+  }
+  // It's easier to calculate the DateTime starting from 0001-01-01T00:00:00
+  seconds = seconds + kSecondsFromEraToEpoch;
+  int year = 1;
+  if (seconds >= kSecondsPer400Years) {
+    int count_400years = seconds / kSecondsPer400Years;
+    year += 400 * count_400years;
+    seconds %= kSecondsPer400Years;
+  }
+  while (seconds >= SecondsPer100Years(year)) {
+    seconds -= SecondsPer100Years(year);
+    year += 100;
+  }
+  while (seconds >= SecondsPer4Years(year)) {
+    seconds -= SecondsPer4Years(year);
+    year += 4;
+  }
+  while (seconds >= SecondsPerYear(year)) {
+    seconds -= SecondsPerYear(year);
+    year += 1;
+  }
+  bool leap = IsLeapYear(year);
+  int month = 1;
+  while (seconds >= SecondsPerMonth(month, leap)) {
+    seconds -= SecondsPerMonth(month, leap);
+    ++month;
+  }
+  int day = 1 + seconds / kSecondsPerDay;
+  seconds %= kSecondsPerDay;
+  int hour = seconds / kSecondsPerHour;
+  seconds %= kSecondsPerHour;
+  int minute = seconds / kSecondsPerMinute;
+  seconds %= kSecondsPerMinute;
+  time->year = year;
+  time->month = month;
+  time->day = day;
+  time->hour = hour;
+  time->minute = minute;
+  time->second = static_cast<int>(seconds);
+  return true;
+}
+
+bool DateTimeToSeconds(const DateTime& time, int64_t* seconds) {
+  if (!ValidateDateTime(time)) {
+    return false;
+  }
+  *seconds = SecondsSinceCommonEra(time) - kSecondsFromEraToEpoch;
+  return true;
+}
+
+void GetCurrentTime(int64_t* seconds, int32_t* nanos) {
+  // TODO(xiaofeng): Improve the accuracy of this implementation (or just
+  // remove this method from protobuf).
+  *seconds = time(nullptr);
+  *nanos = 0;
+}
+
+std::string FormatTime(int64_t seconds, int32_t nanos) {
+  DateTime time;
+  if (nanos < 0 || nanos > 999999999 || !SecondsToDateTime(seconds, &time)) {
+    return "InvalidTime";
+  }
+  std::string result =
+      StringPrintf("%04d-%02d-%02dT%02d:%02d:%02d", time.year, time.month,
+                   time.day, time.hour, time.minute, time.second);
+  if (nanos != 0) {
+    result += "." + FormatNanos(nanos);
+  }
+  return result + "Z";
+}
+
+bool ParseTime(const std::string& value, int64_t* seconds, int32_t* nanos) {
+  DateTime time;
+  const char* data = value.c_str();
+  // We only accept:
+  //   Z-normalized: 2015-05-20T13:29:35.120Z
+  //   With UTC offset: 2015-05-20T13:29:35.120-08:00
+
+  // Parse year
+  if ((data = ParseInt(data, 4, 1, 9999, &time.year)) == nullptr) {
+    return false;
+  }
+  // Expect '-'
+  if (*data++ != '-') return false;
+  // Parse month
+  if ((data = ParseInt(data, 2, 1, 12, &time.month)) == nullptr) {
+    return false;
+  }
+  // Expect '-'
+  if (*data++ != '-') return false;
+  // Parse day
+  if ((data = ParseInt(data, 2, 1, 31, &time.day)) == nullptr) {
+    return false;
+  }
+  // Expect 'T'
+  if (*data++ != 'T') return false;
+  // Parse hour
+  if ((data = ParseInt(data, 2, 0, 23, &time.hour)) == nullptr) {
+    return false;
+  }
+  // Expect ':'
+  if (*data++ != ':') return false;
+  // Parse minute
+  if ((data = ParseInt(data, 2, 0, 59, &time.minute)) == nullptr) {
+    return false;
+  }
+  // Expect ':'
+  if (*data++ != ':') return false;
+  // Parse second
+  if ((data = ParseInt(data, 2, 0, 59, &time.second)) == nullptr) {
+    return false;
+  }
+  if (!DateTimeToSeconds(time, seconds)) {
+    return false;
+  }
+  // Parse nanoseconds.
+  if (*data == '.') {
+    ++data;
+    // Parse nanoseconds.
+    if ((data = ParseNanos(data, nanos)) == nullptr) {
+      return false;
+    }
+  } else {
+    *nanos = 0;
+  }
+  // Parse UTC offsets.
+  if (*data == 'Z') {
+    ++data;
+  } else if (*data == '+') {
+    ++data;
+    int64_t offset;
+    if ((data = ParseTimezoneOffset(data, &offset)) == nullptr) {
+      return false;
+    }
+    *seconds -= offset;
+  } else if (*data == '-') {
+    ++data;
+    int64_t offset;
+    if ((data = ParseTimezoneOffset(data, &offset)) == nullptr) {
+      return false;
+    }
+    *seconds += offset;
+  } else {
+    return false;
+  }
+  // Done with parsing.
+  return *data == 0;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/text_format.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/text_format.cpp
new file mode 100644
index 0000000..05987d3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/text_format.cpp
@@ -0,0 +1,2746 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/text_format.h>
+
+#include <float.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <atomic>
+#include <climits>
+#include <cmath>
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+inline bool IsHexNumber(const std::string& str) {
+  return (str.length() >= 2 && str[0] == '0' &&
+          (str[1] == 'x' || str[1] == 'X'));
+}
+
+inline bool IsOctNumber(const std::string& str) {
+  return (str.length() >= 2 && str[0] == '0' &&
+          (str[1] >= '0' && str[1] < '8'));
+}
+
+}  // namespace
+
+namespace internal {
+const char kDebugStringSilentMarker[] = "";
+const char kDebugStringSilentMarkerForDetection[] = "\t ";
+
+// Controls insertion of kDebugStringSilentMarker.
+PROTOBUF_EXPORT std::atomic<bool> enable_debug_text_format_marker;
+}  // namespace internal
+
+std::string Message::DebugString() const {
+  std::string debug_string;
+
+  TextFormat::Printer printer;
+  printer.SetExpandAny(true);
+  printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load(
+      std::memory_order_relaxed));
+
+  printer.PrintToString(*this, &debug_string);
+
+  return debug_string;
+}
+
+std::string Message::ShortDebugString() const {
+  std::string debug_string;
+
+  TextFormat::Printer printer;
+  printer.SetSingleLineMode(true);
+  printer.SetExpandAny(true);
+  printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load(
+      std::memory_order_relaxed));
+
+  printer.PrintToString(*this, &debug_string);
+  // Single line mode currently might have an extra space at the end.
+  if (!debug_string.empty() && debug_string[debug_string.size() - 1] == ' ') {
+    debug_string.resize(debug_string.size() - 1);
+  }
+
+  return debug_string;
+}
+
+std::string Message::Utf8DebugString() const {
+  std::string debug_string;
+
+  TextFormat::Printer printer;
+  printer.SetUseUtf8StringEscaping(true);
+  printer.SetExpandAny(true);
+  printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load(
+      std::memory_order_relaxed));
+
+  printer.PrintToString(*this, &debug_string);
+
+  return debug_string;
+}
+
+void Message::PrintDebugString() const { printf("%s", DebugString().c_str()); }
+
+
+// ===========================================================================
+// Implementation of the parse information tree class.
+void TextFormat::ParseInfoTree::RecordLocation(
+    const FieldDescriptor* field, TextFormat::ParseLocationRange range) {
+  locations_[field].push_back(range);
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
+    const FieldDescriptor* field) {
+  // Owned by us in the map.
+  auto& vec = nested_[field];
+  vec.emplace_back(new TextFormat::ParseInfoTree());
+  return vec.back().get();
+}
+
+void CheckFieldIndex(const FieldDescriptor* field, int index) {
+  if (field == nullptr) {
+    return;
+  }
+
+  if (field->is_repeated() && index == -1) {
+    GOOGLE_LOG(DFATAL) << "Index must be in range of repeated field values. "
+                << "Field: " << field->name();
+  } else if (!field->is_repeated() && index != -1) {
+    GOOGLE_LOG(DFATAL) << "Index must be -1 for singular fields."
+                << "Field: " << field->name();
+  }
+}
+
+TextFormat::ParseLocationRange TextFormat::ParseInfoTree::GetLocationRange(
+    const FieldDescriptor* field, int index) const {
+  CheckFieldIndex(field, index);
+  if (index == -1) {
+    index = 0;
+  }
+
+  const std::vector<TextFormat::ParseLocationRange>* locations =
+      FindOrNull(locations_, field);
+  if (locations == nullptr ||
+      index >= static_cast<int64_t>(locations->size())) {
+    return TextFormat::ParseLocationRange();
+  }
+
+  return (*locations)[index];
+}
+
+TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
+    const FieldDescriptor* field, int index) const {
+  CheckFieldIndex(field, index);
+  if (index == -1) {
+    index = 0;
+  }
+
+  auto it = nested_.find(field);
+  if (it == nested_.end() || index >= static_cast<int64_t>(it->second.size())) {
+    return nullptr;
+  }
+
+  return it->second[index].get();
+}
+
+namespace {
+// These functions implement the behavior of the "default" TextFormat::Finder,
+// they are defined as standalone to be called when finder_ is nullptr.
+const FieldDescriptor* DefaultFinderFindExtension(Message* message,
+                                                  const std::string& name) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  return descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
+                                                                  name);
+}
+
+const FieldDescriptor* DefaultFinderFindExtensionByNumber(
+    const Descriptor* descriptor, int number) {
+  return descriptor->file()->pool()->FindExtensionByNumber(descriptor, number);
+}
+
+const Descriptor* DefaultFinderFindAnyType(const Message& message,
+                                           const std::string& prefix,
+                                           const std::string& name) {
+  if (prefix != internal::kTypeGoogleApisComPrefix &&
+      prefix != internal::kTypeGoogleProdComPrefix) {
+    return nullptr;
+  }
+  return message.GetDescriptor()->file()->pool()->FindMessageTypeByName(name);
+}
+}  // namespace
+
+// ===========================================================================
+// Internal class for parsing an ASCII representation of a Protocol Message.
+// This class makes use of the Protocol Message compiler's tokenizer found
+// in //net/proto2/io/public/tokenizer.h. Note that class's Parse
+// method is *not* thread-safe and should only be used in a single thread at
+// a time.
+
+// Makes code slightly more readable.  The meaning of "DO(foo)" is
+// "Execute foo and fail if it fails.", where failure is indicated by
+// returning false. Borrowed from parser.cc (Thanks Kenton!).
+#define DO(STATEMENT) \
+  if (STATEMENT) {    \
+  } else {            \
+    return false;     \
+  }
+
+class TextFormat::Parser::ParserImpl {
+ public:
+  // Determines if repeated values for non-repeated fields and
+  // oneofs are permitted, e.g., the string "foo: 1 foo: 2" for a
+  // required/optional field named "foo", or "baz: 1 bar: 2"
+  // where "baz" and "bar" are members of the same oneof.
+  enum SingularOverwritePolicy {
+    ALLOW_SINGULAR_OVERWRITES = 0,   // the last value is retained
+    FORBID_SINGULAR_OVERWRITES = 1,  // an error is issued
+  };
+
+  ParserImpl(const Descriptor* root_message_type,
+             io::ZeroCopyInputStream* input_stream,
+             io::ErrorCollector* error_collector,
+             const TextFormat::Finder* finder, ParseInfoTree* parse_info_tree,
+             SingularOverwritePolicy singular_overwrite_policy,
+             bool allow_case_insensitive_field, bool allow_unknown_field,
+             bool allow_unknown_extension, bool allow_unknown_enum,
+             bool allow_field_number, bool allow_relaxed_whitespace,
+             bool allow_partial, int recursion_limit)
+      : error_collector_(error_collector),
+        finder_(finder),
+        parse_info_tree_(parse_info_tree),
+        tokenizer_error_collector_(this),
+        tokenizer_(input_stream, &tokenizer_error_collector_),
+        root_message_type_(root_message_type),
+        singular_overwrite_policy_(singular_overwrite_policy),
+        allow_case_insensitive_field_(allow_case_insensitive_field),
+        allow_unknown_field_(allow_unknown_field),
+        allow_unknown_extension_(allow_unknown_extension),
+        allow_unknown_enum_(allow_unknown_enum),
+        allow_field_number_(allow_field_number),
+        allow_partial_(allow_partial),
+        initial_recursion_limit_(recursion_limit),
+        recursion_limit_(recursion_limit),
+        had_silent_marker_(false),
+        had_errors_(false) {
+    // For backwards-compatibility with proto1, we need to allow the 'f' suffix
+    // for floats.
+    tokenizer_.set_allow_f_after_float(true);
+
+    // '#' starts a comment.
+    tokenizer_.set_comment_style(io::Tokenizer::SH_COMMENT_STYLE);
+
+    if (allow_relaxed_whitespace) {
+      tokenizer_.set_require_space_after_number(false);
+      tokenizer_.set_allow_multiline_strings(true);
+    }
+
+    // Consume the starting token.
+    tokenizer_.Next();
+  }
+  ~ParserImpl() {}
+
+  // Parses the ASCII representation specified in input and saves the
+  // information into the output pointer (a Message). Returns
+  // false if an error occurs (an error will also be logged to
+  // GOOGLE_LOG(ERROR)).
+  bool Parse(Message* output) {
+    // Consume fields until we cannot do so anymore.
+    while (true) {
+      if (LookingAtType(io::Tokenizer::TYPE_END)) {
+        // Ensures recursion limit properly unwinded, but only for success
+        // cases. This implicitly avoids the check when `Parse` returns false
+        // via `DO(...)`.
+        GOOGLE_DCHECK(had_errors_ || recursion_limit_ == initial_recursion_limit_)
+            << "Recursion limit at end of parse should be "
+            << initial_recursion_limit_ << ", but was " << recursion_limit_
+            << ". Difference of " << initial_recursion_limit_ - recursion_limit_
+            << " stack frames not accounted for stack unwind.";
+
+        return !had_errors_;
+      }
+
+      DO(ConsumeField(output));
+    }
+  }
+
+  bool ParseField(const FieldDescriptor* field, Message* output) {
+    bool suc;
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      suc = ConsumeFieldMessage(output, output->GetReflection(), field);
+    } else {
+      suc = ConsumeFieldValue(output, output->GetReflection(), field);
+    }
+    return suc && LookingAtType(io::Tokenizer::TYPE_END);
+  }
+
+  void ReportError(int line, int col, const std::string& message) {
+    had_errors_ = true;
+    if (error_collector_ == nullptr) {
+      if (line >= 0) {
+        GOOGLE_LOG(ERROR) << "Error parsing text-format "
+                   << root_message_type_->full_name() << ": " << (line + 1)
+                   << ":" << (col + 1) << ": " << message;
+      } else {
+        GOOGLE_LOG(ERROR) << "Error parsing text-format "
+                   << root_message_type_->full_name() << ": " << message;
+      }
+    } else {
+      error_collector_->AddError(line, col, message);
+    }
+  }
+
+  void ReportWarning(int line, int col, const std::string& message) {
+    if (error_collector_ == nullptr) {
+      if (line >= 0) {
+        GOOGLE_LOG(WARNING) << "Warning parsing text-format "
+                     << root_message_type_->full_name() << ": " << (line + 1)
+                     << ":" << (col + 1) << ": " << message;
+      } else {
+        GOOGLE_LOG(WARNING) << "Warning parsing text-format "
+                     << root_message_type_->full_name() << ": " << message;
+      }
+    } else {
+      error_collector_->AddWarning(line, col, message);
+    }
+  }
+
+ private:
+  static constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
+  static constexpr uint32_t kuint32max = std::numeric_limits<uint32_t>::max();
+  static constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+  static constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+  static constexpr uint64_t kuint64max = std::numeric_limits<uint64_t>::max();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl);
+
+  // Reports an error with the given message with information indicating
+  // the position (as derived from the current token).
+  void ReportError(const std::string& message) {
+    ReportError(tokenizer_.current().line, tokenizer_.current().column,
+                message);
+  }
+
+  // Reports a warning with the given message with information indicating
+  // the position (as derived from the current token).
+  void ReportWarning(const std::string& message) {
+    ReportWarning(tokenizer_.current().line, tokenizer_.current().column,
+                  message);
+  }
+
+  // Consumes the specified message with the given starting delimiter.
+  // This method checks to see that the end delimiter at the conclusion of
+  // the consumption matches the starting delimiter passed in here.
+  bool ConsumeMessage(Message* message, const std::string delimiter) {
+    while (!LookingAt(">") && !LookingAt("}")) {
+      DO(ConsumeField(message));
+    }
+
+    // Confirm that we have a valid ending delimiter.
+    DO(Consume(delimiter));
+    return true;
+  }
+
+  // Consume either "<" or "{".
+  bool ConsumeMessageDelimiter(std::string* delimiter) {
+    if (TryConsume("<")) {
+      *delimiter = ">";
+    } else {
+      DO(Consume("{"));
+      *delimiter = "}";
+    }
+    return true;
+  }
+
+
+  // Consumes the current field (as returned by the tokenizer) on the
+  // passed in message.
+  bool ConsumeField(Message* message) {
+    const Reflection* reflection = message->GetReflection();
+    const Descriptor* descriptor = message->GetDescriptor();
+
+    std::string field_name;
+    bool reserved_field = false;
+    const FieldDescriptor* field = nullptr;
+    int start_line = tokenizer_.current().line;
+    int start_column = tokenizer_.current().column;
+
+    const FieldDescriptor* any_type_url_field;
+    const FieldDescriptor* any_value_field;
+    if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field,
+                                         &any_value_field) &&
+        TryConsume("[")) {
+      std::string full_type_name, prefix;
+      DO(ConsumeAnyTypeUrl(&full_type_name, &prefix));
+      std::string prefix_and_full_type_name =
+          StrCat(prefix, full_type_name);
+      DO(ConsumeBeforeWhitespace("]"));
+      TryConsumeWhitespace();
+      // ':' is optional between message labels and values.
+      if (TryConsumeBeforeWhitespace(":")) {
+        TryConsumeWhitespace();
+      }
+      std::string serialized_value;
+      const Descriptor* value_descriptor =
+          finder_ ? finder_->FindAnyType(*message, prefix, full_type_name)
+                  : DefaultFinderFindAnyType(*message, prefix, full_type_name);
+      if (value_descriptor == nullptr) {
+        ReportError("Could not find type \"" + prefix_and_full_type_name +
+                    "\" stored in google.protobuf.Any.");
+        return false;
+      }
+      DO(ConsumeAnyValue(value_descriptor, &serialized_value));
+      if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
+        // Fail if any_type_url_field has already been specified.
+        if ((!any_type_url_field->is_repeated() &&
+             reflection->HasField(*message, any_type_url_field)) ||
+            (!any_value_field->is_repeated() &&
+             reflection->HasField(*message, any_value_field))) {
+          ReportError("Non-repeated Any specified multiple times.");
+          return false;
+        }
+      }
+      reflection->SetString(message, any_type_url_field,
+                            std::move(prefix_and_full_type_name));
+      reflection->SetString(message, any_value_field,
+                            std::move(serialized_value));
+      return true;
+    }
+    if (TryConsume("[")) {
+      // Extension.
+      DO(ConsumeFullTypeName(&field_name));
+      DO(ConsumeBeforeWhitespace("]"));
+      TryConsumeWhitespace();
+
+      field = finder_ ? finder_->FindExtension(message, field_name)
+                      : DefaultFinderFindExtension(message, field_name);
+
+      if (field == nullptr) {
+        if (!allow_unknown_field_ && !allow_unknown_extension_) {
+          ReportError("Extension \"" + field_name +
+                      "\" is not defined or "
+                      "is not an extension of \"" +
+                      descriptor->full_name() + "\".");
+          return false;
+        } else {
+          ReportWarning("Ignoring extension \"" + field_name +
+                        "\" which is not defined or is not an extension of \"" +
+                        descriptor->full_name() + "\".");
+        }
+      }
+    } else {
+      DO(ConsumeIdentifierBeforeWhitespace(&field_name));
+      TryConsumeWhitespace();
+
+      int32_t field_number;
+      if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
+        if (descriptor->IsExtensionNumber(field_number)) {
+          field = finder_
+                      ? finder_->FindExtensionByNumber(descriptor, field_number)
+                      : DefaultFinderFindExtensionByNumber(descriptor,
+                                                           field_number);
+        } else if (descriptor->IsReservedNumber(field_number)) {
+          reserved_field = true;
+        } else {
+          field = descriptor->FindFieldByNumber(field_number);
+        }
+      } else {
+        field = descriptor->FindFieldByName(field_name);
+        // Group names are expected to be capitalized as they appear in the
+        // .proto file, which actually matches their type names, not their
+        // field names.
+        if (field == nullptr) {
+          std::string lower_field_name = field_name;
+          LowerString(&lower_field_name);
+          field = descriptor->FindFieldByName(lower_field_name);
+          // If the case-insensitive match worked but the field is NOT a group,
+          if (field != nullptr &&
+              field->type() != FieldDescriptor::TYPE_GROUP) {
+            field = nullptr;
+          }
+        }
+        // Again, special-case group names as described above.
+        if (field != nullptr && field->type() == FieldDescriptor::TYPE_GROUP &&
+            field->message_type()->name() != field_name) {
+          field = nullptr;
+        }
+
+        if (field == nullptr && allow_case_insensitive_field_) {
+          std::string lower_field_name = field_name;
+          LowerString(&lower_field_name);
+          field = descriptor->FindFieldByLowercaseName(lower_field_name);
+        }
+
+        if (field == nullptr) {
+          reserved_field = descriptor->IsReservedName(field_name);
+        }
+      }
+
+      if (field == nullptr && !reserved_field) {
+        if (!allow_unknown_field_) {
+          ReportError("Message type \"" + descriptor->full_name() +
+                      "\" has no field named \"" + field_name + "\".");
+          return false;
+        } else {
+          ReportWarning("Message type \"" + descriptor->full_name() +
+                        "\" has no field named \"" + field_name + "\".");
+        }
+      }
+    }
+
+    // Skips unknown or reserved fields.
+    if (field == nullptr) {
+      GOOGLE_CHECK(allow_unknown_field_ || allow_unknown_extension_ || reserved_field);
+
+      // Try to guess the type of this field.
+      // If this field is not a message, there should be a ":" between the
+      // field name and the field value and also the field value should not
+      // start with "{" or "<" which indicates the beginning of a message body.
+      // If there is no ":" or there is a "{" or "<" after ":", this field has
+      // to be a message or the input is ill-formed.
+      if (TryConsumeBeforeWhitespace(":")) {
+        TryConsumeWhitespace();
+        if (!LookingAt("{") && !LookingAt("<")) {
+          return SkipFieldValue();
+        }
+      }
+      return SkipFieldMessage();
+    }
+
+    if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
+      // Fail if the field is not repeated and it has already been specified.
+      if (!field->is_repeated() && reflection->HasField(*message, field)) {
+        ReportError("Non-repeated field \"" + field_name +
+                    "\" is specified multiple times.");
+        return false;
+      }
+      // Fail if the field is a member of a oneof and another member has already
+      // been specified.
+      const OneofDescriptor* oneof = field->containing_oneof();
+      if (oneof != nullptr && reflection->HasOneof(*message, oneof)) {
+        const FieldDescriptor* other_field =
+            reflection->GetOneofFieldDescriptor(*message, oneof);
+        ReportError("Field \"" + field_name +
+                    "\" is specified along with "
+                    "field \"" +
+                    other_field->name() +
+                    "\", another member "
+                    "of oneof \"" +
+                    oneof->name() + "\".");
+        return false;
+      }
+    }
+
+    // Perform special handling for embedded message types.
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // ':' is optional here.
+      bool consumed_semicolon = TryConsumeBeforeWhitespace(":");
+      if (consumed_semicolon) {
+        TryConsumeWhitespace();
+      }
+      if (consumed_semicolon && field->options().weak() &&
+          LookingAtType(io::Tokenizer::TYPE_STRING)) {
+        // we are getting a bytes string for a weak field.
+        std::string tmp;
+        DO(ConsumeString(&tmp));
+        MessageFactory* factory =
+            finder_ ? finder_->FindExtensionFactory(field) : nullptr;
+        reflection->MutableMessage(message, field, factory)
+            ->ParseFromString(tmp);
+        goto label_skip_parsing;
+      }
+    } else {
+      // ':' is required here.
+      DO(ConsumeBeforeWhitespace(":"));
+      TryConsumeWhitespace();
+    }
+
+    if (field->is_repeated() && TryConsume("[")) {
+      // Short repeated format, e.g.  "foo: [1, 2, 3]".
+      if (!TryConsume("]")) {
+        // "foo: []" is treated as empty.
+        while (true) {
+          if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+            // Perform special handling for embedded message types.
+            DO(ConsumeFieldMessage(message, reflection, field));
+          } else {
+            DO(ConsumeFieldValue(message, reflection, field));
+          }
+          if (TryConsume("]")) {
+            break;
+          }
+          DO(Consume(","));
+        }
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      DO(ConsumeFieldMessage(message, reflection, field));
+    } else {
+      DO(ConsumeFieldValue(message, reflection, field));
+    }
+  label_skip_parsing:
+    // For historical reasons, fields may optionally be separated by commas or
+    // semicolons.
+    TryConsume(";") || TryConsume(",");
+
+    if (field->options().deprecated()) {
+      ReportWarning("text format contains deprecated field \"" + field_name +
+                    "\"");
+    }
+
+    // If a parse info tree exists, add the location for the parsed
+    // field.
+    if (parse_info_tree_ != nullptr) {
+      int end_line = tokenizer_.previous().line;
+      int end_column = tokenizer_.previous().end_column;
+
+      RecordLocation(parse_info_tree_, field,
+                     ParseLocationRange(ParseLocation(start_line, start_column),
+                                        ParseLocation(end_line, end_column)));
+    }
+
+    return true;
+  }
+
+  // Skips the next field including the field's name and value.
+  bool SkipField() {
+    std::string field_name;
+    if (TryConsume("[")) {
+      // Extension name or type URL.
+      DO(ConsumeTypeUrlOrFullTypeName(&field_name));
+      DO(ConsumeBeforeWhitespace("]"));
+    } else {
+      DO(ConsumeIdentifierBeforeWhitespace(&field_name));
+    }
+    TryConsumeWhitespace();
+
+    // Try to guess the type of this field.
+    // If this field is not a message, there should be a ":" between the
+    // field name and the field value and also the field value should not
+    // start with "{" or "<" which indicates the beginning of a message body.
+    // If there is no ":" or there is a "{" or "<" after ":", this field has
+    // to be a message or the input is ill-formed.
+    if (TryConsumeBeforeWhitespace(":")) {
+      TryConsumeWhitespace();
+      if (!LookingAt("{") && !LookingAt("<")) {
+        DO(SkipFieldValue());
+      } else {
+        DO(SkipFieldMessage());
+      }
+    } else {
+      DO(SkipFieldMessage());
+    }
+    // For historical reasons, fields may optionally be separated by commas or
+    // semicolons.
+    TryConsume(";") || TryConsume(",");
+    return true;
+  }
+
+  bool ConsumeFieldMessage(Message* message, const Reflection* reflection,
+                           const FieldDescriptor* field) {
+    if (--recursion_limit_ < 0) {
+      ReportError(
+          StrCat("Message is too deep, the parser exceeded the "
+                       "configured recursion limit of ",
+                       initial_recursion_limit_, "."));
+      return false;
+    }
+    // If the parse information tree is not nullptr, create a nested one
+    // for the nested message.
+    ParseInfoTree* parent = parse_info_tree_;
+    if (parent != nullptr) {
+      parse_info_tree_ = CreateNested(parent, field);
+    }
+
+    std::string delimiter;
+    DO(ConsumeMessageDelimiter(&delimiter));
+    MessageFactory* factory =
+        finder_ ? finder_->FindExtensionFactory(field) : nullptr;
+    if (field->is_repeated()) {
+      DO(ConsumeMessage(reflection->AddMessage(message, field, factory),
+                        delimiter));
+    } else {
+      DO(ConsumeMessage(reflection->MutableMessage(message, field, factory),
+                        delimiter));
+    }
+
+    ++recursion_limit_;
+
+    // Reset the parse information tree.
+    parse_info_tree_ = parent;
+    return true;
+  }
+
+  // Skips the whole body of a message including the beginning delimiter and
+  // the ending delimiter.
+  bool SkipFieldMessage() {
+    if (--recursion_limit_ < 0) {
+      ReportError(
+          StrCat("Message is too deep, the parser exceeded the "
+                       "configured recursion limit of ",
+                       initial_recursion_limit_, "."));
+      return false;
+    }
+
+    std::string delimiter;
+    DO(ConsumeMessageDelimiter(&delimiter));
+    while (!LookingAt(">") && !LookingAt("}")) {
+      DO(SkipField());
+    }
+    DO(Consume(delimiter));
+
+    ++recursion_limit_;
+    return true;
+  }
+
+  bool ConsumeFieldValue(Message* message, const Reflection* reflection,
+                         const FieldDescriptor* field) {
+// Define an easy to use macro for setting fields. This macro checks
+// to see if the field is repeated (in which case we need to use the Add
+// methods or not (in which case we need to use the Set methods).
+#define SET_FIELD(CPPTYPE, VALUE)                    \
+  if (field->is_repeated()) {                        \
+    reflection->Add##CPPTYPE(message, field, VALUE); \
+  } else {                                           \
+    reflection->Set##CPPTYPE(message, field, VALUE); \
+  }
+
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32: {
+        int64_t value;
+        DO(ConsumeSignedInteger(&value, kint32max));
+        SET_FIELD(Int32, static_cast<int32_t>(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        uint64_t value;
+        DO(ConsumeUnsignedInteger(&value, kuint32max));
+        SET_FIELD(UInt32, static_cast<uint32_t>(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_INT64: {
+        int64_t value;
+        DO(ConsumeSignedInteger(&value, kint64max));
+        SET_FIELD(Int64, value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        uint64_t value;
+        DO(ConsumeUnsignedInteger(&value, kuint64max));
+        SET_FIELD(UInt64, value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_FLOAT: {
+        double value;
+        DO(ConsumeDouble(&value));
+        SET_FIELD(Float, io::SafeDoubleToFloat(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_DOUBLE: {
+        double value;
+        DO(ConsumeDouble(&value));
+        SET_FIELD(Double, value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_STRING: {
+        std::string value;
+        DO(ConsumeString(&value));
+        SET_FIELD(String, std::move(value));
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_BOOL: {
+        if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+          uint64_t value;
+          DO(ConsumeUnsignedInteger(&value, 1));
+          SET_FIELD(Bool, value);
+        } else {
+          std::string value;
+          DO(ConsumeIdentifier(&value));
+          if (value == "true" || value == "True" || value == "t") {
+            SET_FIELD(Bool, true);
+          } else if (value == "false" || value == "False" || value == "f") {
+            SET_FIELD(Bool, false);
+          } else {
+            ReportError("Invalid value for boolean field \"" + field->name() +
+                        "\". Value: \"" + value + "\".");
+            return false;
+          }
+        }
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        std::string value;
+        int64_t int_value = kint64max;
+        const EnumDescriptor* enum_type = field->enum_type();
+        const EnumValueDescriptor* enum_value = nullptr;
+
+        if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+          DO(ConsumeIdentifier(&value));
+          // Find the enumeration value.
+          enum_value = enum_type->FindValueByName(value);
+
+        } else if (LookingAt("-") ||
+                   LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+          DO(ConsumeSignedInteger(&int_value, kint32max));
+          value = StrCat(int_value);  // for error reporting
+          enum_value = enum_type->FindValueByNumber(int_value);
+        } else {
+          ReportError("Expected integer or identifier, got: " +
+                      tokenizer_.current().text);
+          return false;
+        }
+
+        if (enum_value == nullptr) {
+          if (int_value != kint64max &&
+              reflection->SupportsUnknownEnumValues()) {
+            SET_FIELD(EnumValue, int_value);
+            return true;
+          } else if (!allow_unknown_enum_) {
+            ReportError("Unknown enumeration value of \"" + value +
+                        "\" for "
+                        "field \"" +
+                        field->name() + "\".");
+            return false;
+          } else {
+            ReportWarning("Unknown enumeration value of \"" + value +
+                          "\" for "
+                          "field \"" +
+                          field->name() + "\".");
+            return true;
+          }
+        }
+
+        SET_FIELD(Enum, enum_value);
+        break;
+      }
+
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        // We should never get here. Put here instead of a default
+        // so that if new types are added, we get a nice compiler warning.
+        GOOGLE_LOG(FATAL) << "Reached an unintended state: CPPTYPE_MESSAGE";
+        break;
+      }
+    }
+#undef SET_FIELD
+    return true;
+  }
+
+  bool SkipFieldValue() {
+    if (--recursion_limit_ < 0) {
+      ReportError(
+          StrCat("Message is too deep, the parser exceeded the "
+                       "configured recursion limit of ",
+                       initial_recursion_limit_, "."));
+      return false;
+    }
+
+    if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+        tokenizer_.Next();
+      }
+      ++recursion_limit_;
+      return true;
+    }
+    if (TryConsume("[")) {
+      while (true) {
+        if (!LookingAt("{") && !LookingAt("<")) {
+          DO(SkipFieldValue());
+        } else {
+          DO(SkipFieldMessage());
+        }
+        if (TryConsume("]")) {
+          break;
+        }
+        DO(Consume(","));
+      }
+      ++recursion_limit_;
+      return true;
+    }
+    // Possible field values other than string:
+    //   12345        => TYPE_INTEGER
+    //   -12345       => TYPE_SYMBOL + TYPE_INTEGER
+    //   1.2345       => TYPE_FLOAT
+    //   -1.2345      => TYPE_SYMBOL + TYPE_FLOAT
+    //   inf          => TYPE_IDENTIFIER
+    //   -inf         => TYPE_SYMBOL + TYPE_IDENTIFIER
+    //   TYPE_INTEGER => TYPE_IDENTIFIER
+    // Divides them into two group, one with TYPE_SYMBOL
+    // and the other without:
+    //   Group one:
+    //     12345        => TYPE_INTEGER
+    //     1.2345       => TYPE_FLOAT
+    //     inf          => TYPE_IDENTIFIER
+    //     TYPE_INTEGER => TYPE_IDENTIFIER
+    //   Group two:
+    //     -12345       => TYPE_SYMBOL + TYPE_INTEGER
+    //     -1.2345      => TYPE_SYMBOL + TYPE_FLOAT
+    //     -inf         => TYPE_SYMBOL + TYPE_IDENTIFIER
+    // As we can see, the field value consists of an optional '-' and one of
+    // TYPE_INTEGER, TYPE_FLOAT and TYPE_IDENTIFIER.
+    bool has_minus = TryConsume("-");
+    if (!LookingAtType(io::Tokenizer::TYPE_INTEGER) &&
+        !LookingAtType(io::Tokenizer::TYPE_FLOAT) &&
+        !LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      std::string text = tokenizer_.current().text;
+      ReportError("Cannot skip field value, unexpected token: " + text);
+      ++recursion_limit_;
+      return false;
+    }
+    // Combination of '-' and TYPE_IDENTIFIER may result in an invalid field
+    // value while other combinations all generate valid values.
+    // We check if the value of this combination is valid here.
+    // TYPE_IDENTIFIER after a '-' should be one of the float values listed
+    // below:
+    //   inf, inff, infinity, nan
+    if (has_minus && LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      std::string text = tokenizer_.current().text;
+      LowerString(&text);
+      if (text != "inf" &&
+          text != "infinity" && text != "nan") {
+        ReportError("Invalid float number: " + text);
+        ++recursion_limit_;
+        return false;
+      }
+    }
+    tokenizer_.Next();
+    ++recursion_limit_;
+    return true;
+  }
+
+  // Returns true if the current token's text is equal to that specified.
+  bool LookingAt(const std::string& text) {
+    return tokenizer_.current().text == text;
+  }
+
+  // Returns true if the current token's type is equal to that specified.
+  bool LookingAtType(io::Tokenizer::TokenType token_type) {
+    return tokenizer_.current().type == token_type;
+  }
+
+  // Consumes an identifier and saves its value in the identifier parameter.
+  // Returns false if the token is not of type IDENTIFIER.
+  bool ConsumeIdentifier(std::string* identifier) {
+    if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      *identifier = tokenizer_.current().text;
+      tokenizer_.Next();
+      return true;
+    }
+
+    // If allow_field_numer_ or allow_unknown_field_ is true, we should able
+    // to parse integer identifiers.
+    if ((allow_field_number_ || allow_unknown_field_ ||
+         allow_unknown_extension_) &&
+        LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      *identifier = tokenizer_.current().text;
+      tokenizer_.Next();
+      return true;
+    }
+
+    ReportError("Expected identifier, got: " + tokenizer_.current().text);
+    return false;
+  }
+
+  // Similar to `ConsumeIdentifier`, but any following whitespace token may
+  // be reported.
+  bool ConsumeIdentifierBeforeWhitespace(std::string* identifier) {
+    tokenizer_.set_report_whitespace(true);
+    bool result = ConsumeIdentifier(identifier);
+    tokenizer_.set_report_whitespace(false);
+    return result;
+  }
+
+  // Consume a string of form "<id1>.<id2>....<idN>".
+  bool ConsumeFullTypeName(std::string* name) {
+    DO(ConsumeIdentifier(name));
+    while (TryConsume(".")) {
+      std::string part;
+      DO(ConsumeIdentifier(&part));
+      *name += ".";
+      *name += part;
+    }
+    return true;
+  }
+
+  bool ConsumeTypeUrlOrFullTypeName(std::string* name) {
+    DO(ConsumeIdentifier(name));
+    while (true) {
+      std::string connector;
+      if (TryConsume(".")) {
+        connector = ".";
+      } else if (TryConsume("/")) {
+        connector = "/";
+      } else {
+        break;
+      }
+      std::string part;
+      DO(ConsumeIdentifier(&part));
+      *name += connector;
+      *name += part;
+    }
+    return true;
+  }
+
+  // Consumes a string and saves its value in the text parameter.
+  // Returns false if the token is not of type STRING.
+  bool ConsumeString(std::string* text) {
+    if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      ReportError("Expected string, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    text->clear();
+    while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      io::Tokenizer::ParseStringAppend(tokenizer_.current().text, text);
+
+      tokenizer_.Next();
+    }
+
+    return true;
+  }
+
+  // Consumes a uint64_t and saves its value in the value parameter.
+  // Returns false if the token is not of type INTEGER.
+  bool ConsumeUnsignedInteger(uint64_t* value, uint64_t max_value) {
+    if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      ReportError("Expected integer, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    if (!io::Tokenizer::ParseInteger(tokenizer_.current().text, max_value,
+                                     value)) {
+      ReportError("Integer out of range (" + tokenizer_.current().text + ")");
+      return false;
+    }
+
+    tokenizer_.Next();
+    return true;
+  }
+
+  // Consumes an int64_t and saves its value in the value parameter.
+  // Note that since the tokenizer does not support negative numbers,
+  // we actually may consume an additional token (for the minus sign) in this
+  // method. Returns false if the token is not an integer
+  // (signed or otherwise).
+  bool ConsumeSignedInteger(int64_t* value, uint64_t max_value) {
+    bool negative = false;
+
+    if (TryConsume("-")) {
+      negative = true;
+      // Two's complement always allows one more negative integer than
+      // positive.
+      ++max_value;
+    }
+
+    uint64_t unsigned_value;
+
+    DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
+
+    if (negative) {
+      if ((static_cast<uint64_t>(kint64max) + 1) == unsigned_value) {
+        *value = kint64min;
+      } else {
+        *value = -static_cast<int64_t>(unsigned_value);
+      }
+    } else {
+      *value = static_cast<int64_t>(unsigned_value);
+    }
+
+    return true;
+  }
+
+  // Consumes a double and saves its value in the value parameter.
+  // Accepts decimal numbers only, rejects hex or oct numbers.
+  bool ConsumeUnsignedDecimalAsDouble(double* value, uint64_t max_value) {
+    if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      ReportError("Expected integer, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    const std::string& text = tokenizer_.current().text;
+    if (IsHexNumber(text) || IsOctNumber(text)) {
+      ReportError("Expect a decimal number, got: " + text);
+      return false;
+    }
+
+    uint64_t uint64_value;
+    if (io::Tokenizer::ParseInteger(text, max_value, &uint64_value)) {
+      *value = static_cast<double>(uint64_value);
+    } else {
+      // Uint64 overflow, attempt to parse as a double instead.
+      *value = io::Tokenizer::ParseFloat(text);
+    }
+
+    tokenizer_.Next();
+    return true;
+  }
+
+  // Consumes a double and saves its value in the value parameter.
+  // Note that since the tokenizer does not support negative numbers,
+  // we actually may consume an additional token (for the minus sign) in this
+  // method. Returns false if the token is not a double
+  // (signed or otherwise).
+  bool ConsumeDouble(double* value) {
+    bool negative = false;
+
+    if (TryConsume("-")) {
+      negative = true;
+    }
+
+    // A double can actually be an integer, according to the tokenizer.
+    // Therefore, we must check both cases here.
+    if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
+      // We have found an integer value for the double.
+      DO(ConsumeUnsignedDecimalAsDouble(value, kuint64max));
+    } else if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
+      // We have found a float value for the double.
+      *value = io::Tokenizer::ParseFloat(tokenizer_.current().text);
+
+      // Mark the current token as consumed.
+      tokenizer_.Next();
+    } else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      std::string text = tokenizer_.current().text;
+      LowerString(&text);
+      if (text == "inf" ||
+          text == "infinity") {
+        *value = std::numeric_limits<double>::infinity();
+        tokenizer_.Next();
+      } else if (text == "nan") {
+        *value = std::numeric_limits<double>::quiet_NaN();
+        tokenizer_.Next();
+      } else {
+        ReportError("Expected double, got: " + text);
+        return false;
+      }
+    } else {
+      ReportError("Expected double, got: " + tokenizer_.current().text);
+      return false;
+    }
+
+    if (negative) {
+      *value = -*value;
+    }
+
+    return true;
+  }
+
+  // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name"
+  // or "type.googleprod.com/full.type.Name"
+  bool ConsumeAnyTypeUrl(std::string* full_type_name, std::string* prefix) {
+    // TODO(saito) Extend Consume() to consume multiple tokens at once, so that
+    // this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
+    DO(ConsumeIdentifier(prefix));
+    while (TryConsume(".")) {
+      std::string url;
+      DO(ConsumeIdentifier(&url));
+      *prefix += "." + url;
+    }
+    DO(Consume("/"));
+    *prefix += "/";
+    DO(ConsumeFullTypeName(full_type_name));
+
+    return true;
+  }
+
+  // A helper function for reconstructing Any::value. Consumes a text of
+  // full_type_name, then serializes it into serialized_value.
+  bool ConsumeAnyValue(const Descriptor* value_descriptor,
+                       std::string* serialized_value) {
+    DynamicMessageFactory factory;
+    const Message* value_prototype = factory.GetPrototype(value_descriptor);
+    if (value_prototype == nullptr) {
+      return false;
+    }
+    std::unique_ptr<Message> value(value_prototype->New());
+    std::string sub_delimiter;
+    DO(ConsumeMessageDelimiter(&sub_delimiter));
+    DO(ConsumeMessage(value.get(), sub_delimiter));
+
+    if (allow_partial_) {
+      value->AppendPartialToString(serialized_value);
+    } else {
+      if (!value->IsInitialized()) {
+        ReportError(
+            "Value of type \"" + value_descriptor->full_name() +
+            "\" stored in google.protobuf.Any has missing required fields");
+        return false;
+      }
+      value->AppendToString(serialized_value);
+    }
+    return true;
+  }
+
+  // Consumes a token and confirms that it matches that specified in the
+  // value parameter. Returns false if the token found does not match that
+  // which was specified.
+  bool Consume(const std::string& value) {
+    const std::string& current_value = tokenizer_.current().text;
+
+    if (current_value != value) {
+      ReportError("Expected \"" + value + "\", found \"" + current_value +
+                  "\".");
+      return false;
+    }
+
+    tokenizer_.Next();
+
+    return true;
+  }
+
+  // Similar to `Consume`, but the following token may be tokenized as
+  // TYPE_WHITESPACE.
+  bool ConsumeBeforeWhitespace(const std::string& value) {
+    // Report whitespace after this token, but only once.
+    tokenizer_.set_report_whitespace(true);
+    bool result = Consume(value);
+    tokenizer_.set_report_whitespace(false);
+    return result;
+  }
+
+  // Attempts to consume the supplied value. Returns false if a the
+  // token found does not match the value specified.
+  bool TryConsume(const std::string& value) {
+    if (tokenizer_.current().text == value) {
+      tokenizer_.Next();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  // Similar to `TryConsume`, but the following token may be tokenized as
+  // TYPE_WHITESPACE.
+  bool TryConsumeBeforeWhitespace(const std::string& value) {
+    // Report whitespace after this token, but only once.
+    tokenizer_.set_report_whitespace(true);
+    bool result = TryConsume(value);
+    tokenizer_.set_report_whitespace(false);
+    return result;
+  }
+
+  bool TryConsumeWhitespace() {
+    had_silent_marker_ = false;
+    if (LookingAtType(io::Tokenizer::TYPE_WHITESPACE)) {
+      if (tokenizer_.current().text ==
+          StrCat(" ", internal::kDebugStringSilentMarkerForDetection)) {
+        had_silent_marker_ = true;
+      }
+      tokenizer_.Next();
+      return true;
+    }
+    return false;
+  }
+
+  // An internal instance of the Tokenizer's error collector, used to
+  // collect any base-level parse errors and feed them to the ParserImpl.
+  class ParserErrorCollector : public io::ErrorCollector {
+   public:
+    explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser)
+        : parser_(parser) {}
+
+    ~ParserErrorCollector() override {}
+
+    void AddError(int line, int column, const std::string& message) override {
+      parser_->ReportError(line, column, message);
+    }
+
+    void AddWarning(int line, int column, const std::string& message) override {
+      parser_->ReportWarning(line, column, message);
+    }
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector);
+    TextFormat::Parser::ParserImpl* parser_;
+  };
+
+  io::ErrorCollector* error_collector_;
+  const TextFormat::Finder* finder_;
+  ParseInfoTree* parse_info_tree_;
+  ParserErrorCollector tokenizer_error_collector_;
+  io::Tokenizer tokenizer_;
+  const Descriptor* root_message_type_;
+  SingularOverwritePolicy singular_overwrite_policy_;
+  const bool allow_case_insensitive_field_;
+  const bool allow_unknown_field_;
+  const bool allow_unknown_extension_;
+  const bool allow_unknown_enum_;
+  const bool allow_field_number_;
+  const bool allow_partial_;
+  const int initial_recursion_limit_;
+  int recursion_limit_;
+  bool had_silent_marker_;
+  bool had_errors_;
+};
+
+// ===========================================================================
+// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted
+// from the Printer found in //net/proto2/io/public/printer.h
+class TextFormat::Printer::TextGenerator
+    : public TextFormat::BaseTextGenerator {
+ public:
+  explicit TextGenerator(io::ZeroCopyOutputStream* output,
+                         int initial_indent_level)
+      : output_(output),
+        buffer_(nullptr),
+        buffer_size_(0),
+        at_start_of_line_(true),
+        failed_(false),
+        insert_silent_marker_(false),
+        indent_level_(initial_indent_level),
+        initial_indent_level_(initial_indent_level) {}
+
+  explicit TextGenerator(io::ZeroCopyOutputStream* output,
+                         bool insert_silent_marker, int initial_indent_level)
+      : output_(output),
+        buffer_(nullptr),
+        buffer_size_(0),
+        at_start_of_line_(true),
+        failed_(false),
+        insert_silent_marker_(insert_silent_marker),
+        indent_level_(initial_indent_level),
+        initial_indent_level_(initial_indent_level) {}
+
+  ~TextGenerator() override {
+    // Only BackUp() if we're sure we've successfully called Next() at least
+    // once.
+    if (!failed_) {
+      output_->BackUp(buffer_size_);
+    }
+  }
+
+  // Indent text by two spaces.  After calling Indent(), two spaces will be
+  // inserted at the beginning of each line of text.  Indent() may be called
+  // multiple times to produce deeper indents.
+  void Indent() override { ++indent_level_; }
+
+  // Reduces the current indent level by two spaces, or crashes if the indent
+  // level is zero.
+  void Outdent() override {
+    if (indent_level_ == 0 || indent_level_ < initial_indent_level_) {
+      GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
+      return;
+    }
+
+    --indent_level_;
+  }
+
+  size_t GetCurrentIndentationSize() const override {
+    return 2 * indent_level_;
+  }
+
+  // Print text to the output stream.
+  void Print(const char* text, size_t size) override {
+    if (indent_level_ > 0) {
+      size_t pos = 0;  // The number of bytes we've written so far.
+      for (size_t i = 0; i < size; i++) {
+        if (text[i] == '\n') {
+          // Saw newline.  If there is more text, we may need to insert an
+          // indent here.  So, write what we have so far, including the '\n'.
+          Write(text + pos, i - pos + 1);
+          pos = i + 1;
+
+          // Setting this true will cause the next Write() to insert an indent
+          // first.
+          at_start_of_line_ = true;
+        }
+      }
+      // Write the rest.
+      Write(text + pos, size - pos);
+    } else {
+      Write(text, size);
+      if (size > 0 && text[size - 1] == '\n') {
+        at_start_of_line_ = true;
+      }
+    }
+  }
+
+  // True if any write to the underlying stream failed.  (We don't just
+  // crash in this case because this is an I/O failure, not a programming
+  // error.)
+  bool failed() const { return failed_; }
+
+  void PrintMaybeWithMarker(StringPiece text) {
+    Print(text.data(), text.size());
+    if (ConsumeInsertSilentMarker()) {
+      PrintLiteral(internal::kDebugStringSilentMarker);
+    }
+  }
+
+  void PrintMaybeWithMarker(StringPiece text_head,
+                            StringPiece text_tail) {
+    Print(text_head.data(), text_head.size());
+    if (ConsumeInsertSilentMarker()) {
+      PrintLiteral(internal::kDebugStringSilentMarker);
+    }
+    Print(text_tail.data(), text_tail.size());
+  }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
+
+  void Write(const char* data, size_t size) {
+    if (failed_) return;
+    if (size == 0) return;
+
+    if (at_start_of_line_) {
+      // Insert an indent.
+      at_start_of_line_ = false;
+      WriteIndent();
+      if (failed_) return;
+    }
+
+    while (static_cast<int64_t>(size) > buffer_size_) {
+      // Data exceeds space in the buffer.  Copy what we can and request a
+      // new buffer.
+      if (buffer_size_ > 0) {
+        memcpy(buffer_, data, buffer_size_);
+        data += buffer_size_;
+        size -= buffer_size_;
+      }
+      void* void_buffer = nullptr;
+      failed_ = !output_->Next(&void_buffer, &buffer_size_);
+      if (failed_) return;
+      buffer_ = reinterpret_cast<char*>(void_buffer);
+    }
+
+    // Buffer is big enough to receive the data; copy it.
+    memcpy(buffer_, data, size);
+    buffer_ += size;
+    buffer_size_ -= size;
+  }
+
+  void WriteIndent() {
+    if (indent_level_ == 0) {
+      return;
+    }
+    GOOGLE_DCHECK(!failed_);
+    int size = GetCurrentIndentationSize();
+
+    while (size > buffer_size_) {
+      // Data exceeds space in the buffer. Write what we can and request a new
+      // buffer.
+      if (buffer_size_ > 0) {
+        memset(buffer_, ' ', buffer_size_);
+      }
+      size -= buffer_size_;
+      void* void_buffer;
+      failed_ = !output_->Next(&void_buffer, &buffer_size_);
+      if (failed_) return;
+      buffer_ = reinterpret_cast<char*>(void_buffer);
+    }
+
+    // Buffer is big enough to receive the data; copy it.
+    memset(buffer_, ' ', size);
+    buffer_ += size;
+    buffer_size_ -= size;
+  }
+
+  // Return the current value of insert_silent_marker_. If it is true, set it
+  // to false as we assume that a silent marker is inserted after a call to this
+  // function.
+  bool ConsumeInsertSilentMarker() {
+    if (insert_silent_marker_) {
+      insert_silent_marker_ = false;
+      return true;
+    }
+    return false;
+  }
+
+  io::ZeroCopyOutputStream* const output_;
+  char* buffer_;
+  int buffer_size_;
+  bool at_start_of_line_;
+  bool failed_;
+  // This flag is false when inserting silent marker is disabled or a silent
+  // marker has been inserted.
+  bool insert_silent_marker_;
+
+  int indent_level_;
+  int initial_indent_level_;
+};
+
+// ===========================================================================
+//  An internal field value printer that may insert a silent marker in
+//  DebugStrings.
+class TextFormat::Printer::DebugStringFieldValuePrinter
+    : public TextFormat::FastFieldValuePrinter {
+ public:
+  void PrintMessageStart(const Message& /*message*/, int /*field_index*/,
+                         int /*field_count*/, bool single_line_mode,
+                         BaseTextGenerator* generator) const override {
+    // This is safe as only TextGenerator is used with
+    // DebugStringFieldValuePrinter.
+    TextGenerator* text_generator = static_cast<TextGenerator*>(generator);
+    if (single_line_mode) {
+      text_generator->PrintMaybeWithMarker(" ", "{ ");
+    } else {
+      text_generator->PrintMaybeWithMarker(" ", "{\n");
+    }
+  }
+};
+
+// ===========================================================================
+//  An internal field value printer that escape UTF8 strings.
+class TextFormat::Printer::FastFieldValuePrinterUtf8Escaping
+    : public TextFormat::Printer::DebugStringFieldValuePrinter {
+ public:
+  void PrintString(const std::string& val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintLiteral("\"");
+    generator->PrintString(strings::Utf8SafeCEscape(val));
+    generator->PrintLiteral("\"");
+  }
+  void PrintBytes(const std::string& val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    return FastFieldValuePrinter::PrintString(val, generator);
+  }
+};
+
+// ===========================================================================
+// Implementation of the default Finder for extensions.
+TextFormat::Finder::~Finder() {}
+
+const FieldDescriptor* TextFormat::Finder::FindExtension(
+    Message* message, const std::string& name) const {
+  return DefaultFinderFindExtension(message, name);
+}
+
+const FieldDescriptor* TextFormat::Finder::FindExtensionByNumber(
+    const Descriptor* descriptor, int number) const {
+  return DefaultFinderFindExtensionByNumber(descriptor, number);
+}
+
+const Descriptor* TextFormat::Finder::FindAnyType(
+    const Message& message, const std::string& prefix,
+    const std::string& name) const {
+  return DefaultFinderFindAnyType(message, prefix, name);
+}
+
+MessageFactory* TextFormat::Finder::FindExtensionFactory(
+    const FieldDescriptor* /*field*/) const {
+  return nullptr;
+}
+
+// ===========================================================================
+
+TextFormat::Parser::Parser()
+    : error_collector_(nullptr),
+      finder_(nullptr),
+      parse_info_tree_(nullptr),
+      allow_partial_(false),
+      allow_case_insensitive_field_(false),
+      allow_unknown_field_(false),
+      allow_unknown_extension_(false),
+      allow_unknown_enum_(false),
+      allow_field_number_(false),
+      allow_relaxed_whitespace_(false),
+      allow_singular_overwrites_(false),
+      recursion_limit_(std::numeric_limits<int>::max()) {}
+
+TextFormat::Parser::~Parser() {}
+
+namespace {
+
+bool CheckParseInputSize(StringPiece input,
+                         io::ErrorCollector* error_collector) {
+  if (input.size() > INT_MAX) {
+    error_collector->AddError(
+        -1, 0,
+        StrCat(
+            "Input size too large: ", static_cast<int64_t>(input.size()),
+            " bytes", " > ", INT_MAX, " bytes."));
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
+                               Message* output) {
+  output->Clear();
+
+  ParserImpl::SingularOverwritePolicy overwrites_policy =
+      allow_singular_overwrites_ ? ParserImpl::ALLOW_SINGULAR_OVERWRITES
+                                 : ParserImpl::FORBID_SINGULAR_OVERWRITES;
+
+  ParserImpl parser(output->GetDescriptor(), input, error_collector_, finder_,
+                    parse_info_tree_, overwrites_policy,
+                    allow_case_insensitive_field_, allow_unknown_field_,
+                    allow_unknown_extension_, allow_unknown_enum_,
+                    allow_field_number_, allow_relaxed_whitespace_,
+                    allow_partial_, recursion_limit_);
+  return MergeUsingImpl(input, output, &parser);
+}
+
+bool TextFormat::Parser::ParseFromString(ConstStringParam input,
+                                         Message* output) {
+  DO(CheckParseInputSize(input, error_collector_));
+  io::ArrayInputStream input_stream(input.data(), input.size());
+  return Parse(&input_stream, output);
+}
+
+bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
+                               Message* output) {
+  ParserImpl parser(output->GetDescriptor(), input, error_collector_, finder_,
+                    parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+                    allow_case_insensitive_field_, allow_unknown_field_,
+                    allow_unknown_extension_, allow_unknown_enum_,
+                    allow_field_number_, allow_relaxed_whitespace_,
+                    allow_partial_, recursion_limit_);
+  return MergeUsingImpl(input, output, &parser);
+}
+
+bool TextFormat::Parser::MergeFromString(ConstStringParam input,
+                                         Message* output) {
+  DO(CheckParseInputSize(input, error_collector_));
+  io::ArrayInputStream input_stream(input.data(), input.size());
+  return Merge(&input_stream, output);
+}
+
+bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* /* input */,
+                                        Message* output,
+                                        ParserImpl* parser_impl) {
+  if (!parser_impl->Parse(output)) return false;
+  if (!allow_partial_ && !output->IsInitialized()) {
+    std::vector<std::string> missing_fields;
+    output->FindInitializationErrors(&missing_fields);
+    parser_impl->ReportError(-1, 0,
+                             "Message missing required fields: " +
+                                 Join(missing_fields, ", "));
+    return false;
+  }
+  return true;
+}
+
+bool TextFormat::Parser::ParseFieldValueFromString(const std::string& input,
+                                                   const FieldDescriptor* field,
+                                                   Message* output) {
+  io::ArrayInputStream input_stream(input.data(), input.size());
+  ParserImpl parser(
+      output->GetDescriptor(), &input_stream, error_collector_, finder_,
+      parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES,
+      allow_case_insensitive_field_, allow_unknown_field_,
+      allow_unknown_extension_, allow_unknown_enum_, allow_field_number_,
+      allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
+  return parser.ParseField(field, output);
+}
+
+/* static */ bool TextFormat::Parse(io::ZeroCopyInputStream* input,
+                                    Message* output) {
+  return Parser().Parse(input, output);
+}
+
+/* static */ bool TextFormat::Merge(io::ZeroCopyInputStream* input,
+                                    Message* output) {
+  return Parser().Merge(input, output);
+}
+
+/* static */ bool TextFormat::ParseFromString(ConstStringParam input,
+                                              Message* output) {
+  return Parser().ParseFromString(input, output);
+}
+
+/* static */ bool TextFormat::MergeFromString(ConstStringParam input,
+                                              Message* output) {
+  return Parser().MergeFromString(input, output);
+}
+
+#undef DO
+
+// ===========================================================================
+
+TextFormat::BaseTextGenerator::~BaseTextGenerator() {}
+
+namespace {
+
+// A BaseTextGenerator that writes to a string.
+class StringBaseTextGenerator : public TextFormat::BaseTextGenerator {
+ public:
+  void Print(const char* text, size_t size) override {
+    output_.append(text, size);
+  }
+
+// Some compilers do not support ref-qualifiers even in C++11 mode.
+// Disable the optimization for now and revisit it later.
+#if 0  // LANG_CXX11
+  std::string Consume() && { return std::move(output_); }
+#else  // !LANG_CXX11
+  const std::string& Get() { return output_; }
+#endif  // LANG_CXX11
+
+ private:
+  std::string output_;
+};
+
+}  // namespace
+
+// The default implementation for FieldValuePrinter. We just delegate the
+// implementation to the default FastFieldValuePrinter to avoid duplicating the
+// logic.
+TextFormat::FieldValuePrinter::FieldValuePrinter() {}
+TextFormat::FieldValuePrinter::~FieldValuePrinter() {}
+
+#if 0  // LANG_CXX11
+#define FORWARD_IMPL(fn, ...)            \
+  StringBaseTextGenerator generator;     \
+  delegate_.fn(__VA_ARGS__, &generator); \
+  return std::move(generator).Consume()
+#else  // !LANG_CXX11
+#define FORWARD_IMPL(fn, ...)            \
+  StringBaseTextGenerator generator;     \
+  delegate_.fn(__VA_ARGS__, &generator); \
+  return generator.Get()
+#endif  // LANG_CXX11
+
+std::string TextFormat::FieldValuePrinter::PrintBool(bool val) const {
+  FORWARD_IMPL(PrintBool, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintInt32(int32_t val) const {
+  FORWARD_IMPL(PrintInt32, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintUInt32(uint32_t val) const {
+  FORWARD_IMPL(PrintUInt32, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintInt64(int64_t val) const {
+  FORWARD_IMPL(PrintInt64, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintUInt64(uint64_t val) const {
+  FORWARD_IMPL(PrintUInt64, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintFloat(float val) const {
+  FORWARD_IMPL(PrintFloat, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintDouble(double val) const {
+  FORWARD_IMPL(PrintDouble, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintString(
+    const std::string& val) const {
+  FORWARD_IMPL(PrintString, val);
+}
+std::string TextFormat::FieldValuePrinter::PrintBytes(
+    const std::string& val) const {
+  return PrintString(val);
+}
+std::string TextFormat::FieldValuePrinter::PrintEnum(
+    int32_t val, const std::string& name) const {
+  FORWARD_IMPL(PrintEnum, val, name);
+}
+std::string TextFormat::FieldValuePrinter::PrintFieldName(
+    const Message& message, const Reflection* reflection,
+    const FieldDescriptor* field) const {
+  FORWARD_IMPL(PrintFieldName, message, reflection, field);
+}
+std::string TextFormat::FieldValuePrinter::PrintMessageStart(
+    const Message& message, int field_index, int field_count,
+    bool single_line_mode) const {
+  FORWARD_IMPL(PrintMessageStart, message, field_index, field_count,
+               single_line_mode);
+}
+std::string TextFormat::FieldValuePrinter::PrintMessageEnd(
+    const Message& message, int field_index, int field_count,
+    bool single_line_mode) const {
+  FORWARD_IMPL(PrintMessageEnd, message, field_index, field_count,
+               single_line_mode);
+}
+#undef FORWARD_IMPL
+
+TextFormat::FastFieldValuePrinter::FastFieldValuePrinter() {}
+TextFormat::FastFieldValuePrinter::~FastFieldValuePrinter() {}
+void TextFormat::FastFieldValuePrinter::PrintBool(
+    bool val, BaseTextGenerator* generator) const {
+  if (val) {
+    generator->PrintLiteral("true");
+  } else {
+    generator->PrintLiteral("false");
+  }
+}
+void TextFormat::FastFieldValuePrinter::PrintInt32(
+    int32_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintUInt32(
+    uint32_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintInt64(
+    int64_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintUInt64(
+    uint64_t val, BaseTextGenerator* generator) const {
+  generator->PrintString(StrCat(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintFloat(
+    float val, BaseTextGenerator* generator) const {
+  generator->PrintString(!std::isnan(val) ? SimpleFtoa(val) : "nan");
+}
+void TextFormat::FastFieldValuePrinter::PrintDouble(
+    double val, BaseTextGenerator* generator) const {
+  generator->PrintString(!std::isnan(val) ? SimpleDtoa(val) : "nan");
+}
+void TextFormat::FastFieldValuePrinter::PrintEnum(
+    int32_t /*val*/, const std::string& name,
+    BaseTextGenerator* generator) const {
+  generator->PrintString(name);
+}
+
+void TextFormat::FastFieldValuePrinter::PrintString(
+    const std::string& val, BaseTextGenerator* generator) const {
+  generator->PrintLiteral("\"");
+  generator->PrintString(CEscape(val));
+  generator->PrintLiteral("\"");
+}
+void TextFormat::FastFieldValuePrinter::PrintBytes(
+    const std::string& val, BaseTextGenerator* generator) const {
+  PrintString(val, generator);
+}
+void TextFormat::FastFieldValuePrinter::PrintFieldName(
+    const Message& message, int /*field_index*/, int /*field_count*/,
+    const Reflection* reflection, const FieldDescriptor* field,
+    BaseTextGenerator* generator) const {
+  PrintFieldName(message, reflection, field, generator);
+}
+void TextFormat::FastFieldValuePrinter::PrintFieldName(
+    const Message& /*message*/, const Reflection* /*reflection*/,
+    const FieldDescriptor* field, BaseTextGenerator* generator) const {
+  if (field->is_extension()) {
+    generator->PrintLiteral("[");
+    generator->PrintString(field->PrintableNameForExtension());
+    generator->PrintLiteral("]");
+  } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    // Groups must be serialized with their original capitalization.
+    generator->PrintString(field->message_type()->name());
+  } else {
+    generator->PrintString(field->name());
+  }
+}
+void TextFormat::FastFieldValuePrinter::PrintMessageStart(
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool single_line_mode, BaseTextGenerator* generator) const {
+  if (single_line_mode) {
+    generator->PrintLiteral(" { ");
+  } else {
+    generator->PrintLiteral(" {\n");
+  }
+}
+bool TextFormat::FastFieldValuePrinter::PrintMessageContent(
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool /*single_line_mode*/, BaseTextGenerator* /*generator*/) const {
+  return false;  // Use the default printing function.
+}
+void TextFormat::FastFieldValuePrinter::PrintMessageEnd(
+    const Message& /*message*/, int /*field_index*/, int /*field_count*/,
+    bool single_line_mode, BaseTextGenerator* generator) const {
+  if (single_line_mode) {
+    generator->PrintLiteral("} ");
+  } else {
+    generator->PrintLiteral("}\n");
+  }
+}
+
+namespace {
+
+// A legacy compatibility wrapper. Takes ownership of the delegate.
+class FieldValuePrinterWrapper : public TextFormat::FastFieldValuePrinter {
+ public:
+  explicit FieldValuePrinterWrapper(
+      const TextFormat::FieldValuePrinter* delegate)
+      : delegate_(delegate) {}
+
+  void SetDelegate(const TextFormat::FieldValuePrinter* delegate) {
+    delegate_.reset(delegate);
+  }
+
+  void PrintBool(bool val,
+                 TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintBool(val));
+  }
+  void PrintInt32(int32_t val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintInt32(val));
+  }
+  void PrintUInt32(uint32_t val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintUInt32(val));
+  }
+  void PrintInt64(int64_t val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintInt64(val));
+  }
+  void PrintUInt64(uint64_t val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintUInt64(val));
+  }
+  void PrintFloat(float val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintFloat(val));
+  }
+  void PrintDouble(double val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintDouble(val));
+  }
+  void PrintString(const std::string& val,
+                   TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintString(val));
+  }
+  void PrintBytes(const std::string& val,
+                  TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintBytes(val));
+  }
+  void PrintEnum(int32_t val, const std::string& name,
+                 TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintEnum(val, name));
+  }
+  void PrintFieldName(const Message& message, int /*field_index*/,
+                      int /*field_count*/, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(
+        delegate_->PrintFieldName(message, reflection, field));
+  }
+  void PrintFieldName(const Message& message, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(
+        delegate_->PrintFieldName(message, reflection, field));
+  }
+  void PrintMessageStart(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintMessageStart(
+        message, field_index, field_count, single_line_mode));
+  }
+  void PrintMessageEnd(
+      const Message& message, int field_index, int field_count,
+      bool single_line_mode,
+      TextFormat::BaseTextGenerator* generator) const override {
+    generator->PrintString(delegate_->PrintMessageEnd(
+        message, field_index, field_count, single_line_mode));
+  }
+
+ private:
+  std::unique_ptr<const TextFormat::FieldValuePrinter> delegate_;
+};
+
+}  // namespace
+
+const char* const TextFormat::Printer::kDoNotParse =
+    "DO NOT PARSE: fields may be stripped and missing.\n";
+
+TextFormat::Printer::Printer()
+    : initial_indent_level_(0),
+      single_line_mode_(false),
+      use_field_number_(false),
+      use_short_repeated_primitives_(false),
+      insert_silent_marker_(false),
+      hide_unknown_fields_(false),
+      print_message_fields_in_index_order_(false),
+      expand_any_(false),
+      truncate_string_field_longer_than_(0LL),
+      finder_(nullptr) {
+  SetUseUtf8StringEscaping(false);
+}
+
+void TextFormat::Printer::SetUseUtf8StringEscaping(bool as_utf8) {
+  SetDefaultFieldValuePrinter(as_utf8 ? new FastFieldValuePrinterUtf8Escaping()
+                                      : new DebugStringFieldValuePrinter());
+}
+
+void TextFormat::Printer::SetDefaultFieldValuePrinter(
+    const FieldValuePrinter* printer) {
+  default_field_value_printer_.reset(new FieldValuePrinterWrapper(printer));
+}
+
+void TextFormat::Printer::SetDefaultFieldValuePrinter(
+    const FastFieldValuePrinter* printer) {
+  default_field_value_printer_.reset(printer);
+}
+
+bool TextFormat::Printer::RegisterFieldValuePrinter(
+    const FieldDescriptor* field, const FieldValuePrinter* printer) {
+  if (field == nullptr || printer == nullptr) {
+    return false;
+  }
+  std::unique_ptr<FieldValuePrinterWrapper> wrapper(
+      new FieldValuePrinterWrapper(nullptr));
+  auto pair = custom_printers_.insert(std::make_pair(field, nullptr));
+  if (pair.second) {
+    wrapper->SetDelegate(printer);
+    pair.first->second = std::move(wrapper);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool TextFormat::Printer::RegisterFieldValuePrinter(
+    const FieldDescriptor* field, const FastFieldValuePrinter* printer) {
+  if (field == nullptr || printer == nullptr) {
+    return false;
+  }
+  auto pair = custom_printers_.insert(std::make_pair(field, nullptr));
+  if (pair.second) {
+    pair.first->second.reset(printer);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool TextFormat::Printer::RegisterMessagePrinter(
+    const Descriptor* descriptor, const MessagePrinter* printer) {
+  if (descriptor == nullptr || printer == nullptr) {
+    return false;
+  }
+  auto pair =
+      custom_message_printers_.insert(std::make_pair(descriptor, nullptr));
+  if (pair.second) {
+    pair.first->second.reset(printer);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool TextFormat::Printer::PrintToString(const Message& message,
+                                        std::string* output) const {
+  GOOGLE_DCHECK(output) << "output specified is nullptr";
+
+  output->clear();
+  io::StringOutputStream output_stream(output);
+
+  return Print(message, &output_stream);
+}
+
+bool TextFormat::Printer::PrintUnknownFieldsToString(
+    const UnknownFieldSet& unknown_fields, std::string* output) const {
+  GOOGLE_DCHECK(output) << "output specified is nullptr";
+
+  output->clear();
+  io::StringOutputStream output_stream(output);
+  return PrintUnknownFields(unknown_fields, &output_stream);
+}
+
+bool TextFormat::Printer::Print(const Message& message,
+                                io::ZeroCopyOutputStream* output) const {
+  TextGenerator generator(output, insert_silent_marker_, initial_indent_level_);
+
+  Print(message, &generator);
+
+  // Output false if the generator failed internally.
+  return !generator.failed();
+}
+
+// Maximum recursion depth for heuristically printing out length-delimited
+// unknown fields as messages.
+static constexpr int kUnknownFieldRecursionLimit = 10;
+
+bool TextFormat::Printer::PrintUnknownFields(
+    const UnknownFieldSet& unknown_fields,
+    io::ZeroCopyOutputStream* output) const {
+  TextGenerator generator(output, initial_indent_level_);
+
+  PrintUnknownFields(unknown_fields, &generator, kUnknownFieldRecursionLimit);
+
+  // Output false if the generator failed internally.
+  return !generator.failed();
+}
+
+namespace {
+// Comparison functor for sorting FieldDescriptors by field index.
+// Normal fields have higher precedence than extensions.
+struct FieldIndexSorter {
+  bool operator()(const FieldDescriptor* left,
+                  const FieldDescriptor* right) const {
+    if (left->is_extension() && right->is_extension()) {
+      return left->number() < right->number();
+    } else if (left->is_extension()) {
+      return false;
+    } else if (right->is_extension()) {
+      return true;
+    } else {
+      return left->index() < right->index();
+    }
+  }
+};
+
+}  // namespace
+
+bool TextFormat::Printer::PrintAny(const Message& message,
+                                   TextGenerator* generator) const {
+  const FieldDescriptor* type_url_field;
+  const FieldDescriptor* value_field;
+  if (!internal::GetAnyFieldDescriptors(message, &type_url_field,
+                                        &value_field)) {
+    return false;
+  }
+
+  const Reflection* reflection = message.GetReflection();
+
+  // Extract the full type name from the type_url field.
+  const std::string& type_url = reflection->GetString(message, type_url_field);
+  std::string url_prefix;
+  std::string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &url_prefix, &full_type_name)) {
+    return false;
+  }
+
+  // Print the "value" in text.
+  const Descriptor* value_descriptor =
+      finder_ ? finder_->FindAnyType(message, url_prefix, full_type_name)
+              : DefaultFinderFindAnyType(message, url_prefix, full_type_name);
+  if (value_descriptor == nullptr) {
+    GOOGLE_LOG(WARNING) << "Can't print proto content: proto type " << type_url
+                 << " not found";
+    return false;
+  }
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> value_message(
+      factory.GetPrototype(value_descriptor)->New());
+  std::string serialized_value = reflection->GetString(message, value_field);
+  if (!value_message->ParseFromString(serialized_value)) {
+    GOOGLE_LOG(WARNING) << type_url << ": failed to parse contents";
+    return false;
+  }
+  generator->PrintLiteral("[");
+  generator->PrintString(type_url);
+  generator->PrintLiteral("]");
+  const FastFieldValuePrinter* printer = GetFieldPrinter(value_field);
+  printer->PrintMessageStart(message, -1, 0, single_line_mode_, generator);
+  generator->Indent();
+  Print(*value_message, generator);
+  generator->Outdent();
+  printer->PrintMessageEnd(message, -1, 0, single_line_mode_, generator);
+  return true;
+}
+
+void TextFormat::Printer::Print(const Message& message,
+                                TextGenerator* generator) const {
+  const Reflection* reflection = message.GetReflection();
+  if (!reflection) {
+    // This message does not provide any way to describe its structure.
+    // Parse it again in an UnknownFieldSet, and display this instead.
+    UnknownFieldSet unknown_fields;
+    {
+      std::string serialized = message.SerializeAsString();
+      io::ArrayInputStream input(serialized.data(), serialized.size());
+      unknown_fields.ParseFromZeroCopyStream(&input);
+    }
+    PrintUnknownFields(unknown_fields, generator, kUnknownFieldRecursionLimit);
+    return;
+  }
+  const Descriptor* descriptor = message.GetDescriptor();
+  auto itr = custom_message_printers_.find(descriptor);
+  if (itr != custom_message_printers_.end()) {
+    itr->second->Print(message, single_line_mode_, generator);
+    return;
+  }
+  if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ &&
+      PrintAny(message, generator)) {
+    return;
+  }
+  std::vector<const FieldDescriptor*> fields;
+  if (descriptor->options().map_entry()) {
+    fields.push_back(descriptor->field(0));
+    fields.push_back(descriptor->field(1));
+  } else {
+    reflection->ListFieldsOmitStripped(message, &fields);
+    if (reflection->IsMessageStripped(message.GetDescriptor())) {
+      generator->Print(kDoNotParse, std::strlen(kDoNotParse));
+    }
+  }
+
+  if (print_message_fields_in_index_order_) {
+    std::sort(fields.begin(), fields.end(), FieldIndexSorter());
+  }
+  for (const FieldDescriptor* field : fields) {
+    PrintField(message, reflection, field, generator);
+  }
+  if (!hide_unknown_fields_) {
+    PrintUnknownFields(reflection->GetUnknownFields(message), generator,
+                       kUnknownFieldRecursionLimit);
+  }
+}
+
+void TextFormat::Printer::PrintFieldValueToString(const Message& message,
+                                                  const FieldDescriptor* field,
+                                                  int index,
+                                                  std::string* output) const {
+  GOOGLE_DCHECK(output) << "output specified is nullptr";
+
+  output->clear();
+  io::StringOutputStream output_stream(output);
+  TextGenerator generator(&output_stream, initial_indent_level_);
+
+  PrintFieldValue(message, message.GetReflection(), field, index, &generator);
+}
+
+class MapEntryMessageComparator {
+ public:
+  explicit MapEntryMessageComparator(const Descriptor* descriptor)
+      : field_(descriptor->field(0)) {}
+
+  bool operator()(const Message* a, const Message* b) {
+    const Reflection* reflection = a->GetReflection();
+    switch (field_->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_BOOL: {
+        bool first = reflection->GetBool(*a, field_);
+        bool second = reflection->GetBool(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT32: {
+        int32_t first = reflection->GetInt32(*a, field_);
+        int32_t second = reflection->GetInt32(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+        int64_t first = reflection->GetInt64(*a, field_);
+        int64_t second = reflection->GetInt64(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        uint32_t first = reflection->GetUInt32(*a, field_);
+        uint32_t second = reflection->GetUInt32(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        uint64_t first = reflection->GetUInt64(*a, field_);
+        uint64_t second = reflection->GetUInt64(*b, field_);
+        return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+        std::string first = reflection->GetString(*a, field_);
+        std::string second = reflection->GetString(*b, field_);
+        return first < second;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+        return true;
+    }
+  }
+
+ private:
+  const FieldDescriptor* field_;
+};
+
+namespace internal {
+class MapFieldPrinterHelper {
+ public:
+  // DynamicMapSorter::Sort cannot be used because it enforces syncing with
+  // repeated field.
+  static bool SortMap(const Message& message, const Reflection* reflection,
+                      const FieldDescriptor* field,
+                      std::vector<const Message*>* sorted_map_field);
+  static void CopyKey(const MapKey& key, Message* message,
+                      const FieldDescriptor* field_desc);
+  static void CopyValue(const MapValueRef& value, Message* message,
+                        const FieldDescriptor* field_desc);
+};
+
+// Returns true if elements contained in sorted_map_field need to be released.
+bool MapFieldPrinterHelper::SortMap(
+    const Message& message, const Reflection* reflection,
+    const FieldDescriptor* field,
+    std::vector<const Message*>* sorted_map_field) {
+  bool need_release = false;
+  const MapFieldBase& base = *reflection->GetMapData(message, field);
+
+  if (base.IsRepeatedFieldValid()) {
+    const RepeatedPtrField<Message>& map_field =
+        reflection->GetRepeatedPtrFieldInternal<Message>(message, field);
+    for (int i = 0; i < map_field.size(); ++i) {
+      sorted_map_field->push_back(
+          const_cast<RepeatedPtrField<Message>*>(&map_field)->Mutable(i));
+    }
+  } else {
+    // TODO(teboring): For performance, instead of creating map entry message
+    // for each element, just store map keys and sort them.
+    const Descriptor* map_entry_desc = field->message_type();
+    const Message* prototype =
+        reflection->GetMessageFactory()->GetPrototype(map_entry_desc);
+    for (MapIterator iter =
+             reflection->MapBegin(const_cast<Message*>(&message), field);
+         iter != reflection->MapEnd(const_cast<Message*>(&message), field);
+         ++iter) {
+      Message* map_entry_message = prototype->New();
+      CopyKey(iter.GetKey(), map_entry_message, map_entry_desc->field(0));
+      CopyValue(iter.GetValueRef(), map_entry_message,
+                map_entry_desc->field(1));
+      sorted_map_field->push_back(map_entry_message);
+    }
+    need_release = true;
+  }
+
+  MapEntryMessageComparator comparator(field->message_type());
+  std::stable_sort(sorted_map_field->begin(), sorted_map_field->end(),
+                   comparator);
+  return need_release;
+}
+
+void MapFieldPrinterHelper::CopyKey(const MapKey& key, Message* message,
+                                    const FieldDescriptor* field_desc) {
+  const Reflection* reflection = message->GetReflection();
+  switch (field_desc->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      GOOGLE_LOG(ERROR) << "Not supported.";
+      break;
+    case FieldDescriptor::CPPTYPE_STRING:
+      reflection->SetString(message, field_desc, key.GetStringValue());
+      return;
+    case FieldDescriptor::CPPTYPE_INT64:
+      reflection->SetInt64(message, field_desc, key.GetInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_INT32:
+      reflection->SetInt32(message, field_desc, key.GetInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      reflection->SetUInt64(message, field_desc, key.GetUInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      reflection->SetUInt32(message, field_desc, key.GetUInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      reflection->SetBool(message, field_desc, key.GetBoolValue());
+      return;
+  }
+}
+
+void MapFieldPrinterHelper::CopyValue(const MapValueRef& value,
+                                      Message* message,
+                                      const FieldDescriptor* field_desc) {
+  const Reflection* reflection = message->GetReflection();
+  switch (field_desc->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      reflection->SetDouble(message, field_desc, value.GetDoubleValue());
+      return;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      reflection->SetFloat(message, field_desc, value.GetFloatValue());
+      return;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      reflection->SetEnumValue(message, field_desc, value.GetEnumValue());
+      return;
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      Message* sub_message = value.GetMessageValue().New();
+      sub_message->CopyFrom(value.GetMessageValue());
+      reflection->SetAllocatedMessage(message, sub_message, field_desc);
+      return;
+    }
+    case FieldDescriptor::CPPTYPE_STRING:
+      reflection->SetString(message, field_desc, value.GetStringValue());
+      return;
+    case FieldDescriptor::CPPTYPE_INT64:
+      reflection->SetInt64(message, field_desc, value.GetInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_INT32:
+      reflection->SetInt32(message, field_desc, value.GetInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      reflection->SetUInt64(message, field_desc, value.GetUInt64Value());
+      return;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      reflection->SetUInt32(message, field_desc, value.GetUInt32Value());
+      return;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      reflection->SetBool(message, field_desc, value.GetBoolValue());
+      return;
+  }
+}
+}  // namespace internal
+
+void TextFormat::Printer::PrintField(const Message& message,
+                                     const Reflection* reflection,
+                                     const FieldDescriptor* field,
+                                     TextGenerator* generator) const {
+  if (use_short_repeated_primitives_ && field->is_repeated() &&
+      field->cpp_type() != FieldDescriptor::CPPTYPE_STRING &&
+      field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    PrintShortRepeatedField(message, reflection, field, generator);
+    return;
+  }
+
+  int count = 0;
+
+  if (field->is_repeated()) {
+    count = reflection->FieldSize(message, field);
+  } else if (reflection->HasField(message, field) ||
+             field->containing_type()->options().map_entry()) {
+    count = 1;
+  }
+
+  std::vector<const Message*> sorted_map_field;
+  bool need_release = false;
+  bool is_map = field->is_map();
+  if (is_map) {
+    need_release = internal::MapFieldPrinterHelper::SortMap(
+        message, reflection, field, &sorted_map_field);
+  }
+
+  for (int j = 0; j < count; ++j) {
+    const int field_index = field->is_repeated() ? j : -1;
+
+    PrintFieldName(message, field_index, count, reflection, field, generator);
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      const FastFieldValuePrinter* printer = GetFieldPrinter(field);
+      const Message& sub_message =
+          field->is_repeated()
+              ? (is_map ? *sorted_map_field[j]
+                        : reflection->GetRepeatedMessage(message, field, j))
+              : reflection->GetMessage(message, field);
+      printer->PrintMessageStart(sub_message, field_index, count,
+                                 single_line_mode_, generator);
+      generator->Indent();
+      if (!printer->PrintMessageContent(sub_message, field_index, count,
+                                        single_line_mode_, generator)) {
+        Print(sub_message, generator);
+      }
+      generator->Outdent();
+      printer->PrintMessageEnd(sub_message, field_index, count,
+                               single_line_mode_, generator);
+    } else {
+      generator->PrintMaybeWithMarker(": ");
+      // Write the field value.
+      PrintFieldValue(message, reflection, field, field_index, generator);
+      if (single_line_mode_) {
+        generator->PrintLiteral(" ");
+      } else {
+        generator->PrintLiteral("\n");
+      }
+    }
+  }
+
+  if (need_release) {
+    for (const Message* message_to_delete : sorted_map_field) {
+      delete message_to_delete;
+    }
+  }
+}
+
+void TextFormat::Printer::PrintShortRepeatedField(
+    const Message& message, const Reflection* reflection,
+    const FieldDescriptor* field, TextGenerator* generator) const {
+  // Print primitive repeated field in short form.
+  int size = reflection->FieldSize(message, field);
+  PrintFieldName(message, /*field_index=*/-1, /*field_count=*/size, reflection,
+                 field, generator);
+  generator->PrintMaybeWithMarker(": ", "[");
+  for (int i = 0; i < size; i++) {
+    if (i > 0) generator->PrintLiteral(", ");
+    PrintFieldValue(message, reflection, field, i, generator);
+  }
+  if (single_line_mode_) {
+    generator->PrintLiteral("] ");
+  } else {
+    generator->PrintLiteral("]\n");
+  }
+}
+
+void TextFormat::Printer::PrintFieldName(const Message& message,
+                                         int field_index, int field_count,
+                                         const Reflection* reflection,
+                                         const FieldDescriptor* field,
+                                         TextGenerator* generator) const {
+  // if use_field_number_ is true, prints field number instead
+  // of field name.
+  if (use_field_number_) {
+    generator->PrintString(StrCat(field->number()));
+    return;
+  }
+
+  const FastFieldValuePrinter* printer = GetFieldPrinter(field);
+  printer->PrintFieldName(message, field_index, field_count, reflection, field,
+                          generator);
+}
+
+void TextFormat::Printer::PrintFieldValue(const Message& message,
+                                          const Reflection* reflection,
+                                          const FieldDescriptor* field,
+                                          int index,
+                                          TextGenerator* generator) const {
+  GOOGLE_DCHECK(field->is_repeated() || (index == -1))
+      << "Index must be -1 for non-repeated fields";
+
+  const FastFieldValuePrinter* printer = GetFieldPrinter(field);
+
+  switch (field->cpp_type()) {
+#define OUTPUT_FIELD(CPPTYPE, METHOD)                                \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                           \
+    printer->Print##METHOD(                                          \
+        field->is_repeated()                                         \
+            ? reflection->GetRepeated##METHOD(message, field, index) \
+            : reflection->Get##METHOD(message, field),               \
+        generator);                                                  \
+    break
+
+    OUTPUT_FIELD(INT32, Int32);
+    OUTPUT_FIELD(INT64, Int64);
+    OUTPUT_FIELD(UINT32, UInt32);
+    OUTPUT_FIELD(UINT64, UInt64);
+    OUTPUT_FIELD(FLOAT, Float);
+    OUTPUT_FIELD(DOUBLE, Double);
+    OUTPUT_FIELD(BOOL, Bool);
+#undef OUTPUT_FIELD
+
+    case FieldDescriptor::CPPTYPE_STRING: {
+      std::string scratch;
+      const std::string& value =
+          field->is_repeated()
+              ? reflection->GetRepeatedStringReference(message, field, index,
+                                                       &scratch)
+              : reflection->GetStringReference(message, field, &scratch);
+      const std::string* value_to_print = &value;
+      std::string truncated_value;
+      if (truncate_string_field_longer_than_ > 0 &&
+          static_cast<size_t>(truncate_string_field_longer_than_) <
+              value.size()) {
+        truncated_value = value.substr(0, truncate_string_field_longer_than_) +
+                          "...<truncated>...";
+        value_to_print = &truncated_value;
+      }
+      if (field->type() == FieldDescriptor::TYPE_STRING) {
+        printer->PrintString(*value_to_print, generator);
+      } else {
+        GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
+        printer->PrintBytes(*value_to_print, generator);
+      }
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      int enum_value =
+          field->is_repeated()
+              ? reflection->GetRepeatedEnumValue(message, field, index)
+              : reflection->GetEnumValue(message, field);
+      const EnumValueDescriptor* enum_desc =
+          field->enum_type()->FindValueByNumber(enum_value);
+      if (enum_desc != nullptr) {
+        printer->PrintEnum(enum_value, enum_desc->name(), generator);
+      } else {
+        // Ordinarily, enum_desc should not be null, because proto2 has the
+        // invariant that set enum field values must be in-range, but with the
+        // new integer-based API for enums (or the RepeatedField<int> loophole),
+        // it is possible for the user to force an unknown integer value.  So we
+        // simply use the integer value itself as the enum value name in this
+        // case.
+        printer->PrintEnum(enum_value, StrCat(enum_value), generator);
+      }
+      break;
+    }
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      Print(field->is_repeated()
+                ? reflection->GetRepeatedMessage(message, field, index)
+                : reflection->GetMessage(message, field),
+            generator);
+      break;
+  }
+}
+
+/* static */ bool TextFormat::Print(const Message& message,
+                                    io::ZeroCopyOutputStream* output) {
+  return Printer().Print(message, output);
+}
+
+/* static */ bool TextFormat::PrintUnknownFields(
+    const UnknownFieldSet& unknown_fields, io::ZeroCopyOutputStream* output) {
+  return Printer().PrintUnknownFields(unknown_fields, output);
+}
+
+/* static */ bool TextFormat::PrintToString(const Message& message,
+                                            std::string* output) {
+  return Printer().PrintToString(message, output);
+}
+
+/* static */ bool TextFormat::PrintUnknownFieldsToString(
+    const UnknownFieldSet& unknown_fields, std::string* output) {
+  return Printer().PrintUnknownFieldsToString(unknown_fields, output);
+}
+
+/* static */ void TextFormat::PrintFieldValueToString(
+    const Message& message, const FieldDescriptor* field, int index,
+    std::string* output) {
+  return Printer().PrintFieldValueToString(message, field, index, output);
+}
+
+/* static */ bool TextFormat::ParseFieldValueFromString(
+    const std::string& input, const FieldDescriptor* field, Message* message) {
+  return Parser().ParseFieldValueFromString(input, field, message);
+}
+
+void TextFormat::Printer::PrintUnknownFields(
+    const UnknownFieldSet& unknown_fields, TextGenerator* generator,
+    int recursion_budget) const {
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+    std::string field_number = StrCat(field.number());
+
+    switch (field.type()) {
+      case UnknownField::TYPE_VARINT:
+        generator->PrintString(field_number);
+        generator->PrintMaybeWithMarker(": ");
+        generator->PrintString(StrCat(field.varint()));
+        if (single_line_mode_) {
+          generator->PrintLiteral(" ");
+        } else {
+          generator->PrintLiteral("\n");
+        }
+        break;
+      case UnknownField::TYPE_FIXED32: {
+        generator->PrintString(field_number);
+        generator->PrintMaybeWithMarker(": ", "0x");
+        generator->PrintString(
+            StrCat(strings::Hex(field.fixed32(), strings::ZERO_PAD_8)));
+        if (single_line_mode_) {
+          generator->PrintLiteral(" ");
+        } else {
+          generator->PrintLiteral("\n");
+        }
+        break;
+      }
+      case UnknownField::TYPE_FIXED64: {
+        generator->PrintString(field_number);
+        generator->PrintMaybeWithMarker(": ", "0x");
+        generator->PrintString(
+            StrCat(strings::Hex(field.fixed64(), strings::ZERO_PAD_16)));
+        if (single_line_mode_) {
+          generator->PrintLiteral(" ");
+        } else {
+          generator->PrintLiteral("\n");
+        }
+        break;
+      }
+      case UnknownField::TYPE_LENGTH_DELIMITED: {
+        generator->PrintString(field_number);
+        const std::string& value = field.length_delimited();
+        // We create a CodedInputStream so that we can adhere to our recursion
+        // budget when we attempt to parse the data. UnknownFieldSet parsing is
+        // recursive because of groups.
+        io::CodedInputStream input_stream(
+            reinterpret_cast<const uint8_t*>(value.data()), value.size());
+        input_stream.SetRecursionLimit(recursion_budget);
+        UnknownFieldSet embedded_unknown_fields;
+        if (!value.empty() && recursion_budget > 0 &&
+            embedded_unknown_fields.ParseFromCodedStream(&input_stream)) {
+          // This field is parseable as a Message.
+          // So it is probably an embedded message.
+          if (single_line_mode_) {
+            generator->PrintMaybeWithMarker(" ", "{ ");
+          } else {
+            generator->PrintMaybeWithMarker(" ", "{\n");
+            generator->Indent();
+          }
+          PrintUnknownFields(embedded_unknown_fields, generator,
+                             recursion_budget - 1);
+          if (single_line_mode_) {
+            generator->PrintLiteral("} ");
+          } else {
+            generator->Outdent();
+            generator->PrintLiteral("}\n");
+          }
+        } else {
+          // This field is not parseable as a Message (or we ran out of
+          // recursion budget). So it is probably just a plain string.
+          generator->PrintMaybeWithMarker(": ", "\"");
+          generator->PrintString(CEscape(value));
+          if (single_line_mode_) {
+            generator->PrintLiteral("\" ");
+          } else {
+            generator->PrintLiteral("\"\n");
+          }
+        }
+        break;
+      }
+      case UnknownField::TYPE_GROUP:
+        generator->PrintString(field_number);
+        if (single_line_mode_) {
+          generator->PrintMaybeWithMarker(" ", "{ ");
+        } else {
+          generator->PrintMaybeWithMarker(" ", "{\n");
+          generator->Indent();
+        }
+        // For groups, we recurse without checking the budget. This is OK,
+        // because if the groups were too deeply nested then we would have
+        // already rejected the message when we originally parsed it.
+        PrintUnknownFields(field.group(), generator, recursion_budget - 1);
+        if (single_line_mode_) {
+          generator->PrintLiteral("} ");
+        } else {
+          generator->Outdent();
+          generator->PrintLiteral("}\n");
+        }
+        break;
+    }
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/timestamp.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/timestamp.pb.cpp
new file mode 100644
index 0000000..728a004
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/timestamp.pb.cpp
@@ -0,0 +1,307 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#include <google/protobuf/timestamp.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Timestamp::Timestamp(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.seconds_)*/int64_t{0}
+  , /*decltype(_impl_.nanos_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct TimestampDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR TimestampDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~TimestampDefaultTypeInternal() {}
+  union {
+    Timestamp _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 TimestampDefaultTypeInternal _Timestamp_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, _impl_.seconds_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, _impl_.nanos_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Timestamp)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Timestamp_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\037google/protobuf/timestamp.proto\022\017googl"
+  "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
+  "\022\r\n\005nanos\030\002 \001(\005B\205\001\n\023com.google.protobufB"
+  "\016TimestampProtoP\001Z2google.golang.org/pro"
+  "tobuf/types/known/timestamppb\370\001\001\242\002\003GPB\252\002"
+  "\036Google.Protobuf.WellKnownTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
+    false, false, 239, descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto,
+    "google/protobuf/timestamp.proto",
+    &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftimestamp_2eproto(&descriptor_table_google_2fprotobuf_2ftimestamp_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class Timestamp::_Internal {
+ public:
+};
+
+Timestamp::Timestamp(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp)
+}
+Timestamp::Timestamp(const Timestamp& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Timestamp* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){}
+    , decltype(_impl_.nanos_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  ::memcpy(&_impl_.seconds_, &from._impl_.seconds_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.nanos_) -
+    reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Timestamp)
+}
+
+inline void Timestamp::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.seconds_){int64_t{0}}
+    , decltype(_impl_.nanos_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Timestamp::~Timestamp() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Timestamp)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Timestamp::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Timestamp::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Timestamp::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Timestamp)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  ::memset(&_impl_.seconds_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.nanos_) -
+      reinterpret_cast<char*>(&_impl_.seconds_)) + sizeof(_impl_.nanos_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Timestamp::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int64 seconds = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.seconds_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 nanos = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _impl_.nanos_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Timestamp::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Timestamp)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Timestamp)
+  return target;
+}
+
+size_t Timestamp::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Timestamp)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int64 seconds = 1;
+  if (this->_internal_seconds() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
+  }
+
+  // int32 nanos = 2;
+  if (this->_internal_nanos() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Timestamp::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Timestamp::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Timestamp::GetClassData() const { return &_class_data_; }
+
+
+void Timestamp::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Timestamp*>(&to_msg);
+  auto& from = static_cast<const Timestamp&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Timestamp)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_seconds() != 0) {
+    _this->_internal_set_seconds(from._internal_seconds());
+  }
+  if (from._internal_nanos() != 0) {
+    _this->_internal_set_nanos(from._internal_nanos());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Timestamp::CopyFrom(const Timestamp& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Timestamp)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Timestamp::IsInitialized() const {
+  return true;
+}
+
+void Timestamp::InternalSwap(Timestamp* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Timestamp, _impl_.nanos_)
+      + sizeof(Timestamp::_impl_.nanos_)
+      - PROTOBUF_FIELD_OFFSET(Timestamp, _impl_.seconds_)>(
+          reinterpret_cast<char*>(&_impl_.seconds_),
+          reinterpret_cast<char*>(&other->_impl_.seconds_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Timestamp::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Timestamp*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Timestamp >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Timestamp >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/type.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/type.pb.cpp
new file mode 100644
index 0000000..e29bbb8
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/type.pb.cpp
@@ -0,0 +1,2157 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#include <google/protobuf/type.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR Type::Type(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.fields_)*/{}
+  , /*decltype(_impl_.oneofs_)*/{}
+  , /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.source_context_)*/nullptr
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct TypeDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR TypeDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~TypeDefaultTypeInternal() {}
+  union {
+    Type _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 TypeDefaultTypeInternal _Type_default_instance_;
+PROTOBUF_CONSTEXPR Field::Field(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.json_name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.default_value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.kind_)*/0
+  , /*decltype(_impl_.cardinality_)*/0
+  , /*decltype(_impl_.number_)*/0
+  , /*decltype(_impl_.oneof_index_)*/0
+  , /*decltype(_impl_.packed_)*/false
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FieldDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FieldDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FieldDefaultTypeInternal() {}
+  union {
+    Field _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldDefaultTypeInternal _Field_default_instance_;
+PROTOBUF_CONSTEXPR Enum::Enum(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.enumvalue_)*/{}
+  , /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.source_context_)*/nullptr
+  , /*decltype(_impl_.syntax_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct EnumDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumDefaultTypeInternal() {}
+  union {
+    Enum _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDefaultTypeInternal _Enum_default_instance_;
+PROTOBUF_CONSTEXPR EnumValue::EnumValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.options_)*/{}
+  , /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.number_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct EnumValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR EnumValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~EnumValueDefaultTypeInternal() {}
+  union {
+    EnumValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueDefaultTypeInternal _EnumValue_default_instance_;
+PROTOBUF_CONSTEXPR Option::Option(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_.value_)*/nullptr
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct OptionDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR OptionDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~OptionDefaultTypeInternal() {}
+  union {
+    Option _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OptionDefaultTypeInternal _Option_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ftype_2eproto[5];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[3];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2ftype_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.fields_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.oneofs_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.source_context_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.kind_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.cardinality_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.type_url_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.oneof_index_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.packed_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.json_name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _impl_.default_value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.enumvalue_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.options_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.source_context_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.syntax_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _impl_.number_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _impl_.options_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, _impl_.name_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, _impl_.value_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Type)},
+  { 12, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Field)},
+  { 28, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Enum)},
+  { 39, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValue)},
+  { 48, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Option)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Type_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Field_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Enum_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Option_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\032google/protobuf/type.proto\022\017google.pro"
+  "tobuf\032\031google/protobuf/any.proto\032$google"
+  "/protobuf/source_context.proto\"\327\001\n\004Type\022"
+  "\014\n\004name\030\001 \001(\t\022&\n\006fields\030\002 \003(\0132\026.google.p"
+  "rotobuf.Field\022\016\n\006oneofs\030\003 \003(\t\022(\n\007options"
+  "\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc"
+  "e_context\030\005 \001(\0132\036.google.protobuf.Source"
+  "Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu"
+  "f.Syntax\"\325\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
+  "e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001"
+  "(\0162\".google.protobuf.Field.Cardinality\022\016"
+  "\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url"
+  "\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 "
+  "\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O"
+  "ption\022\021\n\tjson_name\030\n \001(\t\022\025\n\rdefault_valu"
+  "e\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TY"
+  "PE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT6"
+  "4\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014"
+  "TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE"
+  "_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n"
+  "\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TY"
+  "PE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXE"
+  "D32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020"
+  "\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013Cardinality\022\027\n\023CAR"
+  "DINALITY_UNKNOWN\020\000\022\030\n\024CARDINALITY_OPTION"
+  "AL\020\001\022\030\n\024CARDINALITY_REQUIRED\020\002\022\030\n\024CARDIN"
+  "ALITY_REPEATED\020\003\"\316\001\n\004Enum\022\014\n\004name\030\001 \001(\t\022"
+  "-\n\tenumvalue\030\002 \003(\0132\032.google.protobuf.Enu"
+  "mValue\022(\n\007options\030\003 \003(\0132\027.google.protobu"
+  "f.Option\0226\n\016source_context\030\004 \001(\0132\036.googl"
+  "e.protobuf.SourceContext\022\'\n\006syntax\030\005 \001(\016"
+  "2\027.google.protobuf.Syntax\"S\n\tEnumValue\022\014"
+  "\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030"
+  "\003 \003(\0132\027.google.protobuf.Option\";\n\006Option"
+  "\022\014\n\004name\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.p"
+  "rotobuf.Any*.\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000"
+  "\022\021\n\rSYNTAX_PROTO3\020\001B{\n\023com.google.protob"
+  "ufB\tTypeProtoP\001Z-google.golang.org/proto"
+  "buf/types/known/typepb\370\001\001\242\002\003GPB\252\002\036Google"
+  ".Protobuf.WellKnownTypesb\006proto3"
+  ;
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2ftype_2eproto_deps[2] = {
+  &::descriptor_table_google_2fprotobuf_2fany_2eproto,
+  &::descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto,
+};
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ftype_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
+    false, false, 1592, descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
+    "google/protobuf/type.proto",
+    &descriptor_table_google_2fprotobuf_2ftype_2eproto_once, descriptor_table_google_2fprotobuf_2ftype_2eproto_deps, 2, 5,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftype_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ftype_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ftype_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2ftype_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftype_2eproto(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Kind_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[0];
+}
+bool Field_Kind_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+    case 18:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr Field_Kind Field::TYPE_UNKNOWN;
+constexpr Field_Kind Field::TYPE_DOUBLE;
+constexpr Field_Kind Field::TYPE_FLOAT;
+constexpr Field_Kind Field::TYPE_INT64;
+constexpr Field_Kind Field::TYPE_UINT64;
+constexpr Field_Kind Field::TYPE_INT32;
+constexpr Field_Kind Field::TYPE_FIXED64;
+constexpr Field_Kind Field::TYPE_FIXED32;
+constexpr Field_Kind Field::TYPE_BOOL;
+constexpr Field_Kind Field::TYPE_STRING;
+constexpr Field_Kind Field::TYPE_GROUP;
+constexpr Field_Kind Field::TYPE_MESSAGE;
+constexpr Field_Kind Field::TYPE_BYTES;
+constexpr Field_Kind Field::TYPE_UINT32;
+constexpr Field_Kind Field::TYPE_ENUM;
+constexpr Field_Kind Field::TYPE_SFIXED32;
+constexpr Field_Kind Field::TYPE_SFIXED64;
+constexpr Field_Kind Field::TYPE_SINT32;
+constexpr Field_Kind Field::TYPE_SINT64;
+constexpr Field_Kind Field::Kind_MIN;
+constexpr Field_Kind Field::Kind_MAX;
+constexpr int Field::Kind_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Cardinality_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[1];
+}
+bool Field_Cardinality_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+constexpr Field_Cardinality Field::CARDINALITY_UNKNOWN;
+constexpr Field_Cardinality Field::CARDINALITY_OPTIONAL;
+constexpr Field_Cardinality Field::CARDINALITY_REQUIRED;
+constexpr Field_Cardinality Field::CARDINALITY_REPEATED;
+constexpr Field_Cardinality Field::Cardinality_MIN;
+constexpr Field_Cardinality Field::Cardinality_MAX;
+constexpr int Field::Cardinality_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
+const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Syntax_descriptor() {
+  ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+  return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[2];
+}
+bool Syntax_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// ===================================================================
+
+class Type::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context(const Type* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::SourceContext&
+Type::_Internal::source_context(const Type* msg) {
+  return *msg->_impl_.source_context_;
+}
+void Type::clear_source_context() {
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+}
+Type::Type(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Type)
+}
+Type::Type(const Type& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Type* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.fields_){from._impl_.fields_}
+    , decltype(_impl_.oneofs_){from._impl_.oneofs_}
+    , decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
+  }
+  _this->_impl_.syntax_ = from._impl_.syntax_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Type)
+}
+
+inline void Type::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.fields_){arena}
+    , decltype(_impl_.oneofs_){arena}
+    , decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Type::~Type() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Type)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Type::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.fields_.~RepeatedPtrField();
+  _impl_.oneofs_.~RepeatedPtrField();
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.source_context_;
+}
+
+void Type::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Type::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Type)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.fields_.Clear();
+  _impl_.oneofs_.Clear();
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+  _impl_.syntax_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Type::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Field fields = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_fields(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated string oneofs = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            auto str = _internal_add_oneofs();
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+            CHK_(ptr);
+            CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.oneofs"));
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<34>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.SourceContext source_context = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 48)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Type::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.Field fields = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_fields_size()); i < n; i++) {
+    const auto& repfield = this->_internal_fields(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated string oneofs = 3;
+  for (int i = 0, n = this->_internal_oneofs_size(); i < n; i++) {
+    const auto& s = this->_internal_oneofs(i);
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      s.data(), static_cast<int>(s.length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.oneofs");
+    target = stream->WriteString(3, s, target);
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(5, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 6;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      6, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Type)
+  return target;
+}
+
+size_t Type::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Type)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Field fields = 2;
+  total_size += 1UL * this->_internal_fields_size();
+  for (const auto& msg : this->_impl_.fields_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated string oneofs = 3;
+  total_size += 1 *
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(_impl_.oneofs_.size());
+  for (int i = 0, n = _impl_.oneofs_.size(); i < n; i++) {
+    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+      _impl_.oneofs_.Get(i));
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // .google.protobuf.SourceContext source_context = 5;
+  if (this->_internal_has_source_context()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.source_context_);
+  }
+
+  // .google.protobuf.Syntax syntax = 6;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Type::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Type::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Type::GetClassData() const { return &_class_data_; }
+
+
+void Type::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Type*>(&to_msg);
+  auto& from = static_cast<const Type&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Type)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.fields_.MergeFrom(from._impl_.fields_);
+  _this->_impl_.oneofs_.MergeFrom(from._impl_.oneofs_);
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
+        from._internal_source_context());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Type::CopyFrom(const Type& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Type)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Type::IsInitialized() const {
+  return true;
+}
+
+void Type::InternalSwap(Type* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.fields_.InternalSwap(&other->_impl_.fields_);
+  _impl_.oneofs_.InternalSwap(&other->_impl_.oneofs_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Type, _impl_.syntax_)
+      + sizeof(Type::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Type, _impl_.source_context_)>(
+          reinterpret_cast<char*>(&_impl_.source_context_),
+          reinterpret_cast<char*>(&other->_impl_.source_context_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Type::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[0]);
+}
+
+// ===================================================================
+
+class Field::_Internal {
+ public:
+};
+
+Field::Field(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Field)
+}
+Field::Field(const Field& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Field* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.type_url_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.kind_){}
+    , decltype(_impl_.cardinality_){}
+    , decltype(_impl_.number_){}
+    , decltype(_impl_.oneof_index_){}
+    , decltype(_impl_.packed_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_type_url().empty()) {
+    _this->_impl_.type_url_.Set(from._internal_type_url(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_json_name().empty()) {
+    _this->_impl_.json_name_.Set(from._internal_json_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_default_value().empty()) {
+    _this->_impl_.default_value_.Set(from._internal_default_value(), 
+      _this->GetArenaForAllocation());
+  }
+  ::memcpy(&_impl_.kind_, &from._impl_.kind_,
+    static_cast<size_t>(reinterpret_cast<char*>(&_impl_.packed_) -
+    reinterpret_cast<char*>(&_impl_.kind_)) + sizeof(_impl_.packed_));
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Field)
+}
+
+inline void Field::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.type_url_){}
+    , decltype(_impl_.json_name_){}
+    , decltype(_impl_.default_value_){}
+    , decltype(_impl_.kind_){0}
+    , decltype(_impl_.cardinality_){0}
+    , decltype(_impl_.number_){0}
+    , decltype(_impl_.oneof_index_){0}
+    , decltype(_impl_.packed_){false}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.type_url_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.type_url_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.json_name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.json_name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  _impl_.default_value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.default_value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Field::~Field() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Field)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Field::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  _impl_.type_url_.Destroy();
+  _impl_.json_name_.Destroy();
+  _impl_.default_value_.Destroy();
+}
+
+void Field::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Field::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Field)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.type_url_.ClearToEmpty();
+  _impl_.json_name_.ClearToEmpty();
+  _impl_.default_value_.ClearToEmpty();
+  ::memset(&_impl_.kind_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&_impl_.packed_) -
+      reinterpret_cast<char*>(&_impl_.kind_)) + sizeof(_impl_.packed_));
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Field::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // .google.protobuf.Field.Kind kind = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_kind(static_cast<::PROTOBUF_NAMESPACE_ID::Field_Kind>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Field.Cardinality cardinality = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_cardinality(static_cast<::PROTOBUF_NAMESPACE_ID::Field_Cardinality>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 number = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 24)) {
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // string name = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string type_url = 6;
+      case 6:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
+          auto str = _internal_mutable_type_url();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.type_url"));
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 oneof_index = 7;
+      case 7:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 56)) {
+          _impl_.oneof_index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // bool packed = 8;
+      case 8:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 64)) {
+          _impl_.packed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 9;
+      case 9:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<74>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // string json_name = 10;
+      case 10:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
+          auto str = _internal_mutable_json_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.json_name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // string default_value = 11;
+      case 11:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 90)) {
+          auto str = _internal_mutable_default_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.default_value"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Field::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Field)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // .google.protobuf.Field.Kind kind = 1;
+  if (this->_internal_kind() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      1, this->_internal_kind(), target);
+  }
+
+  // .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->_internal_cardinality() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      2, this->_internal_cardinality(), target);
+  }
+
+  // int32 number = 3;
+  if (this->_internal_number() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
+  }
+
+  // string name = 4;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.name");
+    target = stream->WriteStringMaybeAliased(
+        4, this->_internal_name(), target);
+  }
+
+  // string type_url = 6;
+  if (!this->_internal_type_url().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.type_url");
+    target = stream->WriteStringMaybeAliased(
+        6, this->_internal_type_url(), target);
+  }
+
+  // int32 oneof_index = 7;
+  if (this->_internal_oneof_index() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(7, this->_internal_oneof_index(), target);
+  }
+
+  // bool packed = 8;
+  if (this->_internal_packed() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(8, this->_internal_packed(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 9;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(9, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // string json_name = 10;
+  if (!this->_internal_json_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_json_name().data(), static_cast<int>(this->_internal_json_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.json_name");
+    target = stream->WriteStringMaybeAliased(
+        10, this->_internal_json_name(), target);
+  }
+
+  // string default_value = 11;
+  if (!this->_internal_default_value().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_default_value().data(), static_cast<int>(this->_internal_default_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.default_value");
+    target = stream->WriteStringMaybeAliased(
+        11, this->_internal_default_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
+  return target;
+}
+
+size_t Field::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Field)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Option options = 9;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 4;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // string type_url = 6;
+  if (!this->_internal_type_url().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_type_url());
+  }
+
+  // string json_name = 10;
+  if (!this->_internal_json_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_json_name());
+  }
+
+  // string default_value = 11;
+  if (!this->_internal_default_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_default_value());
+  }
+
+  // .google.protobuf.Field.Kind kind = 1;
+  if (this->_internal_kind() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_kind());
+  }
+
+  // .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->_internal_cardinality() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_cardinality());
+  }
+
+  // int32 number = 3;
+  if (this->_internal_number() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+  }
+
+  // int32 oneof_index = 7;
+  if (this->_internal_oneof_index() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
+  }
+
+  // bool packed = 8;
+  if (this->_internal_packed() != 0) {
+    total_size += 1 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Field::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Field::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Field::GetClassData() const { return &_class_data_; }
+
+
+void Field::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Field*>(&to_msg);
+  auto& from = static_cast<const Field&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Field)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (!from._internal_type_url().empty()) {
+    _this->_internal_set_type_url(from._internal_type_url());
+  }
+  if (!from._internal_json_name().empty()) {
+    _this->_internal_set_json_name(from._internal_json_name());
+  }
+  if (!from._internal_default_value().empty()) {
+    _this->_internal_set_default_value(from._internal_default_value());
+  }
+  if (from._internal_kind() != 0) {
+    _this->_internal_set_kind(from._internal_kind());
+  }
+  if (from._internal_cardinality() != 0) {
+    _this->_internal_set_cardinality(from._internal_cardinality());
+  }
+  if (from._internal_number() != 0) {
+    _this->_internal_set_number(from._internal_number());
+  }
+  if (from._internal_oneof_index() != 0) {
+    _this->_internal_set_oneof_index(from._internal_oneof_index());
+  }
+  if (from._internal_packed() != 0) {
+    _this->_internal_set_packed(from._internal_packed());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Field::CopyFrom(const Field& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Field)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Field::IsInitialized() const {
+  return true;
+}
+
+void Field::InternalSwap(Field* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.type_url_, lhs_arena,
+      &other->_impl_.type_url_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.json_name_, lhs_arena,
+      &other->_impl_.json_name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.default_value_, lhs_arena,
+      &other->_impl_.default_value_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Field, _impl_.packed_)
+      + sizeof(Field::_impl_.packed_)
+      - PROTOBUF_FIELD_OFFSET(Field, _impl_.kind_)>(
+          reinterpret_cast<char*>(&_impl_.kind_),
+          reinterpret_cast<char*>(&other->_impl_.kind_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Field::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[1]);
+}
+
+// ===================================================================
+
+class Enum::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::SourceContext& source_context(const Enum* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::SourceContext&
+Enum::_Internal::source_context(const Enum* msg) {
+  return *msg->_impl_.source_context_;
+}
+void Enum::clear_source_context() {
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+}
+Enum::Enum(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Enum)
+}
+Enum::Enum(const Enum& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Enum* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.enumvalue_){from._impl_.enumvalue_}
+    , decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
+  }
+  _this->_impl_.syntax_ = from._impl_.syntax_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Enum)
+}
+
+inline void Enum::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.enumvalue_){arena}
+    , decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.source_context_){nullptr}
+    , decltype(_impl_.syntax_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Enum::~Enum() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Enum)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Enum::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.enumvalue_.~RepeatedPtrField();
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.source_context_;
+}
+
+void Enum::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Enum::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Enum)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.enumvalue_.Clear();
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
+    delete _impl_.source_context_;
+  }
+  _impl_.source_context_ = nullptr;
+  _impl_.syntax_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Enum::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Enum.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.EnumValue enumvalue = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_enumvalue(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.SourceContext source_context = 4;
+      case 4:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
+          ptr = ctx->ParseMessage(_internal_mutable_source_context(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Syntax syntax = 5;
+      case 5:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
+          uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+          _internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Enum::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Enum.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enumvalue_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enumvalue(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.SourceContext source_context = 4;
+  if (this->_internal_has_source_context()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(4, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
+  }
+
+  // .google.protobuf.Syntax syntax = 5;
+  if (this->_internal_syntax() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
+      5, this->_internal_syntax(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Enum)
+  return target;
+}
+
+size_t Enum::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Enum)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  total_size += 1UL * this->_internal_enumvalue_size();
+  for (const auto& msg : this->_impl_.enumvalue_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // .google.protobuf.SourceContext source_context = 4;
+  if (this->_internal_has_source_context()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.source_context_);
+  }
+
+  // .google.protobuf.Syntax syntax = 5;
+  if (this->_internal_syntax() != 0) {
+    total_size += 1 +
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Enum::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Enum::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Enum::GetClassData() const { return &_class_data_; }
+
+
+void Enum::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Enum*>(&to_msg);
+  auto& from = static_cast<const Enum&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Enum)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.enumvalue_.MergeFrom(from._impl_.enumvalue_);
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_has_source_context()) {
+    _this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
+        from._internal_source_context());
+  }
+  if (from._internal_syntax() != 0) {
+    _this->_internal_set_syntax(from._internal_syntax());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Enum::CopyFrom(const Enum& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Enum)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Enum::IsInitialized() const {
+  return true;
+}
+
+void Enum::InternalSwap(Enum* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.enumvalue_.InternalSwap(&other->_impl_.enumvalue_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  ::PROTOBUF_NAMESPACE_ID::internal::memswap<
+      PROTOBUF_FIELD_OFFSET(Enum, _impl_.syntax_)
+      + sizeof(Enum::_impl_.syntax_)
+      - PROTOBUF_FIELD_OFFSET(Enum, _impl_.source_context_)>(
+          reinterpret_cast<char*>(&_impl_.source_context_),
+          reinterpret_cast<char*>(&other->_impl_.source_context_));
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Enum::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[2]);
+}
+
+// ===================================================================
+
+class EnumValue::_Internal {
+ public:
+};
+
+EnumValue::EnumValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValue)
+}
+EnumValue::EnumValue(const EnumValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  EnumValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){from._impl_.options_}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.number_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  _this->_impl_.number_ = from._impl_.number_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValue)
+}
+
+inline void EnumValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.options_){arena}
+    , decltype(_impl_.name_){}
+    , decltype(_impl_.number_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+EnumValue::~EnumValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void EnumValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.options_.~RepeatedPtrField();
+  _impl_.name_.Destroy();
+}
+
+void EnumValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void EnumValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.options_.Clear();
+  _impl_.name_.ClearToEmpty();
+  _impl_.number_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* EnumValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.EnumValue.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // int32 number = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 16)) {
+          _impl_.number_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      // repeated .google.protobuf.Option options = 3;
+      case 3:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
+          ptr -= 1;
+          do {
+            ptr += 1;
+            ptr = ctx->ParseMessage(_internal_add_options(), ptr);
+            CHK_(ptr);
+            if (!ctx->DataAvailable(ptr)) break;
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* EnumValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.EnumValue.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // int32 number = 2;
+  if (this->_internal_number() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
+  return target;
+}
+
+size_t EnumValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1UL * this->_internal_options_size();
+  for (const auto& msg : this->_impl_.options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
+  }
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // int32 number = 2;
+  if (this->_internal_number() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData EnumValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    EnumValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValue::GetClassData() const { return &_class_data_; }
+
+
+void EnumValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<EnumValue*>(&to_msg);
+  auto& from = static_cast<const EnumValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  _this->_impl_.options_.MergeFrom(from._impl_.options_);
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_number() != 0) {
+    _this->_internal_set_number(from._internal_number());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void EnumValue::CopyFrom(const EnumValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValue::IsInitialized() const {
+  return true;
+}
+
+void EnumValue::InternalSwap(EnumValue* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  _impl_.options_.InternalSwap(&other->_impl_.options_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.number_, other->_impl_.number_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata EnumValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[3]);
+}
+
+// ===================================================================
+
+class Option::_Internal {
+ public:
+  static const ::PROTOBUF_NAMESPACE_ID::Any& value(const Option* msg);
+};
+
+const ::PROTOBUF_NAMESPACE_ID::Any&
+Option::_Internal::value(const Option* msg) {
+  return *msg->_impl_.value_;
+}
+void Option::clear_value() {
+  if (GetArenaForAllocation() == nullptr && _impl_.value_ != nullptr) {
+    delete _impl_.value_;
+  }
+  _impl_.value_ = nullptr;
+}
+Option::Option(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Option)
+}
+Option::Option(const Option& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Option* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.value_){nullptr}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_name().empty()) {
+    _this->_impl_.name_.Set(from._internal_name(), 
+      _this->GetArenaForAllocation());
+  }
+  if (from._internal_has_value()) {
+    _this->_impl_.value_ = new ::PROTOBUF_NAMESPACE_ID::Any(*from._impl_.value_);
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Option)
+}
+
+inline void Option::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.name_){}
+    , decltype(_impl_.value_){nullptr}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.name_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.name_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+Option::~Option() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Option)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Option::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.name_.Destroy();
+  if (this != internal_default_instance()) delete _impl_.value_;
+}
+
+void Option::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Option::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Option)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.name_.ClearToEmpty();
+  if (GetArenaForAllocation() == nullptr && _impl_.value_ != nullptr) {
+    delete _impl_.value_;
+  }
+  _impl_.value_ = nullptr;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Option::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string name = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_name();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Option.name"));
+        } else
+          goto handle_unusual;
+        continue;
+      // .google.protobuf.Any value = 2;
+      case 2:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
+          ptr = ctx->ParseMessage(_internal_mutable_value(), ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Option::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Option.name");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_name(), target);
+  }
+
+  // .google.protobuf.Any value = 2;
+  if (this->_internal_has_value()) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+      InternalWriteMessage(2, _Internal::value(this),
+        _Internal::value(this).GetCachedSize(), target, stream);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
+  return target;
+}
+
+size_t Option::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Option)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string name = 1;
+  if (!this->_internal_name().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_name());
+  }
+
+  // .google.protobuf.Any value = 2;
+  if (this->_internal_has_value()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
+        *_impl_.value_);
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Option::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Option::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Option::GetClassData() const { return &_class_data_; }
+
+
+void Option::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Option*>(&to_msg);
+  auto& from = static_cast<const Option&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Option)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_name().empty()) {
+    _this->_internal_set_name(from._internal_name());
+  }
+  if (from._internal_has_value()) {
+    _this->_internal_mutable_value()->::PROTOBUF_NAMESPACE_ID::Any::MergeFrom(
+        from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Option::CopyFrom(const Option& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Option)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Option::IsInitialized() const {
+  return true;
+}
+
+void Option::InternalSwap(Option* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.name_, lhs_arena,
+      &other->_impl_.name_, rhs_arena
+  );
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Option::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2ftype_2eproto[4]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Type*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Type >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Type >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Field*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Field >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Field >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Enum*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Enum >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Enum >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Option*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Option >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Option >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/unknown_field_set.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/unknown_field_set.cpp
new file mode 100644
index 0000000..74c358e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/unknown_field_set.cpp
@@ -0,0 +1,350 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/unknown_field_set.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_tctable_decl.h>
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+const UnknownFieldSet& UnknownFieldSet::default_instance() {
+  static auto instance = internal::OnShutdownDelete(new UnknownFieldSet());
+  return *instance;
+}
+
+void UnknownFieldSet::ClearFallback() {
+  GOOGLE_DCHECK(!fields_.empty());
+  int n = fields_.size();
+  do {
+    (fields_)[--n].Delete();
+  } while (n > 0);
+  fields_.clear();
+}
+
+void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) {
+  int other_field_count = other.field_count();
+  if (other_field_count > 0) {
+    fields_.reserve(fields_.size() + other_field_count);
+    for (int i = 0; i < other_field_count; i++) {
+      fields_.push_back((other.fields_)[i]);
+      fields_.back().DeepCopy((other.fields_)[i]);
+    }
+  }
+}
+
+void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
+  int other_field_count = other.field_count();
+  if (other_field_count > 0) {
+    fields_.reserve(fields_.size() + other_field_count);
+    for (int i = 0; i < other_field_count; i++) {
+      fields_.push_back((other.fields_)[i]);
+      fields_.back().DeepCopy((other.fields_)[i]);
+    }
+  }
+}
+
+// A specialized MergeFrom for performance when we are merging from an UFS that
+// is temporary and can be destroyed in the process.
+void UnknownFieldSet::MergeFromAndDestroy(UnknownFieldSet* other) {
+  if (fields_.empty()) {
+    fields_ = std::move(other->fields_);
+  } else {
+    fields_.insert(fields_.end(),
+                   std::make_move_iterator(other->fields_.begin()),
+                   std::make_move_iterator(other->fields_.end()));
+  }
+  other->fields_.clear();
+}
+
+void UnknownFieldSet::MergeToInternalMetadata(
+    const UnknownFieldSet& other, internal::InternalMetadata* metadata) {
+  metadata->mutable_unknown_fields<UnknownFieldSet>()->MergeFrom(other);
+}
+
+size_t UnknownFieldSet::SpaceUsedExcludingSelfLong() const {
+  if (fields_.empty()) return 0;
+
+  size_t total_size = sizeof(UnknownField) * fields_.capacity();
+
+  for (const UnknownField& field : fields_) {
+    switch (field.type()) {
+      case UnknownField::TYPE_LENGTH_DELIMITED:
+        total_size += sizeof(*field.data_.length_delimited_.string_value) +
+                      internal::StringSpaceUsedExcludingSelfLong(
+                          *field.data_.length_delimited_.string_value);
+        break;
+      case UnknownField::TYPE_GROUP:
+        total_size += field.data_.group_->SpaceUsedLong();
+        break;
+      default:
+        break;
+    }
+  }
+  return total_size;
+}
+
+size_t UnknownFieldSet::SpaceUsedLong() const {
+  return sizeof(*this) + SpaceUsedExcludingSelf();
+}
+
+void UnknownFieldSet::AddVarint(int number, uint64_t value) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_VARINT);
+  field.data_.varint_ = value;
+  fields_.push_back(field);
+}
+
+void UnknownFieldSet::AddFixed32(int number, uint32_t value) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_FIXED32);
+  field.data_.fixed32_ = value;
+  fields_.push_back(field);
+}
+
+void UnknownFieldSet::AddFixed64(int number, uint64_t value) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_FIXED64);
+  field.data_.fixed64_ = value;
+  fields_.push_back(field);
+}
+
+std::string* UnknownFieldSet::AddLengthDelimited(int number) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_LENGTH_DELIMITED);
+  field.data_.length_delimited_.string_value = new std::string;
+  fields_.push_back(field);
+  return field.data_.length_delimited_.string_value;
+}
+
+
+UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
+  UnknownField field;
+  field.number_ = number;
+  field.SetType(UnknownField::TYPE_GROUP);
+  field.data_.group_ = new UnknownFieldSet;
+  fields_.push_back(field);
+  return field.data_.group_;
+}
+
+void UnknownFieldSet::AddField(const UnknownField& field) {
+  fields_.push_back(field);
+  fields_.back().DeepCopy(field);
+}
+
+void UnknownFieldSet::DeleteSubrange(int start, int num) {
+  // Delete the specified fields.
+  for (int i = 0; i < num; ++i) {
+    (fields_)[i + start].Delete();
+  }
+  // Slide down the remaining fields.
+  for (size_t i = start + num; i < fields_.size(); ++i) {
+    (fields_)[i - num] = (fields_)[i];
+  }
+  // Pop off the # of deleted fields.
+  for (int i = 0; i < num; ++i) {
+    fields_.pop_back();
+  }
+}
+
+void UnknownFieldSet::DeleteByNumber(int number) {
+  size_t left = 0;  // The number of fields left after deletion.
+  for (size_t i = 0; i < fields_.size(); ++i) {
+    UnknownField* field = &(fields_)[i];
+    if (field->number() == number) {
+      field->Delete();
+    } else {
+      if (i != left) {
+        (fields_)[left] = (fields_)[i];
+      }
+      ++left;
+    }
+  }
+  fields_.resize(left);
+}
+
+bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
+  UnknownFieldSet other;
+  if (internal::WireFormat::SkipMessage(input, &other) &&
+      input->ConsumedEntireMessage()) {
+    MergeFromAndDestroy(&other);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) {
+  Clear();
+  return MergeFromCodedStream(input);
+}
+
+bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+  io::CodedInputStream coded_input(input);
+  return (ParseFromCodedStream(&coded_input) &&
+          coded_input.ConsumedEntireMessage());
+}
+
+bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
+  io::ArrayInputStream input(data, size);
+  return ParseFromZeroCopyStream(&input);
+}
+
+bool UnknownFieldSet::SerializeToString(std::string* output) const {
+  const size_t size =
+      google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(*this);
+  STLStringResizeUninitializedAmortized(output, size);
+  google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+      *this, reinterpret_cast<uint8_t*>(const_cast<char*>(output->data())));
+  return true;
+}
+
+bool UnknownFieldSet::SerializeToCodedStream(
+    io::CodedOutputStream* output) const {
+  google::protobuf::internal::WireFormat::SerializeUnknownFields(*this, output);
+  return !output->HadError();
+}
+void UnknownField::Delete() {
+  switch (type()) {
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      delete data_.length_delimited_.string_value;
+      break;
+    case UnknownField::TYPE_GROUP:
+      delete data_.group_;
+      break;
+    default:
+      break;
+  }
+}
+
+void UnknownField::DeepCopy(const UnknownField& other) {
+  (void)other;  // Parameter is used by Google-internal code.
+  switch (type()) {
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      data_.length_delimited_.string_value =
+          new std::string(*data_.length_delimited_.string_value);
+      break;
+    case UnknownField::TYPE_GROUP: {
+      UnknownFieldSet* group = new UnknownFieldSet();
+      group->InternalMergeFrom(*data_.group_);
+      data_.group_ = group;
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+
+uint8_t* UnknownField::InternalSerializeLengthDelimitedNoTag(
+    uint8_t* target, io::EpsCopyOutputStream* stream) const {
+  GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
+  const std::string& data = *data_.length_delimited_.string_value;
+  target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
+  target = stream->WriteRaw(data.data(), data.size(), target);
+  return target;
+}
+
+namespace internal {
+
+class UnknownFieldParserHelper {
+ public:
+  explicit UnknownFieldParserHelper(UnknownFieldSet* unknown)
+      : unknown_(unknown) {}
+
+  void AddVarint(uint32_t num, uint64_t value) {
+    unknown_->AddVarint(num, value);
+  }
+  void AddFixed64(uint32_t num, uint64_t value) {
+    unknown_->AddFixed64(num, value);
+  }
+  const char* ParseLengthDelimited(uint32_t num, const char* ptr,
+                                   ParseContext* ctx) {
+    std::string* s = unknown_->AddLengthDelimited(num);
+    int size = ReadSize(&ptr);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    return ctx->ReadString(ptr, size, s);
+  }
+  const char* ParseGroup(uint32_t num, const char* ptr, ParseContext* ctx) {
+    UnknownFieldParserHelper child(unknown_->AddGroup(num));
+    return ctx->ParseGroup(&child, ptr, num * 8 + 3);
+  }
+  void AddFixed32(uint32_t num, uint32_t value) {
+    unknown_->AddFixed32(num, value);
+  }
+
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return WireFormatParser(*this, ptr, ctx);
+  }
+
+ private:
+  UnknownFieldSet* unknown_;
+};
+
+const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
+                              ParseContext* ctx) {
+  UnknownFieldParserHelper field_parser(unknown);
+  return WireFormatParser(field_parser, ptr, ctx);
+}
+
+const char* UnknownFieldParse(uint64_t tag, UnknownFieldSet* unknown,
+                              const char* ptr, ParseContext* ctx) {
+  UnknownFieldParserHelper field_parser(unknown);
+  return FieldParser(tag, field_parser, ptr, ctx);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/delimited_message_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/delimited_message_util.cpp
new file mode 100644
index 0000000..fdc633f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/delimited_message_util.cpp
@@ -0,0 +1,128 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Adapted from the patch of kenton@google.com (Kenton Varda)
+// See https://github.com/protocolbuffers/protobuf/pull/710 for details.
+
+#include <google/protobuf/util/delimited_message_util.h>
+#include <google/protobuf/io/coded_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+bool SerializeDelimitedToFileDescriptor(const MessageLite& message,
+                                        int file_descriptor) {
+  io::FileOutputStream output(file_descriptor);
+  return SerializeDelimitedToZeroCopyStream(message, &output);
+}
+
+bool SerializeDelimitedToOstream(const MessageLite& message,
+                                 std::ostream* output) {
+  {
+    io::OstreamOutputStream zero_copy_output(output);
+    if (!SerializeDelimitedToZeroCopyStream(message, &zero_copy_output))
+      return false;
+  }
+  return output->good();
+}
+
+bool ParseDelimitedFromZeroCopyStream(MessageLite* message,
+                                      io::ZeroCopyInputStream* input,
+                                      bool* clean_eof) {
+  io::CodedInputStream coded_input(input);
+  return ParseDelimitedFromCodedStream(message, &coded_input, clean_eof);
+}
+
+bool ParseDelimitedFromCodedStream(MessageLite* message,
+                                   io::CodedInputStream* input,
+                                   bool* clean_eof) {
+  if (clean_eof != nullptr) *clean_eof = false;
+  int start = input->CurrentPosition();
+
+  // Read the size.
+  uint32_t size;
+  if (!input->ReadVarint32(&size)) {
+    if (clean_eof != nullptr) *clean_eof = input->CurrentPosition() == start;
+    return false;
+  }
+
+  // Get the position after any size bytes have been read (and only the message
+  // itself remains).
+  int position_after_size = input->CurrentPosition();
+
+  // Tell the stream not to read beyond that size.
+  io::CodedInputStream::Limit limit = input->PushLimit(static_cast<int>(size));
+
+  // Parse the message.
+  if (!message->MergeFromCodedStream(input)) return false;
+  if (!input->ConsumedEntireMessage()) return false;
+  if (input->CurrentPosition() - position_after_size != static_cast<int>(size))
+    return false;
+
+  // Release the limit.
+  input->PopLimit(limit);
+
+  return true;
+}
+
+bool SerializeDelimitedToZeroCopyStream(const MessageLite& message,
+                                        io::ZeroCopyOutputStream* output) {
+  io::CodedOutputStream coded_output(output);
+  return SerializeDelimitedToCodedStream(message, &coded_output);
+}
+
+bool SerializeDelimitedToCodedStream(const MessageLite& message,
+                                     io::CodedOutputStream* output) {
+  // Write the size.
+  size_t size = message.ByteSizeLong();
+  if (size > INT_MAX) return false;
+
+  output->WriteVarint32(static_cast<uint32_t>(size));
+
+  // Write the content.
+  uint8_t* buffer =
+      output->GetDirectBufferForNBytesAndAdvance(static_cast<int>(size));
+  if (buffer != nullptr) {
+    // Optimization: The message fits in one buffer, so use the faster
+    // direct-to-array serialization path.
+    message.SerializeWithCachedSizesToArray(buffer);
+  } else {
+    // Slightly-slower path when the message is multiple buffers.
+    message.SerializeWithCachedSizes(output);
+    if (output->HadError()) return false;
+  }
+
+  return true;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/field_comparator.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/field_comparator.cpp
new file mode 100644
index 0000000..5d8e865
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/field_comparator.cpp
@@ -0,0 +1,210 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: ksroka@google.com (Krzysztof Sroka)
+
+#include <google/protobuf/util/field_comparator.h>
+
+#include <limits>
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+FieldComparator::FieldComparator() {}
+FieldComparator::~FieldComparator() {}
+
+SimpleFieldComparator::SimpleFieldComparator()
+    : float_comparison_(EXACT),
+      treat_nan_as_equal_(false),
+      has_default_tolerance_(false) {}
+
+SimpleFieldComparator::~SimpleFieldComparator() {}
+
+FieldComparator::ComparisonResult SimpleFieldComparator::SimpleCompare(
+    const Message& message_1, const Message& message_2,
+    const FieldDescriptor* field, int index_1, int index_2,
+    const util::FieldContext* /*field_context*/) {
+  const Reflection* reflection_1 = message_1.GetReflection();
+  const Reflection* reflection_2 = message_2.GetReflection();
+
+  switch (field->cpp_type()) {
+#define COMPARE_FIELD(METHOD)                                                 \
+  if (field->is_repeated()) {                                                 \
+    return ResultFromBoolean(Compare##METHOD(                                 \
+        *field, reflection_1->GetRepeated##METHOD(message_1, field, index_1), \
+        reflection_2->GetRepeated##METHOD(message_2, field, index_2)));       \
+  } else {                                                                    \
+    return ResultFromBoolean(                                                 \
+        Compare##METHOD(*field, reflection_1->Get##METHOD(message_1, field),  \
+                        reflection_2->Get##METHOD(message_2, field)));        \
+  }                                                                           \
+  break;  // Make sure no fall-through is introduced.
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      COMPARE_FIELD(Bool);
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      COMPARE_FIELD(Double);
+    case FieldDescriptor::CPPTYPE_ENUM:
+      COMPARE_FIELD(Enum);
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      COMPARE_FIELD(Float);
+    case FieldDescriptor::CPPTYPE_INT32:
+      COMPARE_FIELD(Int32);
+    case FieldDescriptor::CPPTYPE_INT64:
+      COMPARE_FIELD(Int64);
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->is_repeated()) {
+        // Allocate scratch strings to store the result if a conversion is
+        // needed.
+        std::string scratch1;
+        std::string scratch2;
+        return ResultFromBoolean(
+            CompareString(*field,
+                          reflection_1->GetRepeatedStringReference(
+                              message_1, field, index_1, &scratch1),
+                          reflection_2->GetRepeatedStringReference(
+                              message_2, field, index_2, &scratch2)));
+      } else {
+        // Allocate scratch strings to store the result if a conversion is
+        // needed.
+        std::string scratch1;
+        std::string scratch2;
+        return ResultFromBoolean(CompareString(
+            *field,
+            reflection_1->GetStringReference(message_1, field, &scratch1),
+            reflection_2->GetStringReference(message_2, field, &scratch2)));
+      }
+      break;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      COMPARE_FIELD(UInt32);
+    case FieldDescriptor::CPPTYPE_UINT64:
+      COMPARE_FIELD(UInt64);
+
+#undef COMPARE_FIELD
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return RECURSE;
+
+    default:
+      GOOGLE_LOG(FATAL) << "No comparison code for field " << field->full_name()
+                 << " of CppType = " << field->cpp_type();
+      return DIFFERENT;
+  }
+}
+
+bool SimpleFieldComparator::CompareWithDifferencer(
+    MessageDifferencer* differencer, const Message& message1,
+    const Message& message2, const util::FieldContext* field_context) {
+  return differencer->Compare(message1, message2,
+                              field_context->parent_fields());
+}
+
+void SimpleFieldComparator::SetDefaultFractionAndMargin(double fraction,
+                                                        double margin) {
+  default_tolerance_ = Tolerance(fraction, margin);
+  has_default_tolerance_ = true;
+}
+
+void SimpleFieldComparator::SetFractionAndMargin(const FieldDescriptor* field,
+                                                 double fraction,
+                                                 double margin) {
+  GOOGLE_CHECK(FieldDescriptor::CPPTYPE_FLOAT == field->cpp_type() ||
+        FieldDescriptor::CPPTYPE_DOUBLE == field->cpp_type())
+      << "Field has to be float or double type. Field name is: "
+      << field->full_name();
+  map_tolerance_[field] = Tolerance(fraction, margin);
+}
+
+bool SimpleFieldComparator::CompareDouble(const FieldDescriptor& field,
+                                          double value_1, double value_2) {
+  return CompareDoubleOrFloat(field, value_1, value_2);
+}
+
+bool SimpleFieldComparator::CompareEnum(const FieldDescriptor& /*field*/,
+                                        const EnumValueDescriptor* value_1,
+                                        const EnumValueDescriptor* value_2) {
+  return value_1->number() == value_2->number();
+}
+
+bool SimpleFieldComparator::CompareFloat(const FieldDescriptor& field,
+                                         float value_1, float value_2) {
+  return CompareDoubleOrFloat(field, value_1, value_2);
+}
+
+template <typename T>
+bool SimpleFieldComparator::CompareDoubleOrFloat(const FieldDescriptor& field,
+                                                 T value_1, T value_2) {
+  if (value_1 == value_2) {
+    // Covers +inf and -inf (which are not within margin or fraction of
+    // themselves), and is a shortcut for finite values.
+    return true;
+  } else if (float_comparison_ == EXACT) {
+    if (treat_nan_as_equal_ && std::isnan(value_1) && std::isnan(value_2)) {
+      return true;
+    }
+    return false;
+  } else {
+    if (treat_nan_as_equal_ && std::isnan(value_1) && std::isnan(value_2)) {
+      return true;
+    }
+    // float_comparison_ == APPROXIMATE covers two use cases.
+    Tolerance* tolerance = FindOrNull(map_tolerance_, &field);
+    if (tolerance == NULL && has_default_tolerance_) {
+      tolerance = &default_tolerance_;
+    }
+    if (tolerance == NULL) {
+      return MathUtil::AlmostEquals(value_1, value_2);
+    } else {
+      // Use user-provided fraction and margin. Since they are stored as
+      // doubles, we explicitly cast them to types of values provided. This
+      // is very likely to fail if provided values are not numeric.
+      return MathUtil::WithinFractionOrMargin(
+          value_1, value_2, static_cast<T>(tolerance->fraction),
+          static_cast<T>(tolerance->margin));
+    }
+  }
+}
+
+FieldComparator::ComparisonResult SimpleFieldComparator::ResultFromBoolean(
+    bool boolean_result) const {
+  return boolean_result ? FieldComparator::SAME : FieldComparator::DIFFERENT;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/field_mask_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/field_mask_util.cpp
new file mode 100644
index 0000000..9a40b85
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/field_mask_util.cpp
@@ -0,0 +1,720 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/field_mask_util.h>
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/stubs/map_util.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::FieldMask;
+
+std::string FieldMaskUtil::ToString(const FieldMask& mask) {
+  return Join(mask.paths(), ",");
+}
+
+void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
+  out->Clear();
+  std::vector<std::string> paths = Split(str, ",");
+  for (const std::string& path : paths) {
+    if (path.empty()) continue;
+    out->add_paths(path);
+  }
+}
+
+bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input,
+                                         std::string* output) {
+  output->clear();
+  bool after_underscore = false;
+  for (char input_char : input) {
+    if (input_char >= 'A' && input_char <= 'Z') {
+      // The field name must not contain uppercase letters.
+      return false;
+    }
+    if (after_underscore) {
+      if (input_char >= 'a' && input_char <= 'z') {
+        output->push_back(input_char + 'A' - 'a');
+        after_underscore = false;
+      } else {
+        // The character after a "_" must be a lowercase letter.
+        return false;
+      }
+    } else if (input_char == '_') {
+      after_underscore = true;
+    } else {
+      output->push_back(input_char);
+    }
+  }
+  if (after_underscore) {
+    // Trailing "_".
+    return false;
+  }
+  return true;
+}
+
+bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input,
+                                         std::string* output) {
+  output->clear();
+  for (const char c : input) {
+    if (c == '_') {
+      // The field name must not contain "_"s.
+      return false;
+    }
+    if (c >= 'A' && c <= 'Z') {
+      output->push_back('_');
+      output->push_back(c + 'a' - 'A');
+    } else {
+      output->push_back(c);
+    }
+  }
+  return true;
+}
+
+bool FieldMaskUtil::ToJsonString(const FieldMask& mask, std::string* out) {
+  out->clear();
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    const std::string& path = mask.paths(i);
+    std::string camelcase_path;
+    if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
+      return false;
+    }
+    if (i > 0) {
+      out->push_back(',');
+    }
+    out->append(camelcase_path);
+  }
+  return true;
+}
+
+bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
+  out->Clear();
+  std::vector<std::string> paths = Split(str, ",");
+  for (const std::string& path : paths) {
+    if (path.empty()) continue;
+    std::string snakecase_path;
+    if (!CamelCaseToSnakeCase(path, &snakecase_path)) {
+      return false;
+    }
+    out->add_paths(snakecase_path);
+  }
+  return true;
+}
+
+bool FieldMaskUtil::GetFieldDescriptors(
+    const Descriptor* descriptor, StringPiece path,
+    std::vector<const FieldDescriptor*>* field_descriptors) {
+  if (field_descriptors != nullptr) {
+    field_descriptors->clear();
+  }
+  std::vector<std::string> parts = Split(path, ".");
+  for (const std::string& field_name : parts) {
+    if (descriptor == nullptr) {
+      return false;
+    }
+    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
+    if (field == nullptr) {
+      return false;
+    }
+    if (field_descriptors != nullptr) {
+      field_descriptors->push_back(field);
+    }
+    if (!field->is_repeated() &&
+        field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      descriptor = field->message_type();
+    } else {
+      descriptor = nullptr;
+    }
+  }
+  return true;
+}
+
+void FieldMaskUtil::GetFieldMaskForAllFields(const Descriptor* descriptor,
+                                             FieldMask* out) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    out->add_paths(descriptor->field(i)->name());
+  }
+}
+
+namespace {
+// A FieldMaskTree represents a FieldMask in a tree structure. For example,
+// given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
+//
+//   [root] -+- foo -+- bar
+//           |       |
+//           |       +- baz
+//           |
+//           +- bar --- baz
+//
+// In the tree, each leaf node represents a field path.
+class FieldMaskTree {
+ public:
+  FieldMaskTree();
+  ~FieldMaskTree();
+
+  void MergeFromFieldMask(const FieldMask& mask);
+  void MergeToFieldMask(FieldMask* mask);
+
+  // Add a field path into the tree. In a FieldMask, each field path matches
+  // the specified field and also all its sub-fields. If the field path to
+  // add is a sub-path of an existing field path in the tree (i.e., a leaf
+  // node), it means the tree already matches the given path so nothing will
+  // be added to the tree. If the path matches an existing non-leaf node in the
+  // tree, that non-leaf node will be turned into a leaf node with all its
+  // children removed because the path matches all the node's children.
+  void AddPath(const std::string& path);
+
+  // Remove a path from the tree.
+  // If the path is a sub-path of an existing field path in the tree, it means
+  // we need remove the existing field path and add all sub-paths except
+  // specified path. If the path matches an existing node in the tree, this node
+  // will be moved.
+  void RemovePath(const std::string& path, const Descriptor* descriptor);
+
+  // Calculate the intersection part of a field path with this tree and add
+  // the intersection field path into out.
+  void IntersectPath(const std::string& path, FieldMaskTree* out);
+
+  // Merge all fields specified by this tree from one message to another.
+  void MergeMessage(const Message& source,
+                    const FieldMaskUtil::MergeOptions& options,
+                    Message* destination) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return;
+    }
+    MergeMessage(&root_, source, options, destination);
+  }
+
+  // Add required field path of the message to this tree based on current tree
+  // structure. If a message is present in the tree, add the path of its
+  // required field to the tree. This is to make sure that after trimming a
+  // message with required fields are set, check IsInitialized() will not fail.
+  void AddRequiredFieldPath(const Descriptor* descriptor) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return;
+    }
+    AddRequiredFieldPath(&root_, descriptor);
+  }
+
+  // Trims all fields not specified by this tree from the given message.
+  // Returns true if the message is modified.
+  bool TrimMessage(Message* message) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return false;
+    }
+    return TrimMessage(&root_, message);
+  }
+
+ private:
+  struct Node {
+    Node() {}
+
+    ~Node() { ClearChildren(); }
+
+    void ClearChildren() {
+      for (std::map<std::string, Node*>::iterator it = children.begin();
+           it != children.end(); ++it) {
+        delete it->second;
+      }
+      children.clear();
+    }
+
+    std::map<std::string, Node*> children;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
+  };
+
+  // Merge a sub-tree to mask. This method adds the field paths represented
+  // by all leaf nodes descended from "node" to mask.
+  void MergeToFieldMask(const std::string& prefix, const Node* node,
+                        FieldMask* out);
+
+  // Merge all leaf nodes of a sub-tree to another tree.
+  void MergeLeafNodesToTree(const std::string& prefix, const Node* node,
+                            FieldMaskTree* out);
+
+  // Merge all fields specified by a sub-tree from one message to another.
+  void MergeMessage(const Node* node, const Message& source,
+                    const FieldMaskUtil::MergeOptions& options,
+                    Message* destination);
+
+  // Add required field path of the message to this tree based on current tree
+  // structure. If a message is present in the tree, add the path of its
+  // required field to the tree. This is to make sure that after trimming a
+  // message with required fields are set, check IsInitialized() will not fail.
+  void AddRequiredFieldPath(Node* node, const Descriptor* descriptor);
+
+  // Trims all fields not specified by this sub-tree from the given message.
+  // Returns true if the message is actually modified
+  bool TrimMessage(const Node* node, Message* message);
+
+  Node root_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
+};
+
+FieldMaskTree::FieldMaskTree() {}
+
+FieldMaskTree::~FieldMaskTree() {}
+
+void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    AddPath(mask.paths(i));
+  }
+}
+
+void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
+  MergeToFieldMask("", &root_, mask);
+}
+
+void FieldMaskTree::MergeToFieldMask(const std::string& prefix,
+                                     const Node* node, FieldMask* out) {
+  if (node->children.empty()) {
+    if (prefix.empty()) {
+      // This is the root node.
+      return;
+    }
+    out->add_paths(prefix);
+    return;
+  }
+  for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    std::string current_path =
+        prefix.empty() ? it->first : prefix + "." + it->first;
+    MergeToFieldMask(current_path, it->second, out);
+  }
+}
+
+void FieldMaskTree::AddPath(const std::string& path) {
+  std::vector<std::string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  bool new_branch = false;
+  Node* node = &root_;
+  for (const std::string& node_name : parts) {
+    if (!new_branch && node != &root_ && node->children.empty()) {
+      // Path matches an existing leaf node. This means the path is already
+      // covered by this tree (for example, adding "foo.bar.baz" to a tree
+      // which already contains "foo.bar").
+      return;
+    }
+    Node*& child = node->children[node_name];
+    if (child == nullptr) {
+      new_branch = true;
+      child = new Node();
+    }
+    node = child;
+  }
+  if (!node->children.empty()) {
+    node->ClearChildren();
+  }
+}
+
+void FieldMaskTree::RemovePath(const std::string& path,
+                               const Descriptor* descriptor) {
+  if (root_.children.empty()) {
+    // Nothing to be removed from an empty tree. We shortcut it here so an empty
+    // tree won't be interpreted as a field mask containing all fields by the
+    // code below.
+    return;
+  }
+  std::vector<std::string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  std::vector<Node*> nodes(parts.size());
+  Node* node = &root_;
+  const Descriptor* current_descriptor = descriptor;
+  Node* new_branch_node = nullptr;
+  for (size_t i = 0; i < parts.size(); ++i) {
+    nodes[i] = node;
+    const FieldDescriptor* field_descriptor =
+        current_descriptor->FindFieldByName(parts[i]);
+    if (field_descriptor == nullptr ||
+        (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
+         i != parts.size() - 1)) {
+      // Invalid path.
+      if (new_branch_node != nullptr) {
+        // If add any new nodes, cleanup.
+        new_branch_node->ClearChildren();
+      }
+      return;
+    }
+
+    if (node->children.empty()) {
+      if (new_branch_node == nullptr) {
+        new_branch_node = node;
+      }
+      for (int j = 0; j < current_descriptor->field_count(); ++j) {
+        node->children[current_descriptor->field(j)->name()] = new Node();
+      }
+    }
+    if (ContainsKey(node->children, parts[i])) {
+      node = node->children[parts[i]];
+      if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        current_descriptor = field_descriptor->message_type();
+      }
+    } else {
+      // Path does not exist.
+      return;
+    }
+  }
+  // Remove path.
+  for (int i = parts.size() - 1; i >= 0; i--) {
+    delete nodes[i]->children[parts[i]];
+    nodes[i]->children.erase(parts[i]);
+    if (!nodes[i]->children.empty()) {
+      break;
+    }
+  }
+}
+
+void FieldMaskTree::IntersectPath(const std::string& path, FieldMaskTree* out) {
+  std::vector<std::string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  const Node* node = &root_;
+  for (const std::string& node_name : parts) {
+    if (node->children.empty()) {
+      if (node != &root_) {
+        out->AddPath(path);
+      }
+      return;
+    }
+    const Node* result = FindPtrOrNull(node->children, node_name);
+    if (result == nullptr) {
+      // No intersection found.
+      return;
+    }
+    node = result;
+  }
+  // Now we found a matching node with the given path. Add all leaf nodes
+  // to out.
+  MergeLeafNodesToTree(path, node, out);
+}
+
+void FieldMaskTree::MergeLeafNodesToTree(const std::string& prefix,
+                                         const Node* node, FieldMaskTree* out) {
+  if (node->children.empty()) {
+    out->AddPath(prefix);
+  }
+  for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    std::string current_path =
+        prefix.empty() ? it->first : prefix + "." + it->first;
+    MergeLeafNodesToTree(current_path, it->second, out);
+  }
+}
+
+void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
+                                 const FieldMaskUtil::MergeOptions& options,
+                                 Message* destination) {
+  GOOGLE_DCHECK(!node->children.empty());
+  const Reflection* source_reflection = source.GetReflection();
+  const Reflection* destination_reflection = destination->GetReflection();
+  const Descriptor* descriptor = source.GetDescriptor();
+  for (std::map<std::string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    const std::string& field_name = it->first;
+    const Node* child = it->second;
+    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
+    if (field == nullptr) {
+      GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
+                 << descriptor->full_name();
+      continue;
+    }
+    if (!child->children.empty()) {
+      // Sub-paths are only allowed for singular message fields.
+      if (field->is_repeated() ||
+          field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+        GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
+                   << descriptor->full_name()
+                   << " is not a singular message field and cannot "
+                   << "have sub-fields.";
+        continue;
+      }
+      MergeMessage(child, source_reflection->GetMessage(source, field), options,
+                   destination_reflection->MutableMessage(destination, field));
+      continue;
+    }
+    if (!field->is_repeated()) {
+      switch (field->cpp_type()) {
+#define COPY_VALUE(TYPE, Name)                                              \
+  case FieldDescriptor::CPPTYPE_##TYPE: {                                   \
+    if (source_reflection->HasField(source, field)) {                       \
+      destination_reflection->Set##Name(                                    \
+          destination, field, source_reflection->Get##Name(source, field)); \
+    } else {                                                                \
+      destination_reflection->ClearField(destination, field);               \
+    }                                                                       \
+    break;                                                                  \
+  }
+        COPY_VALUE(BOOL, Bool)
+        COPY_VALUE(INT32, Int32)
+        COPY_VALUE(INT64, Int64)
+        COPY_VALUE(UINT32, UInt32)
+        COPY_VALUE(UINT64, UInt64)
+        COPY_VALUE(FLOAT, Float)
+        COPY_VALUE(DOUBLE, Double)
+        COPY_VALUE(ENUM, Enum)
+        COPY_VALUE(STRING, String)
+#undef COPY_VALUE
+        case FieldDescriptor::CPPTYPE_MESSAGE: {
+          if (options.replace_message_fields()) {
+            destination_reflection->ClearField(destination, field);
+          }
+          if (source_reflection->HasField(source, field)) {
+            destination_reflection->MutableMessage(destination, field)
+                ->MergeFrom(source_reflection->GetMessage(source, field));
+          }
+          break;
+        }
+      }
+    } else {
+      if (options.replace_repeated_fields()) {
+        destination_reflection->ClearField(destination, field);
+      }
+      switch (field->cpp_type()) {
+#define COPY_REPEATED_VALUE(TYPE, Name)                            \
+  case FieldDescriptor::CPPTYPE_##TYPE: {                          \
+    int size = source_reflection->FieldSize(source, field);        \
+    for (int i = 0; i < size; ++i) {                               \
+      destination_reflection->Add##Name(                           \
+          destination, field,                                      \
+          source_reflection->GetRepeated##Name(source, field, i)); \
+    }                                                              \
+    break;                                                         \
+  }
+        COPY_REPEATED_VALUE(BOOL, Bool)
+        COPY_REPEATED_VALUE(INT32, Int32)
+        COPY_REPEATED_VALUE(INT64, Int64)
+        COPY_REPEATED_VALUE(UINT32, UInt32)
+        COPY_REPEATED_VALUE(UINT64, UInt64)
+        COPY_REPEATED_VALUE(FLOAT, Float)
+        COPY_REPEATED_VALUE(DOUBLE, Double)
+        COPY_REPEATED_VALUE(ENUM, Enum)
+        COPY_REPEATED_VALUE(STRING, String)
+#undef COPY_REPEATED_VALUE
+        case FieldDescriptor::CPPTYPE_MESSAGE: {
+          int size = source_reflection->FieldSize(source, field);
+          for (int i = 0; i < size; ++i) {
+            destination_reflection->AddMessage(destination, field)
+                ->MergeFrom(
+                    source_reflection->GetRepeatedMessage(source, field, i));
+          }
+          break;
+        }
+      }
+    }
+  }
+}
+
+void FieldMaskTree::AddRequiredFieldPath(Node* node,
+                                         const Descriptor* descriptor) {
+  const int32_t field_count = descriptor->field_count();
+  for (int index = 0; index < field_count; ++index) {
+    const FieldDescriptor* field = descriptor->field(index);
+    if (field->is_required()) {
+      const std::string& node_name = field->name();
+      Node*& child = node->children[node_name];
+      if (child == nullptr) {
+        // Add required field path to the tree
+        child = new Node();
+      } else if (child->children.empty()) {
+        // If the required field is in the tree and does not have any children,
+        // do nothing.
+        continue;
+      }
+      // Add required field in the children to the tree if the field is message.
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        AddRequiredFieldPath(child, field->message_type());
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      std::map<std::string, Node*>::const_iterator it =
+          node->children.find(field->name());
+      if (it != node->children.end()) {
+        // Add required fields in the children to the
+        // tree if the field is a message and present in the tree.
+        Node* child = it->second;
+        if (!child->children.empty()) {
+          AddRequiredFieldPath(child, field->message_type());
+        }
+      }
+    }
+  }
+}
+
+bool FieldMaskTree::TrimMessage(const Node* node, Message* message) {
+  GOOGLE_DCHECK(!node->children.empty());
+  const Reflection* reflection = message->GetReflection();
+  const Descriptor* descriptor = message->GetDescriptor();
+  const int32_t field_count = descriptor->field_count();
+  bool modified = false;
+  for (int index = 0; index < field_count; ++index) {
+    const FieldDescriptor* field = descriptor->field(index);
+    std::map<std::string, Node*>::const_iterator it =
+        node->children.find(field->name());
+    if (it == node->children.end()) {
+      if (field->is_repeated()) {
+        if (reflection->FieldSize(*message, field) != 0) {
+          modified = true;
+        }
+      } else {
+        if (reflection->HasField(*message, field)) {
+          modified = true;
+        }
+      }
+      reflection->ClearField(message, field);
+    } else {
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        Node* child = it->second;
+        if (!child->children.empty() && reflection->HasField(*message, field)) {
+          bool nestedMessageChanged =
+              TrimMessage(child, reflection->MutableMessage(message, field));
+          modified = nestedMessageChanged || modified;
+        }
+      }
+    }
+  }
+  return modified;
+}
+
+}  // namespace
+
+void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  out->Clear();
+  tree.MergeToFieldMask(out);
+}
+
+void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
+                          FieldMask* out) {
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask1);
+  tree.MergeFromFieldMask(mask2);
+  out->Clear();
+  tree.MergeToFieldMask(out);
+}
+
+void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
+                              FieldMask* out) {
+  FieldMaskTree tree, intersection;
+  tree.MergeFromFieldMask(mask1);
+  for (int i = 0; i < mask2.paths_size(); ++i) {
+    tree.IntersectPath(mask2.paths(i), &intersection);
+  }
+  out->Clear();
+  intersection.MergeToFieldMask(out);
+}
+
+void FieldMaskUtil::Subtract(const Descriptor* descriptor,
+                             const FieldMask& mask1, const FieldMask& mask2,
+                             FieldMask* out) {
+  if (mask1.paths().empty()) {
+    out->Clear();
+    return;
+  }
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask1);
+  for (int i = 0; i < mask2.paths_size(); ++i) {
+    tree.RemovePath(mask2.paths(i), descriptor);
+  }
+  out->Clear();
+  tree.MergeToFieldMask(out);
+}
+
+bool FieldMaskUtil::IsPathInFieldMask(StringPiece path,
+                                      const FieldMask& mask) {
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    const std::string& mask_path = mask.paths(i);
+    if (path == mask_path) {
+      return true;
+    } else if (mask_path.length() < path.length()) {
+      // Also check whether mask.paths(i) is a prefix of path.
+      if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
+          0) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
+                                   const MergeOptions& options,
+                                   Message* destination) {
+  GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  tree.MergeMessage(source, options, destination);
+}
+
+bool FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* message) {
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  return tree.TrimMessage(GOOGLE_CHECK_NOTNULL(message));
+}
+
+bool FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* message,
+                                const TrimOptions& options) {
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  // If keep_required_fields is true, implicitly add required fields of
+  // a message present in the tree to prevent from trimming.
+  if (options.keep_required_fields()) {
+    tree.AddRequiredFieldPath(GOOGLE_CHECK_NOTNULL(message->GetDescriptor()));
+  }
+  return tree.TrimMessage(GOOGLE_CHECK_NOTNULL(message));
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/datapiece.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/datapiece.cpp
new file mode 100644
index 0000000..56f4a18
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/datapiece.cpp
@@ -0,0 +1,448 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/datapiece.h>
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+#include <google/protobuf/struct.pb.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using util::Status;
+
+namespace {
+
+template <typename To, typename From>
+util::StatusOr<To> ValidateNumberConversion(To after, From before) {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#endif
+  if (after == before &&
+      MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) {
+    return after;
+  } else {
+    return util::InvalidArgumentError(
+        std::is_integral<From>::value       ? ValueAsString(before)
+        : std::is_same<From, double>::value ? DoubleAsString(before)
+                                            : FloatAsString(before));
+  }
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+}
+
+// For general conversion between
+//     int32, int64, uint32, uint64, double and float
+// except conversion between double and float.
+template <typename To, typename From>
+util::StatusOr<To> NumberConvertAndCheck(From before) {
+  if (std::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
+// For conversion to integer types (int32, int64, uint32, uint64) from floating
+// point types (double, float) only.
+template <typename To, typename From>
+util::StatusOr<To> FloatingPointToIntConvertAndCheck(From before) {
+  if (std::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
+// For conversion between double and float only.
+util::StatusOr<double> FloatToDouble(float before) {
+  // Casting float to double should just work as double has more precision
+  // than float.
+  return static_cast<double>(before);
+}
+
+util::StatusOr<float> DoubleToFloat(double before) {
+  if (std::isnan(before)) {
+    return std::numeric_limits<float>::quiet_NaN();
+  } else if (!std::isfinite(before)) {
+    // Converting a double +inf/-inf to float should just work.
+    return static_cast<float>(before);
+  } else if (before > std::numeric_limits<float>::max() ||
+             before < -std::numeric_limits<float>::max()) {
+    // Some doubles are larger than the largest float, but after
+    // rounding they will be equal to the largest float.
+    // We can't just attempt the conversion because that has UB if
+    // the value really is out-of-range.
+    // Here we take advantage that 1/2-ing a large floating point
+    // will not lose precision.
+    double half_before = before * 0.5;
+    if (half_before < std::numeric_limits<float>::max() &&
+        half_before > -std::numeric_limits<float>::max()) {
+      const float half_fmax = std::numeric_limits<float>::max() * 0.5f;
+      // If after being cut in half, the value is less than the largest float,
+      // then it's safe to convert it to float.  Importantly, this conversion
+      // rounds in the same way that the original does.
+      float half_after = static_cast<float>(half_before);
+      if (half_after <= half_fmax && half_after >= -half_fmax) {
+        return half_after + half_after;
+      }
+    }
+    // Double value outside of the range of float.
+    return util::InvalidArgumentError(DoubleAsString(before));
+  } else {
+    return static_cast<float>(before);
+  }
+}
+
+}  // namespace
+
+util::StatusOr<int32_t> DataPiece::ToInt32() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<int32_t>(safe_strto32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int32_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int32_t, float>(float_);
+
+  return GenericConvert<int32_t>();
+}
+
+util::StatusOr<uint32_t> DataPiece::ToUint32() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<uint32_t>(safe_strtou32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint32_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint32_t, float>(float_);
+
+  return GenericConvert<uint32_t>();
+}
+
+util::StatusOr<int64_t> DataPiece::ToInt64() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<int64_t>(safe_strto64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int64_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int64_t, float>(float_);
+
+  return GenericConvert<int64_t>();
+}
+
+util::StatusOr<uint64_t> DataPiece::ToUint64() const {
+  if (type_ == TYPE_STRING)
+    return StringToNumber<uint64_t>(safe_strtou64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint64_t, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint64_t, float>(float_);
+
+  return GenericConvert<uint64_t>();
+}
+
+util::StatusOr<double> DataPiece::ToDouble() const {
+  if (type_ == TYPE_FLOAT) {
+    return FloatToDouble(float_);
+  }
+  if (type_ == TYPE_STRING) {
+    if (str_ == "Infinity") return std::numeric_limits<double>::infinity();
+    if (str_ == "-Infinity") return -std::numeric_limits<double>::infinity();
+    if (str_ == "NaN") return std::numeric_limits<double>::quiet_NaN();
+    util::StatusOr<double> value = StringToNumber<double>(safe_strtod);
+    if (value.ok() && !std::isfinite(value.value())) {
+      // safe_strtod converts out-of-range values to +inf/-inf, but we want
+      // to report them as errors.
+      return util::InvalidArgumentError(StrCat("\"", str_, "\""));
+    } else {
+      return value;
+    }
+  }
+  return GenericConvert<double>();
+}
+
+util::StatusOr<float> DataPiece::ToFloat() const {
+  if (type_ == TYPE_DOUBLE) {
+    return DoubleToFloat(double_);
+  }
+  if (type_ == TYPE_STRING) {
+    if (str_ == "Infinity") return std::numeric_limits<float>::infinity();
+    if (str_ == "-Infinity") return -std::numeric_limits<float>::infinity();
+    if (str_ == "NaN") return std::numeric_limits<float>::quiet_NaN();
+    // SafeStrToFloat() is used instead of safe_strtof() because the later
+    // does not fail on inputs like SimpleDtoa(DBL_MAX).
+    return StringToNumber<float>(SafeStrToFloat);
+  }
+  return GenericConvert<float>();
+}
+
+util::StatusOr<bool> DataPiece::ToBool() const {
+  switch (type_) {
+    case TYPE_BOOL:
+      return bool_;
+    case TYPE_STRING:
+      return StringToNumber<bool>(safe_strtob);
+    default:
+      return util::InvalidArgumentError(
+          ValueAsStringOrDefault("Wrong type. Cannot convert to Bool."));
+  }
+}
+
+util::StatusOr<std::string> DataPiece::ToString() const {
+  switch (type_) {
+    case TYPE_STRING:
+      return std::string(str_);
+    case TYPE_BYTES: {
+      std::string base64;
+      Base64Escape(str_, &base64);
+      return base64;
+    }
+    default:
+      return util::InvalidArgumentError(
+          ValueAsStringOrDefault("Cannot convert to string."));
+  }
+}
+
+std::string DataPiece::ValueAsStringOrDefault(
+    StringPiece default_string) const {
+  switch (type_) {
+    case TYPE_INT32:
+      return StrCat(i32_);
+    case TYPE_INT64:
+      return StrCat(i64_);
+    case TYPE_UINT32:
+      return StrCat(u32_);
+    case TYPE_UINT64:
+      return StrCat(u64_);
+    case TYPE_DOUBLE:
+      return DoubleAsString(double_);
+    case TYPE_FLOAT:
+      return FloatAsString(float_);
+    case TYPE_BOOL:
+      return SimpleBtoa(bool_);
+    case TYPE_STRING:
+      return StrCat("\"", str_.ToString(), "\"");
+    case TYPE_BYTES: {
+      std::string base64;
+      WebSafeBase64Escape(str_, &base64);
+      return StrCat("\"", base64, "\"");
+    }
+    case TYPE_NULL:
+      return "null";
+    default:
+      return std::string(default_string);
+  }
+}
+
+util::StatusOr<std::string> DataPiece::ToBytes() const {
+  if (type_ == TYPE_BYTES) return str_.ToString();
+  if (type_ == TYPE_STRING) {
+    std::string decoded;
+    if (!DecodeBase64(str_, &decoded)) {
+      return util::InvalidArgumentError(
+          ValueAsStringOrDefault("Invalid data in input."));
+    }
+    return decoded;
+  } else {
+    return util::InvalidArgumentError(ValueAsStringOrDefault(
+        "Wrong type. Only String or Bytes can be converted to Bytes."));
+  }
+}
+
+util::StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type,
+                                      bool use_lower_camel_for_enums,
+                                      bool case_insensitive_enum_parsing,
+                                      bool ignore_unknown_enum_values,
+                                      bool* is_unknown_enum_value) const {
+  if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE;
+
+  if (type_ == TYPE_STRING) {
+    // First try the given value as a name.
+    std::string enum_name = std::string(str_);
+    const google::protobuf::EnumValue* value =
+        FindEnumValueByNameOrNull(enum_type, enum_name);
+    if (value != nullptr) return value->number();
+
+    // Check if int version of enum is sent as string.
+    util::StatusOr<int32_t> int_value = ToInt32();
+    if (int_value.ok()) {
+      if (const google::protobuf::EnumValue* enum_value =
+              FindEnumValueByNumberOrNull(enum_type, int_value.value())) {
+        return enum_value->number();
+      }
+    }
+
+    // Next try a normalized name.
+    bool should_normalize_enum =
+        case_insensitive_enum_parsing || use_lower_camel_for_enums;
+    if (should_normalize_enum) {
+      for (std::string::iterator it = enum_name.begin(); it != enum_name.end();
+           ++it) {
+        *it = *it == '-' ? '_' : ascii_toupper(*it);
+      }
+      value = FindEnumValueByNameOrNull(enum_type, enum_name);
+      if (value != nullptr) return value->number();
+    }
+
+    // If use_lower_camel_for_enums is true try with enum name without
+    // underscore. This will also accept camel case names as the enum_name has
+    // been normalized before.
+    if (use_lower_camel_for_enums) {
+      value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name);
+      if (value != nullptr) return value->number();
+    }
+
+    // If ignore_unknown_enum_values is true an unknown enum value is ignored.
+    if (ignore_unknown_enum_values) {
+      *is_unknown_enum_value = true;
+      if (enum_type->enumvalue_size() > 0) {
+        return enum_type->enumvalue(0).number();
+      }
+    }
+  } else {
+    // We don't need to check whether the value is actually declared in the
+    // enum because we preserve unknown enum values as well.
+    return ToInt32();
+  }
+  return util::InvalidArgumentError(
+      ValueAsStringOrDefault("Cannot find enum with given value."));
+}
+
+template <typename To>
+util::StatusOr<To> DataPiece::GenericConvert() const {
+  switch (type_) {
+    case TYPE_INT32:
+      return NumberConvertAndCheck<To, int32_t>(i32_);
+    case TYPE_INT64:
+      return NumberConvertAndCheck<To, int64_t>(i64_);
+    case TYPE_UINT32:
+      return NumberConvertAndCheck<To, uint32_t>(u32_);
+    case TYPE_UINT64:
+      return NumberConvertAndCheck<To, uint64_t>(u64_);
+    case TYPE_DOUBLE:
+      return NumberConvertAndCheck<To, double>(double_);
+    case TYPE_FLOAT:
+      return NumberConvertAndCheck<To, float>(float_);
+    default:  // TYPE_ENUM, TYPE_STRING, TYPE_CORD, TYPE_BOOL
+      return util::InvalidArgumentError(ValueAsStringOrDefault(
+          "Wrong type. Bool, Enum, String and Cord not supported in "
+          "GenericConvert."));
+  }
+}
+
+template <typename To>
+util::StatusOr<To> DataPiece::StringToNumber(bool (*func)(StringPiece,
+                                                          To*)) const {
+  if (str_.size() > 0 && (str_[0] == ' ' || str_[str_.size() - 1] == ' ')) {
+    return util::InvalidArgumentError(StrCat("\"", str_, "\""));
+  }
+  To result;
+  if (func(str_, &result)) return result;
+  return util::InvalidArgumentError(
+      StrCat("\"", std::string(str_), "\""));
+}
+
+bool DataPiece::DecodeBase64(StringPiece src, std::string* dest) const {
+  // Try web-safe decode first, if it fails, try the non-web-safe decode.
+  if (WebSafeBase64Unescape(src, dest)) {
+    if (use_strict_base64_decoding_) {
+      // In strict mode, check if the escaped version gives us the same value as
+      // unescaped.
+      std::string encoded;
+      // WebSafeBase64Escape does no padding by default.
+      WebSafeBase64Escape(*dest, &encoded);
+      // Remove trailing padding '=' characters before comparison.
+      StringPiece src_no_padding = StringPiece(src).substr(
+          0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
+                                      : src.length());
+      return encoded == src_no_padding;
+    }
+    return true;
+  }
+
+  if (Base64Unescape(src, dest)) {
+    if (use_strict_base64_decoding_) {
+      std::string encoded;
+      Base64Escape(reinterpret_cast<const unsigned char*>(dest->data()),
+                         dest->length(), &encoded, false);
+      StringPiece src_no_padding = StringPiece(src).substr(
+          0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
+                                      : src.length());
+      return encoded == src_no_padding;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+void DataPiece::InternalCopy(const DataPiece& other) {
+  type_ = other.type_;
+  use_strict_base64_decoding_ = other.use_strict_base64_decoding_;
+  switch (type_) {
+    case TYPE_INT32:
+    case TYPE_INT64:
+    case TYPE_UINT32:
+    case TYPE_UINT64:
+    case TYPE_DOUBLE:
+    case TYPE_FLOAT:
+    case TYPE_BOOL:
+    case TYPE_ENUM:
+    case TYPE_NULL:
+    case TYPE_BYTES:
+    case TYPE_STRING: {
+      str_ = other.str_;
+      break;
+    }
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/default_value_objectwriter.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/default_value_objectwriter.cpp
new file mode 100644
index 0000000..a7d4ce7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/default_value_objectwriter.cpp
@@ -0,0 +1,642 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+
+#include <cstdint>
+#include <unordered_map>
+
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+// Helper function to convert string value to given data type by calling the
+// passed converter function on the DataPiece created from "value" argument.
+// If value is empty or if conversion fails, the default_value is returned.
+template <typename T>
+T ConvertTo(StringPiece value,
+            util::StatusOr<T> (DataPiece::*converter_fn)() const,
+            T default_value) {
+  if (value.empty()) return default_value;
+  util::StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
+  return result.ok() ? result.value() : default_value;
+}
+}  // namespace
+
+DefaultValueObjectWriter::DefaultValueObjectWriter(
+    TypeResolver* type_resolver, const google::protobuf::Type& type,
+    ObjectWriter* ow)
+    : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      type_(type),
+      current_(nullptr),
+      root_(nullptr),
+      suppress_empty_list_(false),
+      preserve_proto_field_names_(false),
+      use_ints_for_enums_(false),
+      ow_(ow) {}
+
+DefaultValueObjectWriter::~DefaultValueObjectWriter() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(
+    StringPiece name, bool value) {
+  if (current_ == nullptr) {
+    ow_->RenderBool(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
+    StringPiece name, int32_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderInt32(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
+    StringPiece name, uint32_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderUint32(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
+    StringPiece name, int64_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderInt64(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
+    StringPiece name, uint64_t value) {
+  if (current_ == nullptr) {
+    ow_->RenderUint64(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
+    StringPiece name, double value) {
+  if (current_ == nullptr) {
+    ow_->RenderDouble(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
+    StringPiece name, float value) {
+  if (current_ == nullptr) {
+    ow_->RenderBool(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
+    StringPiece name, StringPiece value) {
+  if (current_ == nullptr) {
+    ow_->RenderString(name, value);
+  } else {
+    // Since StringPiece is essentially a pointer, takes a copy of "value" to
+    // avoid ownership issues.
+    string_values_.emplace_back(new std::string(value));
+    RenderDataPiece(name, DataPiece(*string_values_.back(), true));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
+    StringPiece name, StringPiece value) {
+  if (current_ == nullptr) {
+    ow_->RenderBytes(name, value);
+  } else {
+    // Since StringPiece is essentially a pointer, takes a copy of "value" to
+    // avoid ownership issues.
+    string_values_.emplace_back(new std::string(value));
+    RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
+    StringPiece name) {
+  if (current_ == nullptr) {
+    ow_->RenderNull(name);
+  } else {
+    RenderDataPiece(name, DataPiece::NullData());
+  }
+  return this;
+}
+
+void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
+    FieldScrubCallBack field_scrub_callback) {
+  field_scrub_callback_ = std::move(field_scrub_callback);
+}
+
+DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
+    const std::string& name, const google::protobuf::Type* type, NodeKind kind,
+    const DataPiece& data, bool is_placeholder,
+    const std::vector<std::string>& path, bool suppress_empty_list,
+    bool preserve_proto_field_names, bool use_ints_for_enums,
+    FieldScrubCallBack field_scrub_callback) {
+  return new Node(name, type, kind, data, is_placeholder, path,
+                  suppress_empty_list, preserve_proto_field_names,
+                  use_ints_for_enums, std::move(field_scrub_callback));
+}
+
+DefaultValueObjectWriter::Node::Node(
+    const std::string& name, const google::protobuf::Type* type, NodeKind kind,
+    const DataPiece& data, bool is_placeholder,
+    const std::vector<std::string>& path, bool suppress_empty_list,
+    bool preserve_proto_field_names, bool use_ints_for_enums,
+    FieldScrubCallBack field_scrub_callback)
+    : name_(name),
+      type_(type),
+      kind_(kind),
+      is_any_(false),
+      data_(data),
+      is_placeholder_(is_placeholder),
+      path_(path),
+      suppress_empty_list_(suppress_empty_list),
+      preserve_proto_field_names_(preserve_proto_field_names),
+      use_ints_for_enums_(use_ints_for_enums),
+      field_scrub_callback_(std::move(field_scrub_callback)) {}
+
+DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
+    StringPiece name) {
+  if (name.empty() || kind_ != OBJECT) {
+    return nullptr;
+  }
+  for (Node* child : children_) {
+    if (child->name() == name) {
+      return child;
+    }
+  }
+  return nullptr;
+}
+
+void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
+  if (kind_ == PRIMITIVE) {
+    ObjectWriter::RenderDataPieceTo(data_, name_, ow);
+    return;
+  }
+
+  // Render maps. Empty maps are rendered as "{}".
+  if (kind_ == MAP) {
+    ow->StartObject(name_);
+    WriteChildren(ow);
+    ow->EndObject();
+    return;
+  }
+
+  // Write out lists. If we didn't have any list in response, write out empty
+  // list.
+  if (kind_ == LIST) {
+    // Suppress empty lists if requested.
+    if (suppress_empty_list_ && is_placeholder_) return;
+
+    ow->StartList(name_);
+    WriteChildren(ow);
+    ow->EndList();
+    return;
+  }
+
+  // If is_placeholder_ = true, we didn't see this node in the response, so
+  // skip output.
+  if (is_placeholder_) return;
+
+  ow->StartObject(name_);
+  WriteChildren(ow);
+  ow->EndObject();
+}
+
+void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
+  for (Node* child : children_) {
+    child->WriteTo(ow);
+  }
+}
+
+const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
+    const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
+  // If this field is a map, we should use the type of its "Value" as
+  // the type of the child node.
+  for (int i = 0; i < found_type.fields_size(); ++i) {
+    const google::protobuf::Field& sub_field = found_type.fields(i);
+    if (sub_field.number() != 2) {
+      continue;
+    }
+    if (sub_field.kind() != google::protobuf::Field::TYPE_MESSAGE) {
+      // This map's value type is not a message type. We don't need to
+      // get the field_type in this case.
+      break;
+    }
+    util::StatusOr<const google::protobuf::Type*> sub_type =
+        typeinfo->ResolveTypeUrl(sub_field.type_url());
+    if (!sub_type.ok()) {
+      GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
+    } else {
+      return sub_type.value();
+    }
+    break;
+  }
+  return nullptr;
+}
+
+void DefaultValueObjectWriter::Node::PopulateChildren(
+    const TypeInfo* typeinfo) {
+  // Ignores well known types that don't require automatically populating their
+  // primitive children. For type "Any", we only populate its children when the
+  // "@type" field is set.
+  // TODO(tsun): remove "kStructValueType" from the list. It's being checked
+  //     now because of a bug in the tool-chain that causes the "oneof_index"
+  //     of kStructValueType to not be set correctly.
+  if (type_ == nullptr || type_->name() == kAnyType ||
+      type_->name() == kStructType || type_->name() == kTimestampType ||
+      type_->name() == kDurationType || type_->name() == kStructValueType) {
+    return;
+  }
+  std::vector<Node*> new_children;
+  std::unordered_map<std::string, int> orig_children_map;
+
+  // Creates a map of child nodes to speed up lookup.
+  for (size_t i = 0; i < children_.size(); ++i) {
+    InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
+  }
+
+  for (int i = 0; i < type_->fields_size(); ++i) {
+    const google::protobuf::Field& field = type_->fields(i);
+
+    // This code is checking if the field to be added to the tree should be
+    // scrubbed or not by calling the field_scrub_callback_ callback function.
+    std::vector<std::string> path;
+    if (!path_.empty()) {
+      path.insert(path.begin(), path_.begin(), path_.end());
+    }
+    path.push_back(field.name());
+    if (field_scrub_callback_ && field_scrub_callback_(path, &field)) {
+      continue;
+    }
+
+    std::unordered_map<std::string, int>::iterator found =
+        orig_children_map.find(field.name());
+    // If the child field has already been set, we just add it to the new list
+    // of children.
+    if (found != orig_children_map.end()) {
+      new_children.push_back(children_[found->second]);
+      children_[found->second] = nullptr;
+      continue;
+    }
+
+    const google::protobuf::Type* field_type = nullptr;
+    bool is_map = false;
+    NodeKind kind = PRIMITIVE;
+
+    if (field.kind() == google::protobuf::Field::TYPE_MESSAGE) {
+      kind = OBJECT;
+      util::StatusOr<const google::protobuf::Type*> found_result =
+          typeinfo->ResolveTypeUrl(field.type_url());
+      if (!found_result.ok()) {
+        // "field" is of an unknown type.
+        GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
+      } else {
+        const google::protobuf::Type* found_type = found_result.value();
+        is_map = IsMap(field, *found_type);
+
+        if (!is_map) {
+          field_type = found_type;
+        } else {
+          // If this field is a map, we should use the type of its "Value" as
+          // the type of the child node.
+          field_type = GetMapValueType(*found_type, typeinfo);
+          kind = MAP;
+        }
+      }
+    }
+
+    if (!is_map &&
+        field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) {
+      kind = LIST;
+    }
+
+    // If oneof_index() != 0, the child field is part of a "oneof", which means
+    // the child field is optional and we shouldn't populate its default
+    // primitive value.
+    if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;
+
+    // If the child field is of primitive type, sets its data to the default
+    // value of its type.
+    std::unique_ptr<Node> child(
+        new Node(preserve_proto_field_names_ ? field.name() : field.json_name(),
+                 field_type, kind,
+                 kind == PRIMITIVE ? CreateDefaultDataPieceForField(
+                                         field, typeinfo, use_ints_for_enums_)
+                                   : DataPiece::NullData(),
+                 true, path, suppress_empty_list_, preserve_proto_field_names_,
+                 use_ints_for_enums_, field_scrub_callback_));
+    new_children.push_back(child.release());
+  }
+  // Adds all leftover nodes in children_ to the beginning of new_child.
+  for (size_t i = 0; i < children_.size(); ++i) {
+    if (children_[i] == nullptr) {
+      continue;
+    }
+    new_children.insert(new_children.begin(), children_[i]);
+    children_[i] = nullptr;
+  }
+  children_.swap(new_children);
+}
+
+void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
+  // If this is an "Any" node with "@type" already given and no other children
+  // have been added, populates its children.
+  if (node != nullptr && node->is_any() && node->type() != nullptr &&
+      node->type()->name() != kAnyType && node->number_of_children() == 1) {
+    node->PopulateChildren(typeinfo_);
+  }
+}
+
+DataPiece DefaultValueObjectWriter::FindEnumDefault(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo,
+    bool use_ints_for_enums) {
+  const google::protobuf::Enum* enum_type =
+      typeinfo->GetEnumByTypeUrl(field.type_url());
+  if (!enum_type) {
+    GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
+                 << "'";
+    return DataPiece::NullData();
+  }
+  if (!field.default_value().empty()) {
+    if (!use_ints_for_enums) {
+      return DataPiece(field.default_value(), true);
+    } else {
+      const std::string& enum_default_value_name = field.default_value();
+      for (int enum_index = 0; enum_index < enum_type->enumvalue_size();
+           ++enum_index) {
+        auto& enum_value = enum_type->enumvalue(enum_index);
+        if (enum_value.name() == enum_default_value_name)
+          return DataPiece(enum_value.number());
+      }
+      GOOGLE_LOG(WARNING) << "Could not find enum value '" << enum_default_value_name
+                   << "' with type '" << field.type_url() << "'";
+      return DataPiece::NullData();
+    }
+  }
+  // We treat the first value as the default if none is specified.
+  return enum_type->enumvalue_size() > 0
+             ? (use_ints_for_enums
+                    ? DataPiece(enum_type->enumvalue(0).number())
+                    : DataPiece(enum_type->enumvalue(0).name(), true))
+             : DataPiece::NullData();
+}
+
+DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo,
+    bool use_ints_for_enums) {
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      return DataPiece(ConvertTo<double>(
+          field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      return DataPiece(ConvertTo<float>(
+          field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
+    }
+    case google::protobuf::Field::TYPE_INT64:
+    case google::protobuf::Field::TYPE_SINT64:
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      return DataPiece(ConvertTo<int64_t>(
+          field.default_value(), &DataPiece::ToInt64, static_cast<int64_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_UINT64:
+    case google::protobuf::Field::TYPE_FIXED64: {
+      return DataPiece(ConvertTo<uint64_t>(field.default_value(),
+                                           &DataPiece::ToUint64,
+                                           static_cast<uint64_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_INT32:
+    case google::protobuf::Field::TYPE_SINT32:
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      return DataPiece(ConvertTo<int32_t>(
+          field.default_value(), &DataPiece::ToInt32, static_cast<int32_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_BOOL: {
+      return DataPiece(
+          ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      return DataPiece(field.default_value(), true);
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      return DataPiece(field.default_value(), false, true);
+    }
+    case google::protobuf::Field::TYPE_UINT32:
+    case google::protobuf::Field::TYPE_FIXED32: {
+      return DataPiece(ConvertTo<uint32_t>(field.default_value(),
+                                           &DataPiece::ToUint32,
+                                           static_cast<uint32_t>(0)));
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      return FindEnumDefault(field, typeinfo, use_ints_for_enums);
+    }
+    default: {
+      return DataPiece::NullData();
+    }
+  }
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
+    StringPiece name) {
+  if (current_ == nullptr) {
+    std::vector<std::string> path;
+    root_.reset(CreateNewNode(std::string(name), &type_, OBJECT,
+                              DataPiece::NullData(), false, path,
+                              suppress_empty_list_, preserve_proto_field_names_,
+                              use_ints_for_enums_, field_scrub_callback_));
+    root_->PopulateChildren(typeinfo_);
+    current_ = root_.get();
+    return this;
+  }
+  MaybePopulateChildrenOfAny(current_);
+  Node* child = current_->FindChild(name);
+  if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) {
+    // If current_ is a list or a map node, we should create a new child and use
+    // the type of current_ as the type of the new child.
+    std::unique_ptr<Node> node(
+        CreateNewNode(std::string(name),
+                      ((current_->kind() == LIST || current_->kind() == MAP)
+                           ? current_->type()
+                           : nullptr),
+                      OBJECT, DataPiece::NullData(), false,
+                      child == nullptr ? current_->path() : child->path(),
+                      suppress_empty_list_, preserve_proto_field_names_,
+                      use_ints_for_enums_, field_scrub_callback_));
+    child = node.get();
+    current_->AddChild(node.release());
+  }
+
+  child->set_is_placeholder(false);
+  if (child->kind() == OBJECT && child->number_of_children() == 0) {
+    child->PopulateChildren(typeinfo_);
+  }
+
+  stack_.push(current_);
+  current_ = child;
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
+  if (stack_.empty()) {
+    // The root object ends here. Writes out the tree.
+    WriteRoot();
+    return this;
+  }
+  current_ = stack_.top();
+  stack_.pop();
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
+    StringPiece name) {
+  if (current_ == nullptr) {
+    std::vector<std::string> path;
+    root_.reset(CreateNewNode(std::string(name), &type_, LIST,
+                              DataPiece::NullData(), false, path,
+                              suppress_empty_list_, preserve_proto_field_names_,
+                              use_ints_for_enums_, field_scrub_callback_));
+    current_ = root_.get();
+    return this;
+  }
+  MaybePopulateChildrenOfAny(current_);
+  Node* child = current_->FindChild(name);
+  if (child == nullptr || child->kind() != LIST) {
+    std::unique_ptr<Node> node(CreateNewNode(
+        std::string(name), nullptr, LIST, DataPiece::NullData(), false,
+        child == nullptr ? current_->path() : child->path(),
+        suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
+        field_scrub_callback_));
+    child = node.get();
+    current_->AddChild(node.release());
+  }
+  child->set_is_placeholder(false);
+
+  stack_.push(current_);
+  current_ = child;
+  return this;
+}
+
+void DefaultValueObjectWriter::WriteRoot() {
+  root_->WriteTo(ow_);
+  root_.reset(nullptr);
+  current_ = nullptr;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
+  if (stack_.empty()) {
+    WriteRoot();
+    return this;
+  }
+  current_ = stack_.top();
+  stack_.pop();
+  return this;
+}
+
+void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
+                                               const DataPiece& data) {
+  MaybePopulateChildrenOfAny(current_);
+  if (current_->type() != nullptr && current_->type()->name() == kAnyType &&
+      name == "@type") {
+    util::StatusOr<std::string> data_string = data.ToString();
+    if (data_string.ok()) {
+      const std::string& string_value = data_string.value();
+      // If the type of current_ is "Any" and its "@type" field is being set
+      // here, sets the type of current_ to be the type specified by the
+      // "@type".
+      util::StatusOr<const google::protobuf::Type*> found_type =
+          typeinfo_->ResolveTypeUrl(string_value);
+      if (!found_type.ok()) {
+        GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
+      } else {
+        current_->set_type(found_type.value());
+      }
+      current_->set_is_any(true);
+      // If the "@type" field is placed after other fields, we should populate
+      // other children of primitive type now. Otherwise, we should wait until
+      // the first value field is rendered before we populate the children,
+      // because the "value" field of a Any message could be omitted.
+      if (current_->number_of_children() > 1 && current_->type() != nullptr) {
+        current_->PopulateChildren(typeinfo_);
+      }
+    }
+  }
+  Node* child = current_->FindChild(name);
+  if (child == nullptr || child->kind() != PRIMITIVE) {
+    // No children are found, creates a new child.
+    std::unique_ptr<Node> node(
+        CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false,
+                      child == nullptr ? current_->path() : child->path(),
+                      suppress_empty_list_, preserve_proto_field_names_,
+                      use_ints_for_enums_, field_scrub_callback_));
+    current_->AddChild(node.release());
+  } else {
+    child->set_data(data);
+    child->set_is_placeholder(false);
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/error_listener.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/error_listener.cpp
new file mode 100644
index 0000000..538307b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/error_listener.cpp
@@ -0,0 +1,42 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/error_listener.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/field_mask_utility.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/field_mask_utility.cpp
new file mode 100644
index 0000000..521bf48
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/field_mask_utility.cpp
@@ -0,0 +1,218 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/field_mask_utility.h>
+
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+
+// Appends a FieldMask path segment to a prefix.
+std::string AppendPathSegmentToPrefix(StringPiece prefix,
+                                      StringPiece segment) {
+  if (prefix.empty()) {
+    return std::string(segment);
+  }
+  if (segment.empty()) {
+    return std::string(prefix);
+  }
+  // If the segment is a map key, appends it to the prefix without the ".".
+  if (HasPrefixString(segment, "[\"")) {
+    return StrCat(prefix, segment);
+  }
+  return StrCat(prefix, ".", segment);
+}
+
+}  // namespace
+
+std::string ConvertFieldMaskPath(const StringPiece path,
+                                 ConverterCallback converter) {
+  std::string result;
+  result.reserve(path.size() << 1);
+
+  bool is_quoted = false;
+  bool is_escaping = false;
+  int current_segment_start = 0;
+
+  // Loops until 1 passed the end of the input to make handling the last
+  // segment easier.
+  for (size_t i = 0; i <= path.size(); ++i) {
+    // Outputs quoted string as-is.
+    if (is_quoted) {
+      if (i == path.size()) {
+        break;
+      }
+      result.push_back(path[i]);
+      if (is_escaping) {
+        is_escaping = false;
+      } else if (path[i] == '\\') {
+        is_escaping = true;
+      } else if (path[i] == '\"') {
+        current_segment_start = i + 1;
+        is_quoted = false;
+      }
+      continue;
+    }
+    if (i == path.size() || path[i] == '.' || path[i] == '(' ||
+        path[i] == ')' || path[i] == '\"') {
+      result += converter(
+          path.substr(current_segment_start, i - current_segment_start));
+      if (i < path.size()) {
+        result.push_back(path[i]);
+      }
+      current_segment_start = i + 1;
+    }
+    if (i < path.size() && path[i] == '\"') {
+      is_quoted = true;
+    }
+  }
+  return result;
+}
+
+util::Status DecodeCompactFieldMaskPaths(StringPiece paths,
+                                         PathSinkCallback path_sink) {
+  std::stack<std::string> prefix;
+  int length = paths.length();
+  int previous_position = 0;
+  bool in_map_key = false;
+  bool is_escaping = false;
+  // Loops until 1 passed the end of the input to make the handle of the last
+  // segment easier.
+  for (int i = 0; i <= length; ++i) {
+    if (i != length) {
+      // Skips everything in a map key until we hit the end of it, which is
+      // marked by an un-escaped '"' immediately followed by a ']'.
+      if (in_map_key) {
+        if (is_escaping) {
+          is_escaping = false;
+          continue;
+        }
+        if (paths[i] == '\\') {
+          is_escaping = true;
+          continue;
+        }
+        if (paths[i] != '\"') {
+          continue;
+        }
+        // Un-escaped '"' must be followed with a ']'.
+        if (i >= length - 1 || paths[i + 1] != ']') {
+          return util::InvalidArgumentError(StrCat(
+              "Invalid FieldMask '", paths,
+              "'. Map keys should be represented as [\"some_key\"]."));
+        }
+        // The end of the map key ("\"]") has been found.
+        in_map_key = false;
+        // Skips ']'.
+        i++;
+        // Checks whether the key ends at the end of a path segment.
+        if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' &&
+            paths[i + 1] != ')' && paths[i + 1] != '(') {
+          return util::InvalidArgumentError(StrCat(
+              "Invalid FieldMask '", paths,
+              "'. Map keys should be at the end of a path segment."));
+        }
+        is_escaping = false;
+        continue;
+      }
+
+      // We are not in a map key, look for the start of one.
+      if (paths[i] == '[') {
+        if (i >= length - 1 || paths[i + 1] != '\"') {
+          return util::InvalidArgumentError(StrCat(
+              "Invalid FieldMask '", paths,
+              "'. Map keys should be represented as [\"some_key\"]."));
+        }
+        // "[\"" starts a map key.
+        in_map_key = true;
+        i++;  // Skips the '\"'.
+        continue;
+      }
+      // If the current character is not a special character (',', '(' or ')'),
+      // continue to the next.
+      if (paths[i] != ',' && paths[i] != ')' && paths[i] != '(') {
+        continue;
+      }
+    }
+    // Gets the current segment - sub-string between previous position (after
+    // '(', ')', ',', or the beginning of the input) and the current position.
+    StringPiece segment =
+        paths.substr(previous_position, i - previous_position);
+    std::string current_prefix = prefix.empty() ? "" : prefix.top();
+
+    if (i < length && paths[i] == '(') {
+      // Builds a prefix and save it into the stack.
+      prefix.push(AppendPathSegmentToPrefix(current_prefix, segment));
+    } else if (!segment.empty()) {
+      // When the current character is ')', ',' or the current position has
+      // passed the end of the input, builds and outputs a new paths by
+      // concatenating the last prefix with the current segment.
+      RETURN_IF_ERROR(
+          path_sink(AppendPathSegmentToPrefix(current_prefix, segment)));
+    }
+
+    // Removes the last prefix after seeing a ')'.
+    if (i < length && paths[i] == ')') {
+      if (prefix.empty()) {
+        return util::InvalidArgumentError(
+            StrCat("Invalid FieldMask '", paths,
+                         "'. Cannot find matching '(' for all ')'."));
+      }
+      prefix.pop();
+    }
+    previous_position = i + 1;
+  }
+  if (in_map_key) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid FieldMask '", paths,
+                     "'. Cannot find matching ']' for all '['."));
+  }
+  if (!prefix.empty()) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid FieldMask '", paths,
+                     "'. Cannot find matching ')' for all '('."));
+  }
+  return util::Status();
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_escaping.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_escaping.cpp
new file mode 100644
index 0000000..c192ddc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_escaping.cpp
@@ -0,0 +1,372 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/json_escaping.h>
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+
+// Array of hex characters for conversion to hex.
+static const char kHex[] = "0123456789abcdef";
+
+// Characters 0x00 to 0x9f are very commonly used, so we provide a special
+// table lookup.
+//
+// For unicode code point ch < 0xa0:
+// kCommonEscapes[ch] is the escaped string of ch, if escaping is needed;
+//                    or an empty string, if escaping is not needed.
+static const char kCommonEscapes[160][7] = {
+    // C0 (ASCII and derivatives) control characters
+    "\\u0000", "\\u0001", "\\u0002", "\\u0003",  // 0x00
+    "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b",
+    "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012",
+    "\\u0013",  // 0x10
+    "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a",
+    "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f",
+    // Escaping of " and \ are required by www.json.org string definition.
+    // Escaping of < and > are required for HTML security.
+    "", "", "\\\"", "", "", "", "", "",                              // 0x20
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",  // 0x30
+    "", "", "", "", "\\u003c", "", "\\u003e", "", "", "", "", "", "", "", "",
+    "",                                                                  // 0x40
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",      // 0x50
+    "", "", "", "", "\\\\", "", "", "", "", "", "", "", "", "", "", "",  // 0x60
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",      // 0x70
+    "", "", "", "", "", "", "", "\\u007f",
+    // C1 (ISO 8859 and Unicode) extended control characters
+    "\\u0080", "\\u0081", "\\u0082", "\\u0083",  // 0x80
+    "\\u0084", "\\u0085", "\\u0086", "\\u0087", "\\u0088", "\\u0089", "\\u008a",
+    "\\u008b", "\\u008c", "\\u008d", "\\u008e", "\\u008f", "\\u0090", "\\u0091",
+    "\\u0092", "\\u0093",  // 0x90
+    "\\u0094", "\\u0095", "\\u0096", "\\u0097", "\\u0098", "\\u0099", "\\u009a",
+    "\\u009b", "\\u009c", "\\u009d", "\\u009e", "\\u009f"};
+
+// Determines if the given char value is a unicode surrogate code unit (either
+// high-surrogate or low-surrogate).
+inline bool IsSurrogate(uint32_t c) {
+  // Optimized form of:
+  // return c >= kMinHighSurrogate && c <= kMaxLowSurrogate;
+  // (Reduced from 3 ALU instructions to 2 ALU instructions)
+  return (c & 0xfffff800) == JsonEscaping::kMinHighSurrogate;
+}
+
+// Returns true if the given unicode code point cp is a valid
+// unicode code point (i.e. in the range 0 <= cp <= kMaxCodePoint).
+inline bool IsValidCodePoint(uint32_t cp) {
+  return cp <= JsonEscaping::kMaxCodePoint;
+}
+
+// Returns the low surrogate for the given unicode code point. The result is
+// meaningless if the given code point is not a supplementary character.
+inline uint16_t ToLowSurrogate(uint32_t cp) {
+  return (cp &
+          (JsonEscaping::kMaxLowSurrogate - JsonEscaping::kMinLowSurrogate)) +
+         JsonEscaping::kMinLowSurrogate;
+}
+
+// Returns the high surrogate for the given unicode code point. The result is
+// meaningless if the given code point is not a supplementary character.
+inline uint16_t ToHighSurrogate(uint32_t cp) {
+  return (cp >> 10) + (JsonEscaping::kMinHighSurrogate -
+                       (JsonEscaping::kMinSupplementaryCodePoint >> 10));
+}
+
+// Input str is encoded in UTF-8. A unicode code point could be encoded in
+// UTF-8 using anywhere from 1 to 4 characters, and it could span multiple
+// reads of the ByteSource.
+//
+// This function reads the next unicode code point from the input (str) at
+// the given position (index), taking into account any left-over partial
+// code point from the previous iteration (cp), together with the number
+// of characters left to read to complete this code point (num_left).
+//
+// This function assumes that the input (str) is valid at the given position
+// (index). In order words, at least one character could be read successfully.
+//
+// The code point read (partial or complete) is stored in (cp). Upon return,
+// (num_left) stores the number of characters that has yet to be read in
+// order to complete the current unicode code point. If the read is complete,
+// then (num_left) is 0. Also, (num_read) is the number of characters read.
+//
+// Returns false if we encounter an invalid UTF-8 string. Returns true
+// otherwise, including the case when we reach the end of the input (str)
+// before a complete unicode code point is read.
+bool ReadCodePoint(StringPiece str, int index, uint32_t* cp,
+                   int* num_left, int* num_read) {
+  if (*num_left == 0) {
+    // Last read was complete. Start reading a new unicode code point.
+    *cp = static_cast<uint8_t>(str[index++]);
+    *num_read = 1;
+    // The length of the code point is determined from reading the first byte.
+    //
+    // If the first byte is between:
+    //    0..0x7f: that's the value of the code point.
+    // 0x80..0xbf: <invalid>
+    // 0xc0..0xdf: 11-bit code point encoded in 2 bytes.
+    //                                   bit 10-6, bit 5-0
+    // 0xe0..0xef: 16-bit code point encoded in 3 bytes.
+    //                        bit 15-12, bit 11-6, bit 5-0
+    // 0xf0..0xf7: 21-bit code point encoded in 4 bytes.
+    //             bit 20-18, bit 17-12, bit 11-6, bit 5-0
+    // 0xf8..0xff: <invalid>
+    //
+    // Meaning of each bit:
+    // <msb> bit 7: 0 - single byte code point: bits 6-0 are values.
+    //              1 - multibyte code point
+    //       bit 6: 0 - subsequent bytes of multibyte code point:
+    //                  bits 5-0 are values.
+    //              1 - first byte of multibyte code point
+    //       bit 5: 0 - first byte of 2-byte code point: bits 4-0 are values.
+    //              1 - first byte of code point with >= 3 bytes.
+    //       bit 4: 0 - first byte of 3-byte code point: bits 3-0 are values.
+    //              1 - first byte of code point with >= 4 bytes.
+    //       bit 3: 0 - first byte of 4-byte code point: bits 2-0 are values.
+    //              1 - reserved for future expansion.
+    if (*cp <= 0x7f) {
+      return true;
+    } else if (*cp <= 0xbf) {
+      return false;
+    } else if (*cp <= 0xdf) {
+      *cp &= 0x1f;
+      *num_left = 1;
+    } else if (*cp <= 0xef) {
+      *cp &= 0x0f;
+      *num_left = 2;
+    } else if (*cp <= 0xf7) {
+      *cp &= 0x07;
+      *num_left = 3;
+    } else {
+      return false;
+    }
+  } else {
+    // Last read was partial. Initialize num_read to 0 and continue reading
+    // the last unicode code point.
+    *num_read = 0;
+  }
+  while (*num_left > 0 && index < static_cast<int>(str.size())) {
+    uint32_t ch = static_cast<uint8_t>(str[index++]);
+    --(*num_left);
+    ++(*num_read);
+    *cp = (*cp << 6) | (ch & 0x3f);
+    if (ch < 0x80 || ch > 0xbf) return false;
+  }
+  return *num_left > 0 || (!IsSurrogate(*cp) && IsValidCodePoint(*cp));
+}
+
+// Stores the 16-bit unicode code point as its hexadecimal digits in buffer
+// and returns a StringPiece that points to this buffer. The input buffer needs
+// to be at least 6 bytes long.
+StringPiece ToHex(uint16_t cp, char* buffer) {
+  buffer[5] = kHex[cp & 0x0f];
+  cp >>= 4;
+  buffer[4] = kHex[cp & 0x0f];
+  cp >>= 4;
+  buffer[3] = kHex[cp & 0x0f];
+  cp >>= 4;
+  buffer[2] = kHex[cp & 0x0f];
+  return StringPiece(buffer, 6);
+}
+
+// Stores the 32-bit unicode code point as its hexadecimal digits in buffer
+// and returns a StringPiece that points to this buffer. The input buffer needs
+// to be at least 12 bytes long.
+StringPiece ToSurrogateHex(uint32_t cp, char* buffer) {
+  uint16_t low = ToLowSurrogate(cp);
+  uint16_t high = ToHighSurrogate(cp);
+
+  buffer[11] = kHex[low & 0x0f];
+  low >>= 4;
+  buffer[10] = kHex[low & 0x0f];
+  low >>= 4;
+  buffer[9] = kHex[low & 0x0f];
+  low >>= 4;
+  buffer[8] = kHex[low & 0x0f];
+
+  buffer[5] = kHex[high & 0x0f];
+  high >>= 4;
+  buffer[4] = kHex[high & 0x0f];
+  high >>= 4;
+  buffer[3] = kHex[high & 0x0f];
+  high >>= 4;
+  buffer[2] = kHex[high & 0x0f];
+
+  return StringPiece(buffer, 12);
+}
+
+// If the given unicode code point needs escaping, then returns the
+// escaped form. The returned StringPiece either points to statically
+// pre-allocated char[] or to the given buffer. The input buffer needs
+// to be at least 12 bytes long.
+//
+// If the given unicode code point does not need escaping, an empty
+// StringPiece is returned.
+StringPiece EscapeCodePoint(uint32_t cp, char* buffer) {
+  if (cp < 0xa0) return kCommonEscapes[cp];
+  switch (cp) {
+    // These are not required by json spec
+    // but used to prevent security bugs in javascript.
+    case 0xfeff:  // Zero width no-break space
+    case 0xfff9:  // Interlinear annotation anchor
+    case 0xfffa:  // Interlinear annotation separator
+    case 0xfffb:  // Interlinear annotation terminator
+
+    case 0x00ad:  // Soft-hyphen
+    case 0x06dd:  // Arabic end of ayah
+    case 0x070f:  // Syriac abbreviation mark
+    case 0x17b4:  // Khmer vowel inherent Aq
+    case 0x17b5:  // Khmer vowel inherent Aa
+      return ToHex(cp, buffer);
+
+    default:
+      if ((cp >= 0x0600 && cp <= 0x0603) ||  // Arabic signs
+          (cp >= 0x200b && cp <= 0x200f) ||  // Zero width etc.
+          (cp >= 0x2028 && cp <= 0x202e) ||  // Separators etc.
+          (cp >= 0x2060 && cp <= 0x2064) ||  // Invisible etc.
+          (cp >= 0x206a && cp <= 0x206f)) {  // Shaping etc.
+        return ToHex(cp, buffer);
+      }
+
+      if (cp == 0x000e0001 ||                        // Language tag
+          (cp >= 0x0001d173 && cp <= 0x0001d17a) ||  // Music formatting
+          (cp >= 0x000e0020 && cp <= 0x000e007f)) {  // TAG symbols
+        return ToSurrogateHex(cp, buffer);
+      }
+  }
+  return StringPiece();
+}
+
+// Tries to escape the given code point first. If the given code point
+// does not need to be escaped, but force_output is true, then render
+// the given multi-byte code point in UTF8 in the buffer and returns it.
+StringPiece EscapeCodePoint(uint32_t cp, char* buffer,
+                                  bool force_output) {
+  StringPiece sp = EscapeCodePoint(cp, buffer);
+  if (force_output && sp.empty()) {
+    buffer[5] = (cp & 0x3f) | 0x80;
+    cp >>= 6;
+    if (cp <= 0x1f) {
+      buffer[4] = cp | 0xc0;
+      sp = StringPiece(buffer + 4, 2);
+      return sp;
+    }
+    buffer[4] = (cp & 0x3f) | 0x80;
+    cp >>= 6;
+    if (cp <= 0x0f) {
+      buffer[3] = cp | 0xe0;
+      sp = StringPiece(buffer + 3, 3);
+      return sp;
+    }
+    buffer[3] = (cp & 0x3f) | 0x80;
+    buffer[2] = ((cp >> 6) & 0x07) | 0xf0;
+    sp = StringPiece(buffer + 2, 4);
+  }
+  return sp;
+}
+
+}  // namespace
+
+void JsonEscaping::Escape(strings::ByteSource* input,
+                          strings::ByteSink* output) {
+  char buffer[12] = "\\udead\\ubee";
+  uint32_t cp = 0;   // Current unicode code point.
+  int num_left = 0;  // Num of chars to read to complete the code point.
+  while (input->Available() > 0) {
+    StringPiece str = input->Peek();
+    StringPiece escaped;
+    size_t i = 0;
+    int num_read;
+    bool ok;
+    bool cp_was_split = num_left > 0;
+    // Loop until we encounter either
+    //   i) a code point that needs to be escaped; or
+    //  ii) a split code point is completely read; or
+    // iii) a character that is not a valid utf8; or
+    //  iv) end of the StringPiece str is reached.
+    do {
+      ok = ReadCodePoint(str, i, &cp, &num_left, &num_read);
+      if (num_left > 0 || !ok) break;  // case iii or iv
+      escaped = EscapeCodePoint(cp, buffer, cp_was_split);
+      if (!escaped.empty()) break;  // case i or ii
+      i += num_read;
+      num_read = 0;
+    } while (i < str.length());  // case iv
+    // First copy the un-escaped prefix, if any, to the output ByteSink.
+    if (i > 0) input->CopyTo(output, i);
+    if (num_read > 0) input->Skip(num_read);
+    if (!ok) {
+      // Case iii: Report error.
+      // TODO(wpoon): Add error reporting.
+      num_left = 0;
+    } else if (num_left == 0 && !escaped.empty()) {
+      // Case i or ii: Append the escaped code point to the output ByteSink.
+      output->Append(escaped.data(), escaped.size());
+    }
+  }
+  if (num_left > 0) {
+    // Treat as case iii: report error.
+    // TODO(wpoon): Add error reporting.
+  }
+}
+
+void JsonEscaping::Escape(StringPiece input, strings::ByteSink* output) {
+  const size_t len = input.length();
+  const char* p = input.data();
+
+  bool can_skip_escaping = true;
+  for (size_t i = 0; i < len; i++) {
+    char c = p[i];
+    if (c < 0x20 || c >= 0x7F || c == '"' || c == '<' || c == '>' ||
+        c == '\\') {
+      can_skip_escaping = false;
+      break;
+    }
+  }
+
+  if (can_skip_escaping) {
+    output->Append(input.data(), input.length());
+  } else {
+    strings::ArrayByteSource source(input);
+    Escape(&source, output);
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_objectwriter.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_objectwriter.cpp
new file mode 100644
index 0000000..1a86f00
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_objectwriter.cpp
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/json_objectwriter.h>
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/json_escaping.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+JsonObjectWriter::~JsonObjectWriter() {
+  if (element_ && !element_->is_root()) {
+    GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed.";
+  }
+}
+
+JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) {
+  WritePrefix(name);
+  WriteChar('{');
+  PushObject();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::EndObject() {
+  Pop();
+  WriteChar('}');
+  if (element() && element()->is_root()) NewLine();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) {
+  WritePrefix(name);
+  WriteChar('[');
+  PushArray();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::EndList() {
+  Pop();
+  WriteChar(']');
+  if (element()->is_root()) NewLine();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name,
+                                               bool value) {
+  return RenderSimple(name, value ? "true" : "false");
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name,
+                                                int32_t value) {
+  return RenderSimple(name, StrCat(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name,
+                                                 uint32_t value) {
+  return RenderSimple(name, StrCat(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name,
+                                                int64_t value) {
+  WritePrefix(name);
+  WriteChar('"');
+  WriteRawString(StrCat(value));
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
+                                                 uint64_t value) {
+  WritePrefix(name);
+  WriteChar('"');
+  WriteRawString(StrCat(value));
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
+                                                 double value) {
+  if (std::isfinite(value)) {
+    return RenderSimple(name, SimpleDtoa(value));
+  }
+
+  // Render quoted with NaN/Infinity-aware DoubleAsString.
+  return RenderString(name, DoubleAsString(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name,
+                                                float value) {
+  if (std::isfinite(value)) {
+    return RenderSimple(name, SimpleFtoa(value));
+  }
+
+  // Render quoted with NaN/Infinity-aware FloatAsString.
+  return RenderString(name, FloatAsString(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderString(StringPiece name,
+                                                 StringPiece value) {
+  WritePrefix(name);
+  WriteChar('"');
+  JsonEscaping::Escape(value, &sink_);
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name,
+                                                StringPiece value) {
+  WritePrefix(name);
+  std::string base64;
+
+  if (use_websafe_base64_for_bytes_)
+    WebSafeBase64EscapeWithPadding(std::string(value), &base64);
+  else
+    Base64Escape(value, &base64);
+
+  WriteChar('"');
+  // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes
+  //              directly to the stream, rather than first putting them
+  //              into a string and then writing them to the stream.
+  stream_->WriteRaw(base64.data(), base64.size());
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderNull(StringPiece name) {
+  return RenderSimple(name, "null");
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderNullAsEmpty(StringPiece name) {
+  return RenderSimple(name, "");
+}
+
+void JsonObjectWriter::WritePrefix(StringPiece name) {
+  bool not_first = !element()->is_first();
+  if (not_first) WriteChar(',');
+  if (not_first || !element()->is_root()) NewLine();
+  if (!name.empty() || element()->is_json_object()) {
+    WriteChar('"');
+    if (!name.empty()) {
+      JsonEscaping::Escape(name, &sink_);
+    }
+    WriteRawString("\":");
+    if (!indent_string_.empty()) WriteChar(' ');
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_stream_parser.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_stream_parser.cpp
new file mode 100644
index 0000000..e786781
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/json_stream_parser.cpp
@@ -0,0 +1,995 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/json_stream_parser.h>
+
+#include <algorithm>
+#include <cctype>
+#include <cmath>
+#include <memory>
+#include <stack>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/json_escaping.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+namespace converter {
+
+// Number of digits in an escaped UTF-16 code unit ('\\' 'u' X X X X)
+static const int kUnicodeEscapedLength = 6;
+
+static const int kDefaultMaxRecursionDepth = 100;
+
+// These cannot be constexpr for portability with VS2015.
+static const StringPiece kKeywordTrue = "true";
+static const StringPiece kKeywordFalse = "false";
+static const StringPiece kKeywordNull = "null";
+
+inline bool IsLetter(char c) {
+  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_') ||
+         (c == '$');
+}
+
+inline bool IsAlphanumeric(char c) {
+  return IsLetter(c) || ('0' <= c && c <= '9');
+}
+
+// Indicates a character may not be part of an unquoted key.
+inline bool IsKeySeparator(char c) {
+  return (ascii_isspace(c) || c == '"' || c == '\'' || c == '{' ||
+          c == '}' || c == '[' || c == ']' || c == ':' || c == ',');
+}
+
+inline void ReplaceInvalidCodePoints(StringPiece str,
+                                     const std::string& replacement,
+                                     std::string* dst) {
+  while (!str.empty()) {
+    size_t n_valid_bytes = internal::UTF8SpnStructurallyValid(str);
+    StringPiece valid_part = str.substr(0, n_valid_bytes);
+    StrAppend(dst, valid_part);
+
+    if (n_valid_bytes == str.size()) {
+      break;
+    }
+
+    // Append replacement value.
+    StrAppend(dst, replacement);
+
+    // Move past valid bytes + one invalid byte.
+    str.remove_prefix(n_valid_bytes + 1);
+  }
+}
+
+static bool ConsumeKey(StringPiece* input, StringPiece* key) {
+  if (input->empty() || !IsLetter((*input)[0])) return false;
+  size_t len = 1;
+  for (; len < input->size(); ++len) {
+    if (!IsAlphanumeric((*input)[len])) {
+      break;
+    }
+  }
+  *key = StringPiece(input->data(), len);
+  *input = StringPiece(input->data() + len, input->size() - len);
+  return true;
+}
+
+// Same as 'ConsumeKey', but allows a widened set of key characters.
+static bool ConsumeKeyPermissive(StringPiece* input,
+                                 StringPiece* key) {
+  if (input->empty() || !IsLetter((*input)[0])) return false;
+  size_t len = 1;
+  for (; len < input->size(); ++len) {
+    if (IsKeySeparator((*input)[len])) {
+      break;
+    }
+  }
+  *key = StringPiece(input->data(), len);
+  *input = StringPiece(input->data() + len, input->size() - len);
+  return true;
+}
+
+static bool MatchKey(StringPiece input) {
+  return !input.empty() && IsLetter(input[0]);
+}
+
+JsonStreamParser::JsonStreamParser(ObjectWriter* ow)
+    : ow_(ow),
+      stack_(),
+      leftover_(),
+      json_(),
+      p_(),
+      key_(),
+      key_storage_(),
+      finishing_(false),
+      seen_non_whitespace_(false),
+      allow_no_root_element_(false),
+      parsed_(),
+      parsed_storage_(),
+      string_open_(0),
+      chunk_storage_(),
+      coerce_to_utf8_(false),
+      utf8_replacement_character_(" "),
+      allow_empty_null_(false),
+      allow_permissive_key_naming_(false),
+      loose_float_number_conversion_(false),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  // Initialize the stack with a single value to be parsed.
+  stack_.push(VALUE);
+}
+
+JsonStreamParser::~JsonStreamParser() {}
+
+
+util::Status JsonStreamParser::Parse(StringPiece json) {
+  StringPiece chunk = json;
+  // If we have leftovers from a previous chunk, append the new chunk to it
+  // and create a new StringPiece pointing at the string's data. This could
+  // be large but we rely on the chunks to be small, assuming they are
+  // fragments of a Cord.
+  if (!leftover_.empty()) {
+    // Don't point chunk to leftover_ because leftover_ will be updated in
+    // ParseChunk(chunk).
+    chunk_storage_.swap(leftover_);
+    StrAppend(&chunk_storage_, json);
+    chunk = StringPiece(chunk_storage_);
+  }
+
+  // Find the structurally valid UTF8 prefix and parse only that.
+  int n = internal::UTF8SpnStructurallyValid(chunk);
+  if (n > 0) {
+    util::Status status = ParseChunk(chunk.substr(0, n));
+
+    // Any leftover characters are stashed in leftover_ for later parsing when
+    // there is more data available.
+    StrAppend(&leftover_, chunk.substr(n));
+    return status;
+  } else {
+    leftover_.assign(chunk.data(), chunk.size());
+    return util::Status();
+  }
+}
+
+util::Status JsonStreamParser::FinishParse() {
+  // If we do not expect anything and there is nothing left to parse we're all
+  // done.
+  if (stack_.empty() && leftover_.empty()) {
+    return util::Status();
+  }
+
+  // Lifetime needs to last until RunParser returns, so keep this variable
+  // outside of the coerce_to_utf8 block.
+  std::unique_ptr<std::string> scratch;
+
+  bool is_valid_utf8 = internal::IsStructurallyValidUTF8(leftover_);
+  if (coerce_to_utf8_ && !is_valid_utf8) {
+    scratch.reset(new std::string);
+    scratch->reserve(leftover_.size() * utf8_replacement_character_.size());
+    ReplaceInvalidCodePoints(leftover_, utf8_replacement_character_,
+                             scratch.get());
+    p_ = json_ = *scratch;
+  } else {
+    p_ = json_ = leftover_;
+    if (!is_valid_utf8) {
+      return ReportFailure("Encountered non UTF-8 code points.",
+                           ParseErrorType::NON_UTF_8);
+    }
+  }
+
+  // Parse the remainder in finishing mode, which reports errors for things like
+  // unterminated strings or unknown tokens that would normally be retried.
+  finishing_ = true;
+  util::Status result = RunParser();
+  if (result.ok()) {
+    SkipWhitespace();
+    if (!p_.empty()) {
+      result =
+          ReportFailure("Parsing terminated before end of input.",
+                        ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT);
+    }
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseChunk(StringPiece chunk) {
+  // Do not do any work if the chunk is empty.
+  if (chunk.empty()) return util::Status();
+
+  p_ = json_ = chunk;
+
+  finishing_ = false;
+  util::Status result = RunParser();
+  if (!result.ok()) return result;
+
+  SkipWhitespace();
+  if (p_.empty()) {
+    // If we parsed everything we had, clear the leftover.
+    leftover_.clear();
+  } else {
+    // If we do not expect anything i.e. stack is empty, and we have non-empty
+    // string left to parse, we report an error.
+    if (stack_.empty()) {
+      return ReportFailure(
+          "Parsing terminated before end of input.",
+          ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT);
+    }
+    // If we expect future data i.e. stack is non-empty, and we have some
+    // unparsed data left, we save it for later parse.
+    leftover_ = std::string(p_);
+  }
+  return util::Status();
+}
+
+bool JsonStreamParser::IsInputAllWhiteSpaces(TokenType type) {
+  // Conclude the whole input is full of white spaces by:
+  // - it is at the finishing stage
+  // - we have run out of the input data
+  // - haven't seen non-whitespace char so far
+  if (finishing_ && p_.empty() && type == UNKNOWN && !seen_non_whitespace_) {
+    return true;
+  }
+  return false;
+}
+
+util::Status JsonStreamParser::RunParser() {
+  while (!stack_.empty()) {
+    ParseType type = stack_.top();
+    TokenType t = (string_open_ == 0) ? GetNextTokenType() : BEGIN_STRING;
+    stack_.pop();
+    util::Status result;
+    switch (type) {
+      case VALUE:
+        if (allow_no_root_element_ && IsInputAllWhiteSpaces(t)) {
+          return util::Status();
+        }
+        result = ParseValue(t);
+        break;
+
+      case OBJ_MID:
+        result = ParseObjectMid(t);
+        break;
+
+      case ENTRY:
+        result = ParseEntry(t);
+        break;
+
+      case ENTRY_MID:
+        result = ParseEntryMid(t);
+        break;
+
+      case ARRAY_VALUE:
+        result = ParseArrayValue(t);
+        break;
+
+      case ARRAY_MID:
+        result = ParseArrayMid(t);
+        break;
+
+      default:
+        result =
+            util::InternalError(StrCat("Unknown parse type: ", type));
+        break;
+    }
+    if (!result.ok()) {
+      // If we were cancelled, save our state and try again later.
+      if (!finishing_ && util::IsCancelled(result)) {
+        stack_.push(type);
+        // If we have a key we still need to render, make sure to save off the
+        // contents in our own storage.
+        if (!key_.empty() && key_storage_.empty()) {
+          StrAppend(&key_storage_, key_);
+          key_ = StringPiece(key_storage_);
+        }
+        result = util::Status();
+      }
+      return result;
+    }
+  }
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseValue(TokenType type) {
+  switch (type) {
+    case BEGIN_OBJECT:
+      return HandleBeginObject();
+    case BEGIN_ARRAY:
+      return HandleBeginArray();
+    case BEGIN_STRING:
+      return ParseString();
+    case BEGIN_NUMBER:
+      return ParseNumber();
+    case BEGIN_TRUE:
+      return ParseTrue();
+    case BEGIN_FALSE:
+      return ParseFalse();
+    case BEGIN_NULL:
+      return ParseNull();
+    case UNKNOWN:
+      return ReportUnknown("Expected a value.", ParseErrorType::EXPECTED_VALUE);
+    default: {
+      // Special case for having been cut off while parsing, wait for more data.
+      // This handles things like 'fals' being at the end of the string, we
+      // don't know if the next char would be e, completing it, or something
+      // else, making it invalid.
+      if (!finishing_ && p_.length() < kKeywordFalse.length()) {
+        return util::CancelledError("");
+      }
+
+      if (allow_empty_null_ && IsEmptyNullAllowed(type)) {
+        return ParseEmptyNull();
+      }
+      return ReportFailure("Unexpected token.",
+                           ParseErrorType::UNEXPECTED_TOKEN);
+    }
+  }
+}
+
+util::Status JsonStreamParser::ParseString() {
+  util::Status result = ParseStringHelper();
+  if (result.ok()) {
+    ow_->RenderString(key_, parsed_);
+    key_ = StringPiece();
+    parsed_ = StringPiece();
+    parsed_storage_.clear();
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseStringHelper() {
+  // If we haven't seen the start quote, grab it and remember it for later.
+  if (string_open_ == 0) {
+    string_open_ = *p_.data();
+    GOOGLE_DCHECK(string_open_ == '\"' || string_open_ == '\'');
+    Advance();
+  }
+  // Track where we last copied data from so we can minimize copying.
+  const char* last = p_.data();
+  while (!p_.empty()) {
+    const char* data = p_.data();
+    if (*data == '\\') {
+      // We're about to handle an escape, copy all bytes from last to data.
+      if (last < data) {
+        parsed_storage_.append(last, data - last);
+      }
+      // If we ran out of string after the \, cancel or report an error
+      // depending on if we expect more data later.
+      if (p_.length() == 1) {
+        if (!finishing_) {
+          return util::CancelledError("");
+        }
+        return ReportFailure("Closing quote expected in string.",
+                             ParseErrorType::EXPECTED_CLOSING_QUOTE);
+      }
+      // Parse a unicode escape if we found \u in the string.
+      if (data[1] == 'u') {
+        util::Status result = ParseUnicodeEscape();
+        if (!result.ok()) {
+          return result;
+        }
+        // Move last pointer past the unicode escape and continue.
+        last = p_.data();
+        continue;
+      }
+      // Handle the standard set of backslash-escaped characters.
+      switch (data[1]) {
+        case 'b':
+          parsed_storage_.push_back('\b');
+          break;
+        case 'f':
+          parsed_storage_.push_back('\f');
+          break;
+        case 'n':
+          parsed_storage_.push_back('\n');
+          break;
+        case 'r':
+          parsed_storage_.push_back('\r');
+          break;
+        case 't':
+          parsed_storage_.push_back('\t');
+          break;
+        case 'v':
+          parsed_storage_.push_back('\v');
+          break;
+        default:
+          parsed_storage_.push_back(data[1]);
+      }
+      // We handled two characters, so advance past them and continue.
+      p_.remove_prefix(2);
+      last = p_.data();
+      continue;
+    }
+    // If we found the closing quote note it, advance past it, and return.
+    if (*data == string_open_) {
+      // If we didn't copy anything, reuse the input buffer.
+      if (parsed_storage_.empty()) {
+        parsed_ = StringPiece(last, data - last);
+      } else {
+        if (last < data) {
+          parsed_storage_.append(last, data - last);
+        }
+        parsed_ = StringPiece(parsed_storage_);
+      }
+      // Clear the quote char so next time we try to parse a string we'll
+      // start fresh.
+      string_open_ = 0;
+      Advance();
+      return util::Status();
+    }
+    // Normal character, just advance past it.
+    Advance();
+  }
+  // If we ran out of characters, copy over what we have so far.
+  if (last < p_.data()) {
+    parsed_storage_.append(last, p_.data() - last);
+  }
+  // If we didn't find the closing quote but we expect more data, cancel for now
+  if (!finishing_) {
+    return util::CancelledError("");
+  }
+  // End of string reached without a closing quote, report an error.
+  string_open_ = 0;
+  return ReportFailure("Closing quote expected in string.",
+                       ParseErrorType::EXPECTED_CLOSING_QUOTE);
+}
+
+// Converts a unicode escaped character to a decimal value stored in a char32
+// for use in UTF8 encoding utility.  We assume that str begins with \uhhhh and
+// convert that from the hex number to a decimal value.
+//
+// There are some security exploits with UTF-8 that we should be careful of:
+//   - http://www.unicode.org/reports/tr36/#UTF-8_Exploit
+//   - http://sites/intl-eng/design-guide/core-application
+util::Status JsonStreamParser::ParseUnicodeEscape() {
+  if (p_.length() < kUnicodeEscapedLength) {
+    if (!finishing_) {
+      return util::CancelledError("");
+    }
+    return ReportFailure("Illegal hex string.",
+                         ParseErrorType::ILLEGAL_HEX_STRING);
+  }
+  GOOGLE_DCHECK_EQ('\\', p_.data()[0]);
+  GOOGLE_DCHECK_EQ('u', p_.data()[1]);
+  uint32_t code = 0;
+  for (int i = 2; i < kUnicodeEscapedLength; ++i) {
+    if (!isxdigit(p_.data()[i])) {
+      return ReportFailure("Invalid escape sequence.",
+                           ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+    }
+    code = (code << 4) + hex_digit_to_int(p_.data()[i]);
+  }
+  if (code >= JsonEscaping::kMinHighSurrogate &&
+      code <= JsonEscaping::kMaxHighSurrogate) {
+    if (p_.length() < 2 * kUnicodeEscapedLength) {
+      if (!finishing_) {
+        return util::CancelledError("");
+      }
+      if (!coerce_to_utf8_) {
+        return ReportFailure("Missing low surrogate.",
+                             ParseErrorType::MISSING_LOW_SURROGATE);
+      }
+    } else if (p_.data()[kUnicodeEscapedLength] == '\\' &&
+               p_.data()[kUnicodeEscapedLength + 1] == 'u') {
+      uint32_t low_code = 0;
+      for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength;
+           ++i) {
+        if (!isxdigit(p_.data()[i])) {
+          return ReportFailure("Invalid escape sequence.",
+                               ParseErrorType::INVALID_ESCAPE_SEQUENCE);
+        }
+        low_code = (low_code << 4) + hex_digit_to_int(p_.data()[i]);
+      }
+      if (low_code >= JsonEscaping::kMinLowSurrogate &&
+          low_code <= JsonEscaping::kMaxLowSurrogate) {
+        // Convert UTF-16 surrogate pair to 21-bit Unicode codepoint.
+        code = (((code & 0x3FF) << 10) | (low_code & 0x3FF)) +
+               JsonEscaping::kMinSupplementaryCodePoint;
+        // Advance past the first code unit escape.
+        p_.remove_prefix(kUnicodeEscapedLength);
+      } else if (!coerce_to_utf8_) {
+        return ReportFailure("Invalid low surrogate.",
+                             ParseErrorType::INVALID_LOW_SURROGATE);
+      }
+    } else if (!coerce_to_utf8_) {
+      return ReportFailure("Missing low surrogate.",
+                           ParseErrorType::MISSING_LOW_SURROGATE);
+    }
+  }
+  if (!coerce_to_utf8_ && !IsValidCodePoint(code)) {
+    return ReportFailure("Invalid unicode code point.",
+                         ParseErrorType::INVALID_UNICODE);
+  }
+  char buf[UTFmax];
+  int len = EncodeAsUTF8Char(code, buf);
+  // Advance past the [final] code unit escape.
+  p_.remove_prefix(kUnicodeEscapedLength);
+  parsed_storage_.append(buf, len);
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseNumber() {
+  NumberResult number;
+  util::Status result = ParseNumberHelper(&number);
+  if (result.ok()) {
+    switch (number.type) {
+      case NumberResult::DOUBLE:
+        ow_->RenderDouble(key_, number.double_val);
+        key_ = StringPiece();
+        break;
+
+      case NumberResult::INT:
+        ow_->RenderInt64(key_, number.int_val);
+        key_ = StringPiece();
+        break;
+
+      case NumberResult::UINT:
+        ow_->RenderUint64(key_, number.uint_val);
+        key_ = StringPiece();
+        break;
+
+      default:
+        return ReportFailure("Unable to parse number.",
+                             ParseErrorType::UNABLE_TO_PARSE_NUMBER);
+    }
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseDoubleHelper(const std::string& number,
+                                                 NumberResult* result) {
+  if (!safe_strtod(number, &result->double_val)) {
+    return ReportFailure("Unable to parse number.",
+                         ParseErrorType::UNABLE_TO_PARSE_NUMBER);
+  }
+  if (!loose_float_number_conversion_ && !std::isfinite(result->double_val)) {
+    return ReportFailure("Number exceeds the range of double.",
+                         ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE);
+  }
+  result->type = NumberResult::DOUBLE;
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) {
+  const char* data = p_.data();
+  int length = p_.length();
+
+  // Look for the first non-numeric character, or the end of the string.
+  int index = 0;
+  bool floating = false;
+  bool negative = data[index] == '-';
+  // Find the first character that cannot be part of the number. Along the way
+  // detect if the number needs to be parsed as a double.
+  // Note that this restricts numbers to the JSON specification, so for example
+  // we do not support hex or octal notations.
+  for (; index < length; ++index) {
+    char c = data[index];
+    if (isdigit(c)) continue;
+    if (c == '.' || c == 'e' || c == 'E') {
+      floating = true;
+      continue;
+    }
+    if (c == '+' || c == '-' || c == 'x') continue;
+    // Not a valid number character, break out.
+    break;
+  }
+
+  // If the entire input is a valid number, and we may have more content in the
+  // future, we abort for now and resume when we know more.
+  if (index == length && !finishing_) {
+    return util::CancelledError("");
+  }
+
+  // Create a string containing just the number, so we can use safe_strtoX
+  std::string number = std::string(p_.substr(0, index));
+
+  // Floating point number, parse as a double.
+  if (floating) {
+    util::Status status = ParseDoubleHelper(number, result);
+    if (status.ok()) {
+      p_.remove_prefix(index);
+    }
+    return status;
+  }
+
+  // Positive non-floating point number, parse as a uint64_t.
+  if (!negative) {
+    // Octal/Hex numbers are not valid JSON values.
+    if (number.length() >= 2 && number[0] == '0') {
+      return ReportFailure(
+          "Octal/hex numbers are not valid JSON values.",
+          ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+    }
+    if (safe_strtou64(number, &result->uint_val)) {
+      result->type = NumberResult::UINT;
+      p_.remove_prefix(index);
+      return util::Status();
+    } else {
+      // If the value is too large, parse it as double.
+      util::Status status = ParseDoubleHelper(number, result);
+      if (status.ok()) {
+        p_.remove_prefix(index);
+      }
+      return status;
+    }
+  }
+
+  // Octal/Hex numbers are not valid JSON values.
+  if (number.length() >= 3 && number[1] == '0') {
+    return ReportFailure(
+        "Octal/hex numbers are not valid JSON values.",
+        ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
+  }
+  // Negative non-floating point number, parse as an int64_t.
+  if (safe_strto64(number, &result->int_val)) {
+    result->type = NumberResult::INT;
+    p_.remove_prefix(index);
+    return util::Status();
+  } else {
+    // If the value is too large, parse it as double.
+    util::Status status = ParseDoubleHelper(number, result);
+    if (status.ok()) {
+      p_.remove_prefix(index);
+    }
+    return status;
+  }
+}
+
+util::Status JsonStreamParser::HandleBeginObject() {
+  GOOGLE_DCHECK_EQ('{', *p_.data());
+  Advance();
+  ow_->StartObject(key_);
+  auto status = IncrementRecursionDepth(key_);
+  if (!status.ok()) {
+    return status;
+  }
+  key_ = StringPiece();
+  stack_.push(ENTRY);
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseObjectMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected , or } after key:value pair.",
+                         ParseErrorType::EXPECTED_COMMA_OR_BRACES);
+  }
+
+  // Object is complete, advance past the comma and render the EndObject.
+  if (type == END_OBJECT) {
+    Advance();
+    ow_->EndObject();
+    --recursion_depth_;
+    return util::Status();
+  }
+  // Found a comma, advance past it and get ready for an entry.
+  if (type == VALUE_SEPARATOR) {
+    Advance();
+    stack_.push(ENTRY);
+    return util::Status();
+  }
+  // Illegal token after key:value pair.
+  return ReportFailure("Expected , or } after key:value pair.",
+                       ParseErrorType::EXPECTED_COMMA_OR_BRACES);
+}
+
+util::Status JsonStreamParser::ParseEntry(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected an object key or }.",
+                         ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+
+  // Close the object and return. This allows for trailing commas.
+  if (type == END_OBJECT) {
+    ow_->EndObject();
+    Advance();
+    --recursion_depth_;
+    return util::Status();
+  }
+
+  util::Status result;
+  if (type == BEGIN_STRING) {
+    // Key is a string (standard JSON), parse it and store the string.
+    result = ParseStringHelper();
+    if (result.ok()) {
+      key_storage_.clear();
+      if (!parsed_storage_.empty()) {
+        parsed_storage_.swap(key_storage_);
+        key_ = StringPiece(key_storage_);
+      } else {
+        key_ = parsed_;
+      }
+      parsed_ = StringPiece();
+    }
+  } else if (type == BEGIN_KEY) {
+    // Key is a bare key (back compat), create a StringPiece pointing to it.
+    result = ParseKey();
+  } else if (type == BEGIN_NULL || type == BEGIN_TRUE || type == BEGIN_FALSE) {
+    // Key may be a bare key that begins with a reserved word.
+    result = ParseKey();
+    if (result.ok() && (key_ == kKeywordNull || key_ == kKeywordTrue ||
+                        key_ == kKeywordFalse)) {
+      result = ReportFailure("Expected an object key or }.",
+                             ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+    }
+  } else {
+    // Unknown key type, report an error.
+    result = ReportFailure("Expected an object key or }.",
+                           ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES);
+  }
+  // On success we next expect an entry mid ':' then an object mid ',' or '}'
+  if (result.ok()) {
+    stack_.push(OBJ_MID);
+    stack_.push(ENTRY_MID);
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseEntryMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected : between key:value pair.",
+                         ParseErrorType::EXPECTED_COLON);
+  }
+  if (type == ENTRY_SEPARATOR) {
+    Advance();
+    stack_.push(VALUE);
+    return util::Status();
+  }
+  return ReportFailure("Expected : between key:value pair.",
+                       ParseErrorType::EXPECTED_COLON);
+}
+
+util::Status JsonStreamParser::HandleBeginArray() {
+  GOOGLE_DCHECK_EQ('[', *p_.data());
+  Advance();
+  ow_->StartList(key_);
+  key_ = StringPiece();
+  stack_.push(ARRAY_VALUE);
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseArrayValue(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected a value or ] within an array.",
+                         ParseErrorType::EXPECTED_VALUE_OR_BRACKET);
+  }
+
+  if (type == END_ARRAY) {
+    ow_->EndList();
+    Advance();
+    return util::Status();
+  }
+
+  // The ParseValue call may push something onto the stack so we need to make
+  // sure an ARRAY_MID is after it, so we push it on now. Also, the parsing of
+  // empty-null array value is relying on this ARRAY_MID token.
+  stack_.push(ARRAY_MID);
+  util::Status result = ParseValue(type);
+  if (util::IsCancelled(result)) {
+    // If we were cancelled, pop back off the ARRAY_MID so we don't try to
+    // push it on again when we try over.
+    stack_.pop();
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseArrayMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected , or ] after array value.",
+                         ParseErrorType::EXPECTED_COMMA_OR_BRACKET);
+  }
+
+  if (type == END_ARRAY) {
+    ow_->EndList();
+    Advance();
+    return util::Status();
+  }
+
+  // Found a comma, advance past it and expect an array value next.
+  if (type == VALUE_SEPARATOR) {
+    Advance();
+    stack_.push(ARRAY_VALUE);
+    return util::Status();
+  }
+  // Illegal token after array value.
+  return ReportFailure("Expected , or ] after array value.",
+                       ParseErrorType::EXPECTED_COMMA_OR_BRACKET);
+}
+
+util::Status JsonStreamParser::ParseTrue() {
+  ow_->RenderBool(key_, true);
+  key_ = StringPiece();
+  p_.remove_prefix(kKeywordTrue.length());
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseFalse() {
+  ow_->RenderBool(key_, false);
+  key_ = StringPiece();
+  p_.remove_prefix(kKeywordFalse.length());
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseNull() {
+  ow_->RenderNull(key_);
+  key_ = StringPiece();
+  p_.remove_prefix(kKeywordNull.length());
+  return util::Status();
+}
+
+util::Status JsonStreamParser::ParseEmptyNull() {
+  ow_->RenderNull(key_);
+  key_ = StringPiece();
+  return util::Status();
+}
+
+bool JsonStreamParser::IsEmptyNullAllowed(TokenType type) {
+  if (stack_.empty()) return false;
+  return (stack_.top() == ARRAY_MID && type == VALUE_SEPARATOR) ||
+         stack_.top() == OBJ_MID;
+}
+
+util::Status JsonStreamParser::ReportFailure(StringPiece message,
+                                             ParseErrorType parse_code) {
+  (void)parse_code;  // Parameter is used in Google-internal code.
+  static const int kContextLength = 20;
+  const char* p_start = p_.data();
+  const char* json_start = json_.data();
+  const char* begin = std::max(p_start - kContextLength, json_start);
+  const char* end =
+      std::min(p_start + kContextLength, json_start + json_.size());
+  StringPiece segment(begin, end - begin);
+  std::string location(p_start - begin, ' ');
+  location.push_back('^');
+  auto status = util::InvalidArgumentError(
+      StrCat(message, "\n", segment, "\n", location));
+  return status;
+}
+
+util::Status JsonStreamParser::ReportUnknown(StringPiece message,
+                                             ParseErrorType parse_code) {
+  // If we aren't finishing the parse, cancel parsing and try later.
+  if (!finishing_) {
+    return util::CancelledError("");
+  }
+  if (p_.empty()) {
+    return ReportFailure(StrCat("Unexpected end of string. ", message),
+                         parse_code);
+  }
+  return ReportFailure(message, parse_code);
+}
+
+util::Status JsonStreamParser::IncrementRecursionDepth(
+    StringPiece key) const {
+  if (++recursion_depth_ > max_recursion_depth_) {
+    return util::InvalidArgumentError(StrCat(
+        "Message too deep. Max recursion depth reached for key '", key, "'"));
+  }
+  return util::Status();
+}
+
+void JsonStreamParser::SkipWhitespace() {
+  while (!p_.empty() && ascii_isspace(*p_.data())) {
+    Advance();
+  }
+  if (!p_.empty() && !ascii_isspace(*p_.data())) {
+    seen_non_whitespace_ = true;
+  }
+}
+
+void JsonStreamParser::Advance() {
+  // Advance by moving one UTF8 character while making sure we don't go beyond
+  // the length of StringPiece.
+  p_.remove_prefix(std::min<int>(
+      p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length())));
+}
+
+util::Status JsonStreamParser::ParseKey() {
+  StringPiece original = p_;
+
+  if (allow_permissive_key_naming_) {
+    if (!ConsumeKeyPermissive(&p_, &key_)) {
+      return ReportFailure("Invalid key or variable name.",
+                           ParseErrorType::INVALID_KEY_OR_VARIABLE_NAME);
+    }
+  } else {
+    if (!ConsumeKey(&p_, &key_)) {
+      return ReportFailure("Invalid key or variable name.",
+                           ParseErrorType::INVALID_KEY_OR_VARIABLE_NAME);
+    }
+  }
+
+  // If we consumed everything but expect more data, reset p_ and cancel since
+  // we can't know if the key was complete or not.
+  if (!finishing_ && p_.empty()) {
+    p_ = original;
+    return util::CancelledError("");
+  }
+  // Since we aren't using the key storage, clear it out.
+  key_storage_.clear();
+  return util::Status();
+}
+
+JsonStreamParser::TokenType JsonStreamParser::GetNextTokenType() {
+  SkipWhitespace();
+
+  size_t size = p_.size();
+  if (size == 0) {
+    // If we ran out of data, report unknown and we'll place the previous parse
+    // type onto the stack and try again when we have more data.
+    return UNKNOWN;
+  }
+  // TODO(sven): Split this method based on context since different contexts
+  // support different tokens. Would slightly speed up processing?
+  const char* data = p_.data();
+  StringPiece data_view = StringPiece(data, size);
+  if (*data == '\"' || *data == '\'') return BEGIN_STRING;
+  if (*data == '-' || ('0' <= *data && *data <= '9')) {
+    return BEGIN_NUMBER;
+  }
+  if (size >= kKeywordTrue.length() &&
+      HasPrefixString(data_view, kKeywordTrue)) {
+    return BEGIN_TRUE;
+  }
+  if (size >= kKeywordFalse.length() &&
+      HasPrefixString(data_view, kKeywordFalse)) {
+    return BEGIN_FALSE;
+  }
+  if (size >= kKeywordNull.length() &&
+      HasPrefixString(data_view, kKeywordNull)) {
+    return BEGIN_NULL;
+  }
+  if (*data == '{') return BEGIN_OBJECT;
+  if (*data == '}') return END_OBJECT;
+  if (*data == '[') return BEGIN_ARRAY;
+  if (*data == ']') return END_ARRAY;
+  if (*data == ':') return ENTRY_SEPARATOR;
+  if (*data == ',') return VALUE_SEPARATOR;
+  if (MatchKey(p_)) {
+    return BEGIN_KEY;
+  }
+
+  // We don't know that we necessarily have an invalid token here, just that we
+  // can't parse what we have so far. So we don't report an error and just
+  // return UNKNOWN so we can try again later when we have more data, or if we
+  // finish and we have leftovers.
+  return UNKNOWN;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/object_writer.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/object_writer.cpp
new file mode 100644
index 0000000..4dabd37
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/object_writer.cpp
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/object_writer.h>
+
+#include <google/protobuf/util/internal/datapiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// static
+void ObjectWriter::RenderDataPieceTo(const DataPiece& data,
+                                     StringPiece name, ObjectWriter* ow) {
+  switch (data.type()) {
+    case DataPiece::TYPE_INT32: {
+      ow->RenderInt32(name, data.ToInt32().value());
+      break;
+    }
+    case DataPiece::TYPE_INT64: {
+      ow->RenderInt64(name, data.ToInt64().value());
+      break;
+    }
+    case DataPiece::TYPE_UINT32: {
+      ow->RenderUint32(name, data.ToUint32().value());
+      break;
+    }
+    case DataPiece::TYPE_UINT64: {
+      ow->RenderUint64(name, data.ToUint64().value());
+      break;
+    }
+    case DataPiece::TYPE_DOUBLE: {
+      ow->RenderDouble(name, data.ToDouble().value());
+      break;
+    }
+    case DataPiece::TYPE_FLOAT: {
+      ow->RenderFloat(name, data.ToFloat().value());
+      break;
+    }
+    case DataPiece::TYPE_BOOL: {
+      ow->RenderBool(name, data.ToBool().value());
+      break;
+    }
+    case DataPiece::TYPE_STRING: {
+      ow->RenderString(name, data.ToString().value());
+      break;
+    }
+    case DataPiece::TYPE_BYTES: {
+      ow->RenderBytes(name, data.ToBytes().value());
+      break;
+    }
+    case DataPiece::TYPE_NULL: {
+      ow->RenderNull(name);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/proto_writer.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/proto_writer.cpp
new file mode 100644
index 0000000..11b6df1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/proto_writer.cpp
@@ -0,0 +1,827 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/proto_writer.h>
+
+#include <cstdint>
+#include <functional>
+#include <stack>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using io::CodedOutputStream;
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
+
+ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
+                         const google::protobuf::Type& type,
+                         strings::ByteSink* output, ErrorListener* listener)
+    : master_type_(type),
+      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      done_(false),
+      ignore_unknown_fields_(false),
+      ignore_unknown_enum_values_(false),
+      use_lower_camel_for_enums_(false),
+      case_insensitive_enum_parsing_(true),
+      use_json_name_in_missing_fields_(false),
+      element_(nullptr),
+      size_insert_(),
+      output_(output),
+      buffer_(),
+      adapter_(&buffer_),
+      stream_(new CodedOutputStream(&adapter_)),
+      listener_(listener),
+      invalid_depth_(0),
+      tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
+                         const google::protobuf::Type& type,
+                         strings::ByteSink* output, ErrorListener* listener)
+    : master_type_(type),
+      typeinfo_(typeinfo),
+      own_typeinfo_(false),
+      done_(false),
+      ignore_unknown_fields_(false),
+      ignore_unknown_enum_values_(false),
+      use_lower_camel_for_enums_(false),
+      case_insensitive_enum_parsing_(true),
+      use_json_name_in_missing_fields_(false),
+      element_(nullptr),
+      size_insert_(),
+      output_(output),
+      buffer_(),
+      adapter_(&buffer_),
+      stream_(new CodedOutputStream(&adapter_)),
+      listener_(listener),
+      invalid_depth_(0),
+      tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::~ProtoWriter() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+  if (element_ == nullptr) return;
+  // Cleanup explicitly in order to avoid destructor stack overflow when input
+  // is deeply nested.
+  // Cast to BaseElement to avoid doing additional checks (like missing fields)
+  // during pop().
+  std::unique_ptr<BaseElement> element(
+      static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+  while (element != nullptr) {
+    element.reset(element->pop<BaseElement>());
+  }
+}
+
+namespace {
+
+// Writes an INT32 field, including tag to the stream.
+inline util::Status WriteInt32(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<int32_t> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteInt32(field_number, i32.value(), stream);
+  }
+  return i32.status();
+}
+
+// writes an SFIXED32 field, including tag, to the stream.
+inline util::Status WriteSFixed32(int field_number, const DataPiece& data,
+                                  CodedOutputStream* stream) {
+  util::StatusOr<int32_t> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSFixed32(field_number, i32.value(), stream);
+  }
+  return i32.status();
+}
+
+// Writes an SINT32 field, including tag, to the stream.
+inline util::Status WriteSInt32(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<int32_t> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSInt32(field_number, i32.value(), stream);
+  }
+  return i32.status();
+}
+
+// Writes a FIXED32 field, including tag, to the stream.
+inline util::Status WriteFixed32(int field_number, const DataPiece& data,
+                                 CodedOutputStream* stream) {
+  util::StatusOr<uint32_t> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteFixed32(field_number, u32.value(), stream);
+  }
+  return u32.status();
+}
+
+// Writes a UINT32 field, including tag, to the stream.
+inline util::Status WriteUInt32(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<uint32_t> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteUInt32(field_number, u32.value(), stream);
+  }
+  return u32.status();
+}
+
+// Writes an INT64 field, including tag, to the stream.
+inline util::Status WriteInt64(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<int64_t> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteInt64(field_number, i64.value(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SFIXED64 field, including tag, to the stream.
+inline util::Status WriteSFixed64(int field_number, const DataPiece& data,
+                                  CodedOutputStream* stream) {
+  util::StatusOr<int64_t> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSFixed64(field_number, i64.value(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SINT64 field, including tag, to the stream.
+inline util::Status WriteSInt64(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<int64_t> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSInt64(field_number, i64.value(), stream);
+  }
+  return i64.status();
+}
+
+// Writes a FIXED64 field, including tag, to the stream.
+inline util::Status WriteFixed64(int field_number, const DataPiece& data,
+                                 CodedOutputStream* stream) {
+  util::StatusOr<uint64_t> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteFixed64(field_number, u64.value(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a UINT64 field, including tag, to the stream.
+inline util::Status WriteUInt64(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<uint64_t> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteUInt64(field_number, u64.value(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a DOUBLE field, including tag, to the stream.
+inline util::Status WriteDouble(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<double> d = data.ToDouble();
+  if (d.ok()) {
+    WireFormatLite::WriteDouble(field_number, d.value(), stream);
+  }
+  return d.status();
+}
+
+// Writes a FLOAT field, including tag, to the stream.
+inline util::Status WriteFloat(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<float> f = data.ToFloat();
+  if (f.ok()) {
+    WireFormatLite::WriteFloat(field_number, f.value(), stream);
+  }
+  return f.status();
+}
+
+// Writes a BOOL field, including tag, to the stream.
+inline util::Status WriteBool(int field_number, const DataPiece& data,
+                              CodedOutputStream* stream) {
+  util::StatusOr<bool> b = data.ToBool();
+  if (b.ok()) {
+    WireFormatLite::WriteBool(field_number, b.value(), stream);
+  }
+  return b.status();
+}
+
+// Writes a BYTES field, including tag, to the stream.
+inline util::Status WriteBytes(int field_number, const DataPiece& data,
+                               CodedOutputStream* stream) {
+  util::StatusOr<std::string> c = data.ToBytes();
+  if (c.ok()) {
+    WireFormatLite::WriteBytes(field_number, c.value(), stream);
+  }
+  return c.status();
+}
+
+// Writes a STRING field, including tag, to the stream.
+inline util::Status WriteString(int field_number, const DataPiece& data,
+                                CodedOutputStream* stream) {
+  util::StatusOr<std::string> s = data.ToString();
+  if (s.ok()) {
+    WireFormatLite::WriteString(field_number, s.value(), stream);
+  }
+  return s.status();
+}
+
+// Given a google::protobuf::Type, returns the set of all required fields.
+std::unordered_set<const google::protobuf::Field*> GetRequiredFields(
+    const google::protobuf::Type& type) {
+  std::unordered_set<const google::protobuf::Field*> required;
+  for (int i = 0; i < type.fields_size(); i++) {
+    const google::protobuf::Field& field = type.fields(i);
+    if (field.cardinality() == google::protobuf::Field::CARDINALITY_REQUIRED) {
+      required.insert(&field);
+    }
+  }
+  return required;
+}
+
+}  // namespace
+
+ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
+                                        const google::protobuf::Type& type,
+                                        ProtoWriter* enclosing)
+    : BaseElement(nullptr),
+      ow_(enclosing),
+      parent_field_(nullptr),
+      typeinfo_(typeinfo),
+      proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
+      type_(type),
+      size_index_(-1),
+      array_index_(-1),
+      // oneof_indices_ values are 1-indexed (0 means not present).
+      oneof_indices_(type.oneofs_size() + 1) {
+  if (!proto3_) {
+    required_fields_ = GetRequiredFields(type_);
+  }
+}
+
+ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
+                                        const google::protobuf::Field* field,
+                                        const google::protobuf::Type& type,
+                                        bool is_list)
+    : BaseElement(parent),
+      ow_(this->parent()->ow_),
+      parent_field_(field),
+      typeinfo_(this->parent()->typeinfo_),
+      proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
+      type_(type),
+      size_index_(!is_list &&
+                          field->kind() == google::protobuf::Field::TYPE_MESSAGE
+                      ? ow_->size_insert_.size()
+                      : -1),
+      array_index_(is_list ? 0 : -1),
+      // oneof_indices_ values are 1-indexed (0 means not present).
+      oneof_indices_(type_.oneofs_size() + 1) {
+  if (!is_list) {
+    if (ow_->IsRepeated(*field)) {
+      // Update array_index_ if it is an explicit list.
+      if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
+    } else if (!proto3_) {
+      // For required fields tracking.
+      this->parent()->RegisterField(field);
+    }
+
+    if (field->kind() == google::protobuf::Field::TYPE_MESSAGE) {
+      if (!proto3_) {
+        required_fields_ = GetRequiredFields(type_);
+      }
+      int start_pos = ow_->stream_->ByteCount();
+      // length of serialized message is the final buffer position minus
+      // starting buffer position, plus length adjustments for size fields
+      // of any nested messages. We start with -start_pos here, so we only
+      // need to add the final buffer position to it at the end.
+      SizeInfo info = {start_pos, -start_pos};
+      ow_->size_insert_.push_back(info);
+    }
+  }
+}
+
+ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
+  if (!proto3_) {
+    // Calls the registered error listener for any required field(s) not yet
+    // seen.
+    for (std::unordered_set<const google::protobuf::Field*>::iterator it =
+             required_fields_.begin();
+         it != required_fields_.end(); ++it) {
+      ow_->MissingField(ow_->use_json_name_in_missing_fields_
+                            ? (*it)->json_name()
+                            : (*it)->name());
+    }
+  }
+  // Computes the total number of proto bytes used by a message, also adjusts
+  // the size of all parent messages by the length of this size field.
+  // If size_index_ < 0, this is not a message, so no size field is added.
+  if (size_index_ >= 0) {
+    // Add the final buffer position to compute the total length of this
+    // serialized message. The stored value (before this addition) already
+    // contains the total length of the size fields of all nested messages
+    // minus the initial buffer position.
+    ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
+    // Calculate the length required to serialize the size field of the
+    // message, and propagate this additional size information upward to
+    // all enclosing messages.
+    int size = ow_->size_insert_[size_index_].size;
+    int length = CodedOutputStream::VarintSize32(size);
+    for (ProtoElement* e = parent(); e != nullptr; e = e->parent()) {
+      // Only nested messages have size field, lists do not have size field.
+      if (e->size_index_ >= 0) {
+        ow_->size_insert_[e->size_index_].size += length;
+      }
+    }
+  }
+  return BaseElement::pop<ProtoElement>();
+}
+
+void ProtoWriter::ProtoElement::RegisterField(
+    const google::protobuf::Field* field) {
+  if (!required_fields_.empty() &&
+      field->cardinality() == google::protobuf::Field::CARDINALITY_REQUIRED) {
+    required_fields_.erase(field);
+  }
+}
+
+std::string ProtoWriter::ProtoElement::ToString() const {
+  std::string loc = "";
+
+  // first populate a stack with the nodes since we need to process them
+  // from root to leaf when generating the string location
+  const ProtoWriter::ProtoElement* now = this;
+  std::stack<const ProtoWriter::ProtoElement*> element_stack;
+  while (now->parent() != nullptr) {
+    element_stack.push(now);
+    now = now->parent();
+  }
+
+  // now pop each node from the stack and append to the location string
+  while (!element_stack.empty()) {
+    now = element_stack.top();
+    element_stack.pop();
+
+    if (!ow_->IsRepeated(*(now->parent_field_)) ||
+        now->parent()->parent_field_ != now->parent_field_) {
+      std::string name = now->parent_field_->name();
+      size_t i = 0;
+      while (i < name.size() &&
+             (ascii_isalnum(name[i]) || name[i] == '_'))
+        ++i;
+      if (i > 0 && i == name.size()) {  // safe field name
+        if (loc.empty()) {
+          loc = name;
+        } else {
+          StrAppend(&loc, ".", name);
+        }
+      } else {
+        StrAppend(&loc, "[\"", CEscape(name), "\"]");
+      }
+    }
+
+    int array_index_now = now->array_index_;
+    if (ow_->IsRepeated(*(now->parent_field_)) && array_index_now > 0) {
+      StrAppend(&loc, "[", array_index_now - 1, "]");
+    }
+  }
+
+  return loc;
+}
+
+bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32_t index) {
+  return oneof_indices_[index];
+}
+
+void ProtoWriter::ProtoElement::TakeOneofIndex(int32_t index) {
+  oneof_indices_[index] = true;
+}
+
+void ProtoWriter::InvalidName(StringPiece unknown_name,
+                              StringPiece message) {
+  listener_->InvalidName(location(), unknown_name, message);
+}
+
+void ProtoWriter::InvalidValue(StringPiece type_name,
+                               StringPiece value) {
+  listener_->InvalidValue(location(), type_name, value);
+}
+
+void ProtoWriter::MissingField(StringPiece missing_name) {
+  listener_->MissingField(location(), missing_name);
+}
+
+ProtoWriter* ProtoWriter::StartObject(
+    StringPiece name) {
+  // Starting the root message. Create the root ProtoElement and return.
+  if (element_ == nullptr) {
+    if (!name.empty()) {
+      InvalidName(name, "Root element should not be named.");
+    }
+    element_.reset(new ProtoElement(typeinfo_, master_type_, this));
+    return this;
+  }
+
+  const google::protobuf::Field* field = BeginNamed(name, false);
+
+  if (field == nullptr) return this;
+
+  // Check to see if this field is a oneof and that no oneof in that group has
+  // already been set.
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == nullptr) {
+    ++invalid_depth_;
+    InvalidName(name, StrCat("Missing descriptor for field: ",
+                                   field->type_url()));
+    return this;
+  }
+
+  return StartObjectField(*field, *type);
+}
+
+
+ProtoWriter* ProtoWriter::EndObject() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+    return this;
+  }
+
+  if (element_ != nullptr) {
+    element_.reset(element_->pop());
+  }
+
+
+  // If ending the root element,
+  // then serialize the full message with calculated sizes.
+  if (element_ == nullptr) {
+    WriteRootMessage();
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartList(
+    StringPiece name) {
+
+  const google::protobuf::Field* field = BeginNamed(name, true);
+
+  if (field == nullptr) return this;
+
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == nullptr) {
+    ++invalid_depth_;
+    InvalidName(name, StrCat("Missing descriptor for field: ",
+                                   field->type_url()));
+    return this;
+  }
+
+  return StartListField(*field, *type);
+}
+
+
+ProtoWriter* ProtoWriter::EndList() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+  } else if (element_ != nullptr) {
+    element_.reset(element_->pop());
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& data) {
+  util::Status status;
+  if (invalid_depth_ > 0) return this;
+
+  const google::protobuf::Field* field = Lookup(name);
+
+  if (field == nullptr) return this;
+
+  if (!ValidOneof(*field, name)) return this;
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == nullptr) {
+    InvalidName(name, StrCat("Missing descriptor for field: ",
+                                   field->type_url()));
+    return this;
+  }
+
+  return RenderPrimitiveField(*field, *type, data);
+}
+
+bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
+                             StringPiece unnormalized_name) {
+  if (element_ == nullptr) return true;
+
+  if (field.oneof_index() > 0) {
+    if (element_->IsOneofIndexTaken(field.oneof_index())) {
+      InvalidValue(
+          "oneof",
+          StrCat(
+              "oneof field '", element_->type().oneofs(field.oneof_index() - 1),
+              "' is already set. Cannot set '", unnormalized_name, "'"));
+      return false;
+    }
+    element_->TakeOneofIndex(field.oneof_index());
+  }
+  return true;
+}
+
+bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
+  return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED;
+}
+
+ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field,
+                                           const google::protobuf::Type& type) {
+    WriteTag(field);
+  element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field,
+                                         const google::protobuf::Type& type) {
+  element_.reset(new ProtoElement(element_.release(), &field, type, true));
+  return this;
+}
+
+util::Status ProtoWriter::WriteEnum(int field_number, const DataPiece& data,
+                                    const google::protobuf::Enum* enum_type,
+                                    CodedOutputStream* stream,
+                                    bool use_lower_camel_for_enums,
+                                    bool case_insensitive_enum_parsing,
+                                    bool ignore_unknown_values) {
+  bool is_unknown_enum_value = false;
+  util::StatusOr<int> e = data.ToEnum(
+      enum_type, use_lower_camel_for_enums, case_insensitive_enum_parsing,
+      ignore_unknown_values, &is_unknown_enum_value);
+  if (e.ok() && !is_unknown_enum_value) {
+    WireFormatLite::WriteEnum(field_number, e.value(), stream);
+  }
+  return e.status();
+}
+
+ProtoWriter* ProtoWriter::RenderPrimitiveField(
+    const google::protobuf::Field& field, const google::protobuf::Type& type,
+    const DataPiece& data) {
+  util::Status status;
+
+  // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
+  // error location reporting and required field accounting.
+  //
+  // For proto3, since there is no required field tracking, we only need to
+  // push ProtoElement for error cases.
+  if (!element_->proto3()) {
+    element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  }
+
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_INT32: {
+      status = WriteInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      status = WriteSFixed32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT32: {
+      status = WriteSInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED32: {
+      status = WriteFixed32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT32: {
+      status = WriteUInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT64: {
+      status = WriteInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      status = WriteSFixed64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT64: {
+      status = WriteSInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED64: {
+      status = WriteFixed64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT64: {
+      status = WriteUInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      status = WriteDouble(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      status = WriteFloat(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_BOOL: {
+      status = WriteBool(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      status = WriteBytes(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      status = WriteString(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      status = WriteEnum(
+          field.number(), data, typeinfo_->GetEnumByTypeUrl(field.type_url()),
+          stream_.get(), use_lower_camel_for_enums_,
+          case_insensitive_enum_parsing_, ignore_unknown_enum_values_);
+      break;
+    }
+    default:  // TYPE_GROUP, TYPE_MESSAGE, TYPE_UNKNOWN.
+      status = util::InvalidArgumentError(data.ValueAsStringOrDefault(""));
+  }
+
+  if (!status.ok()) {
+    // Push a ProtoElement for location reporting purposes.
+    if (element_->proto3()) {
+      element_.reset(new ProtoElement(element_.release(), &field, type, false));
+    }
+    InvalidValue(field.type_url().empty()
+                     ? google::protobuf::Field_Kind_Name(field.kind())
+                     : field.type_url(),
+                 status.message());
+    element_.reset(element()->pop());
+    return this;
+  }
+
+  if (!element_->proto3()) element_.reset(element()->pop());
+
+  return this;
+}
+
+const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
+                                                       bool is_list) {
+  if (invalid_depth_ > 0) {
+    ++invalid_depth_;
+    return nullptr;
+  }
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == nullptr) {
+    ++invalid_depth_;
+    // InvalidName() already called in Lookup().
+    return nullptr;
+  }
+  if (is_list && !IsRepeated(*field)) {
+    ++invalid_depth_;
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return nullptr;
+  }
+  return field;
+}
+
+const google::protobuf::Field* ProtoWriter::Lookup(
+    StringPiece unnormalized_name) {
+  ProtoElement* e = element();
+  if (e == nullptr) {
+    InvalidName(unnormalized_name, "Root element must be a message.");
+    return nullptr;
+  }
+  if (unnormalized_name.empty()) {
+    // Objects in repeated field inherit the same field descriptor.
+    if (e->parent_field() == nullptr) {
+      InvalidName(unnormalized_name, "Proto fields must have a name.");
+    } else if (!IsRepeated(*e->parent_field())) {
+      InvalidName(unnormalized_name, "Proto fields must have a name.");
+      return nullptr;
+    }
+    return e->parent_field();
+  }
+  const google::protobuf::Field* field =
+      typeinfo_->FindField(&e->type(), unnormalized_name);
+  if (field == nullptr && !ignore_unknown_fields_) {
+    InvalidName(unnormalized_name, "Cannot find field.");
+  }
+  return field;
+}
+
+const google::protobuf::Type* ProtoWriter::LookupType(
+    const google::protobuf::Field* field) {
+  return ((field->kind() == google::protobuf::Field::TYPE_MESSAGE ||
+           field->kind() == google::protobuf::Field::TYPE_GROUP)
+              ? typeinfo_->GetTypeByTypeUrl(field->type_url())
+              : &element_->type());
+}
+
+void ProtoWriter::WriteRootMessage() {
+  GOOGLE_DCHECK(!done_);
+  int curr_pos = 0;
+  // Calls the destructor of CodedOutputStream to remove any uninitialized
+  // memory from the Cord before we read it.
+  stream_.reset(nullptr);
+  const void* data;
+  int length;
+  io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
+  while (input_stream.Next(&data, &length)) {
+    if (length == 0) continue;
+    int num_bytes = length;
+    // Write up to where we need to insert the size field.
+    // The number of bytes we may write is the smaller of:
+    //   - the current fragment size
+    //   - the distance to the next position where a size field needs to be
+    //     inserted.
+    if (!size_insert_.empty() &&
+        size_insert_.front().pos - curr_pos < num_bytes) {
+      num_bytes = size_insert_.front().pos - curr_pos;
+    }
+    output_->Append(static_cast<const char*>(data), num_bytes);
+    if (num_bytes < length) {
+      input_stream.BackUp(length - num_bytes);
+    }
+    curr_pos += num_bytes;
+    // Insert the size field.
+    //   size_insert_.front():      the next <index, size> pair to be written.
+    //   size_insert_.front().pos:  position of the size field.
+    //   size_insert_.front().size: the size (integer) to be inserted.
+    if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
+      // Varint32 occupies at most 10 bytes.
+      uint8_t insert_buffer[10];
+      uint8_t* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
+          size_insert_.front().size, insert_buffer);
+      output_->Append(reinterpret_cast<const char*>(insert_buffer),
+                      insert_buffer_pos - insert_buffer);
+      size_insert_.pop_front();
+    }
+  }
+  output_->Flush();
+  stream_.reset(new CodedOutputStream(&adapter_));
+  done_ = true;
+}
+
+void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
+  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(field.kind()));
+  stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
+}
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/protostream_objectsource.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/protostream_objectsource.cpp
new file mode 100644
index 0000000..cf6c99a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/protostream_objectsource.cpp
@@ -0,0 +1,1114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+
+#include <cstdint>
+#include <unordered_map>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormat;
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
+
+namespace {
+
+static int kDefaultMaxRecursionDepth = 64;
+
+// Finds a field with the given number. nullptr if none found.
+const google::protobuf::Field* FindFieldByNumber(
+    const google::protobuf::Type& type, int number);
+
+// Returns true if the field is packable.
+bool IsPackable(const google::protobuf::Field& field);
+
+// Finds an enum value with the given number. nullptr if none found.
+const google::protobuf::EnumValue* FindEnumValueByNumber(
+    const google::protobuf::Enum& tech_enum, int number);
+
+// Utility function to format nanos.
+const std::string FormatNanos(uint32_t nanos, bool with_trailing_zeros);
+
+util::StatusOr<std::string> MapKeyDefaultValueAsString(
+    const google::protobuf::Field& field) {
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_BOOL:
+      return std::string("false");
+    case google::protobuf::Field::TYPE_INT32:
+    case google::protobuf::Field::TYPE_INT64:
+    case google::protobuf::Field::TYPE_UINT32:
+    case google::protobuf::Field::TYPE_UINT64:
+    case google::protobuf::Field::TYPE_SINT32:
+    case google::protobuf::Field::TYPE_SINT64:
+    case google::protobuf::Field::TYPE_SFIXED32:
+    case google::protobuf::Field::TYPE_SFIXED64:
+    case google::protobuf::Field::TYPE_FIXED32:
+    case google::protobuf::Field::TYPE_FIXED64:
+      return std::string("0");
+    case google::protobuf::Field::TYPE_STRING:
+      return std::string();
+    default:
+      return util::InternalError("Invalid map key type.");
+  }
+}
+}  // namespace
+
+
+ProtoStreamObjectSource::ProtoStreamObjectSource(
+    io::CodedInputStream* stream, TypeResolver* type_resolver,
+    const google::protobuf::Type& type, const RenderOptions& render_options)
+    : stream_(stream),
+      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      type_(type),
+      render_options_(render_options),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
+}
+
+ProtoStreamObjectSource::ProtoStreamObjectSource(
+    io::CodedInputStream* stream, const TypeInfo* typeinfo,
+    const google::protobuf::Type& type, const RenderOptions& render_options)
+    : stream_(stream),
+      typeinfo_(typeinfo),
+      own_typeinfo_(false),
+      type_(type),
+      render_options_(render_options),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
+}
+
+ProtoStreamObjectSource::~ProtoStreamObjectSource() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+}
+
+util::Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name,
+                                                   ObjectWriter* ow) const {
+  return WriteMessage(type_, name, 0, true, ow);
+}
+
+const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField(
+    const google::protobuf::Type& type, uint32_t tag) const {
+  // Lookup the new field in the type by tag number.
+  const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3);
+  // Verify if the field corresponds to the wire type in tag.
+  // If there is any discrepancy, mark the field as not found.
+  if (field != nullptr) {
+    WireFormatLite::WireType expected_type =
+        WireFormatLite::WireTypeForFieldType(
+            static_cast<WireFormatLite::FieldType>(field->kind()));
+    WireFormatLite::WireType actual_type = WireFormatLite::GetTagWireType(tag);
+    if (actual_type != expected_type &&
+        (!IsPackable(*field) ||
+         actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
+      field = nullptr;
+    }
+  }
+  return field;
+}
+
+util::Status ProtoStreamObjectSource::WriteMessage(
+    const google::protobuf::Type& type, StringPiece name,
+    const uint32_t end_tag, bool include_start_and_end,
+    ObjectWriter* ow) const {
+
+  const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
+  if (type_renderer != nullptr) {
+    return (*type_renderer)(this, type, name, ow);
+  }
+
+  const google::protobuf::Field* field = nullptr;
+  std::string field_name;
+  // last_tag set to dummy value that is different from tag.
+  uint32_t tag = stream_->ReadTag(), last_tag = tag + 1;
+  UnknownFieldSet unknown_fields;
+
+
+  if (include_start_and_end) {
+    ow->StartObject(name);
+  }
+  while (tag != end_tag && tag != 0) {
+    if (tag != last_tag) {  // Update field only if tag is changed.
+      last_tag = tag;
+      field = FindAndVerifyField(type, tag);
+      if (field != nullptr) {
+        if (render_options_.preserve_proto_field_names) {
+          field_name = field->name();
+        } else {
+          field_name = field->json_name();
+        }
+      }
+    }
+    if (field == nullptr) {
+      // If we didn't find a field, skip this unknown tag.
+      // TODO(wpoon): Check return boolean value.
+      WireFormat::SkipField(
+          stream_, tag,
+                                                nullptr);
+      tag = stream_->ReadTag();
+      continue;
+    }
+
+    if (field->cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) {
+      if (IsMap(*field)) {
+        ow->StartObject(field_name);
+        ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
+        ow->EndObject();
+      } else {
+        ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow));
+      }
+    } else {
+      // Render the field.
+      RETURN_IF_ERROR(RenderField(field, field_name, ow));
+      tag = stream_->ReadTag();
+    }
+  }
+
+
+  if (include_start_and_end) {
+    ow->EndObject();
+  }
+  return util::Status();
+}
+
+util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderList(
+    const google::protobuf::Field* field, StringPiece name,
+    uint32_t list_tag, ObjectWriter* ow) const {
+  uint32_t tag_to_return = 0;
+  ow->StartList(name);
+  if (IsPackable(*field) &&
+      list_tag ==
+          WireFormatLite::MakeTag(field->number(),
+                                  WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
+    RETURN_IF_ERROR(RenderPacked(field, ow));
+    // Since packed fields have a single tag, read another tag from stream to
+    // return.
+    tag_to_return = stream_->ReadTag();
+  } else {
+    do {
+      RETURN_IF_ERROR(RenderField(field, "", ow));
+    } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+  }
+  ow->EndList();
+  return tag_to_return;
+}
+
+util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderMap(
+    const google::protobuf::Field* field, StringPiece /* name */,
+    uint32_t list_tag, ObjectWriter* ow) const {
+  const google::protobuf::Type* field_type =
+      typeinfo_->GetTypeByTypeUrl(field->type_url());
+  uint32_t tag_to_return = 0;
+  do {
+    // Render map entry message type.
+    uint32_t buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    std::string map_key;
+    for (uint32_t tag = stream_->ReadTag(); tag != 0;
+         tag = stream_->ReadTag()) {
+      const google::protobuf::Field* map_entry_field =
+          FindAndVerifyField(*field_type, tag);
+      if (map_entry_field == nullptr) {
+        WireFormat::SkipField(stream_, tag, nullptr);
+        continue;
+      }
+      // Map field numbers are key = 1 and value = 2
+      if (map_entry_field->number() == 1) {
+        map_key = ReadFieldValueAsString(*map_entry_field);
+      } else if (map_entry_field->number() == 2) {
+        if (map_key.empty()) {
+          // An absent map key is treated as the default.
+          const google::protobuf::Field* key_field =
+              FindFieldByNumber(*field_type, 1);
+          if (key_field == nullptr) {
+            // The Type info for this map entry is incorrect. It should always
+            // have a field named "key" and with field number 1.
+            return util::InternalError("Invalid map entry.");
+          }
+          ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field));
+        }
+        RETURN_IF_ERROR(RenderField(map_entry_field, map_key, ow));
+      } else {
+        // The Type info for this map entry is incorrect. It should contain
+        // exactly two fields with field number 1 and 2.
+        return util::InternalError("Invalid map entry.");
+      }
+    }
+    stream_->PopLimit(old_limit);
+  } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+  return tag_to_return;
+}
+
+util::Status ProtoStreamObjectSource::RenderPacked(
+    const google::protobuf::Field* field, ObjectWriter* ow) const {
+  uint32_t length;
+  stream_->ReadVarint32(&length);
+  int old_limit = stream_->PushLimit(length);
+  while (stream_->BytesUntilLimit() > 0) {
+    RETURN_IF_ERROR(RenderField(field, StringPiece(), ow));
+  }
+  stream_->PopLimit(old_limit);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderTimestamp(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  std::pair<int64_t, int32_t> p = os->ReadSecondsAndNanos(type);
+  int64_t seconds = p.first;
+  int32_t nanos = p.second;
+  if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) {
+    return util::InternalError(StrCat(
+        "Timestamp seconds exceeds limit for field: ", field_name));
+  }
+
+  if (nanos < 0 || nanos >= kNanosPerSecond) {
+    return util::InternalError(
+        StrCat("Timestamp nanos exceeds limit for field: ", field_name));
+  }
+
+  ow->RenderString(field_name,
+                   ::google::protobuf::internal::FormatTime(seconds, nanos));
+
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderDuration(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  std::pair<int64_t, int32_t> p = os->ReadSecondsAndNanos(type);
+  int64_t seconds = p.first;
+  int32_t nanos = p.second;
+  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) {
+    return util::InternalError(
+        StrCat("Duration seconds exceeds limit for field: ", field_name));
+  }
+
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    return util::InternalError(
+        StrCat("Duration nanos exceeds limit for field: ", field_name));
+  }
+
+  std::string sign = "";
+  if (seconds < 0) {
+    if (nanos > 0) {
+      return util::InternalError(
+          StrCat("Duration nanos is non-negative, but seconds is "
+                       "negative for field: ",
+                       field_name));
+    }
+    sign = "-";
+    seconds = -seconds;
+    nanos = -nanos;
+  } else if (seconds == 0 && nanos < 0) {
+    sign = "-";
+    nanos = -nanos;
+  }
+  std::string formatted_duration = StringPrintf(
+      "%s%lld%ss", sign.c_str(), static_cast<long long>(seconds),  // NOLINT
+      FormatNanos(
+          nanos,
+          false
+          )
+          .c_str());
+  ow->RenderString(field_name, formatted_duration);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderDouble(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t buffer64 = 0;  // default value of Double wrapper value
+  if (tag != 0) {
+    os->stream_->ReadLittleEndian64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderDouble(field_name, bit_cast<double>(buffer64));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderFloat(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32 = 0;  // default value of Float wrapper value
+  if (tag != 0) {
+    os->stream_->ReadLittleEndian32(&buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderFloat(field_name, bit_cast<float>(buffer32));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderInt64(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t buffer64 = 0;  // default value of Int64 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderUInt64(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t buffer64 = 0;  // default value of UInt64 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderInt32(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32 = 0;  // default value of Int32 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderInt32(field_name, bit_cast<int32_t>(buffer32));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderUInt32(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32 = 0;  // default value of UInt32 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderUint32(field_name, bit_cast<uint32_t>(buffer32));
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderBool(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint64_t buffer64 = 0;  // results in 'false' value as default, which is the
+                          // default value of Bool wrapper
+  if (tag != 0) {
+    os->stream_->ReadVarint64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderBool(field_name, buffer64 != 0);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderString(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32;
+  std::string str;  // default value of empty for String wrapper
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);  // string size.
+    os->stream_->ReadString(&str, buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderString(field_name, str);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderBytes(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+  uint32_t buffer32;
+  std::string str;
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadString(&str, buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderBytes(field_name, str);
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderStruct(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  const google::protobuf::Field* field = nullptr;
+  uint32_t tag = os->stream_->ReadTag();
+  ow->StartObject(field_name);
+  while (tag != 0) {
+    field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      tag = os->stream_->ReadTag();
+      continue;
+    }
+    // google.protobuf.Struct has only one field that is a map. Hence we use
+    // RenderMap to render that field.
+    if (os->IsMap(*field)) {
+      ASSIGN_OR_RETURN(tag, os->RenderMap(field, field_name, tag, ow));
+    }
+  }
+  ow->EndObject();
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderStructValue(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  const google::protobuf::Field* field = nullptr;
+  for (uint32_t tag = os->stream_->ReadTag(); tag != 0;
+       tag = os->stream_->ReadTag()) {
+    field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      continue;
+    }
+    RETURN_IF_ERROR(os->RenderField(field, field_name, ow));
+  }
+  return util::Status();
+}
+
+// TODO(skarvaje): Avoid code duplication of for loops and SkipField logic.
+util::Status ProtoStreamObjectSource::RenderStructListValue(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32_t tag = os->stream_->ReadTag();
+
+  // Render empty list when we find empty ListValue message.
+  if (tag == 0) {
+    ow->StartList(field_name);
+    ow->EndList();
+    return util::Status();
+  }
+
+  while (tag != 0) {
+    const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      tag = os->stream_->ReadTag();
+      continue;
+    }
+    ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow));
+  }
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderAny(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  // An Any is of the form { string type_url = 1; bytes value = 2; }
+  uint32_t tag;
+  std::string type_url;
+  std::string value;
+
+  // First read out the type_url and value from the proto stream
+  for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) {
+    const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(os->stream_, tag, nullptr);
+      continue;
+    }
+    // 'type_url' has field number of 1 and 'value' has field number 2
+    // //google/protobuf/any.proto
+    if (field->number() == 1) {
+      // read type_url
+      uint32_t type_url_size;
+      os->stream_->ReadVarint32(&type_url_size);
+      os->stream_->ReadString(&type_url, type_url_size);
+    } else if (field->number() == 2) {
+      // read value
+      uint32_t value_size;
+      os->stream_->ReadVarint32(&value_size);
+      os->stream_->ReadString(&value, value_size);
+    }
+  }
+
+  // If there is no value, we don't lookup the type, we just output it (if
+  // present). If both type and value are empty we output an empty object.
+  if (value.empty()) {
+    ow->StartObject(field_name);
+    if (!type_url.empty()) {
+      ow->RenderString("@type", type_url);
+    }
+    ow->EndObject();
+    return util::Status();
+  }
+
+  // If there is a value but no type, we cannot render it, so report an error.
+  if (type_url.empty()) {
+    // TODO(sven): Add an external message once those are ready.
+    return util::InternalError("Invalid Any, the type_url is missing.");
+  }
+
+  util::StatusOr<const google::protobuf::Type*> resolved_type =
+      os->typeinfo_->ResolveTypeUrl(type_url);
+
+  if (!resolved_type.ok()) {
+    // Convert into an internal error, since this means the backend gave us
+    // an invalid response (missing or invalid type information).
+    return util::InternalError(resolved_type.status().message());
+  }
+  // nested_type cannot be null at this time.
+  const google::protobuf::Type* nested_type = resolved_type.value();
+
+  io::ArrayInputStream zero_copy_stream(value.data(), value.size());
+  io::CodedInputStream in_stream(&zero_copy_stream);
+  // We know the type so we can render it. Recursively parse the nested stream
+  // using a nested ProtoStreamObjectSource using our nested type information.
+  ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type,
+                                    os->render_options_);
+
+  // We manually call start and end object here so we can inject the @type.
+  ow->StartObject(field_name);
+  ow->RenderString("@type", type_url);
+  util::Status result =
+      nested_os.WriteMessage(nested_os.type_, "value", 0, false, ow);
+  ow->EndObject();
+  return result;
+}
+
+util::Status ProtoStreamObjectSource::RenderFieldMask(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  std::string combined;
+  uint32_t buffer32;
+  uint32_t paths_field_tag = 0;
+  for (uint32_t tag = os->stream_->ReadTag(); tag != 0;
+       tag = os->stream_->ReadTag()) {
+    if (paths_field_tag == 0) {
+      const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+      if (field != nullptr && field->number() == 1 &&
+          field->name() == "paths") {
+        paths_field_tag = tag;
+      }
+    }
+    if (paths_field_tag != tag) {
+      return util::InternalError("Invalid FieldMask, unexpected field.");
+    }
+    std::string str;
+    os->stream_->ReadVarint32(&buffer32);  // string size.
+    os->stream_->ReadString(&str, buffer32);
+    if (!combined.empty()) {
+      combined.append(",");
+    }
+    combined.append(ConvertFieldMaskPath(str, &ToCamelCase));
+  }
+  ow->RenderString(field_name, combined);
+  return util::Status();
+}
+
+
+std::unordered_map<std::string, ProtoStreamObjectSource::TypeRenderer>*
+    ProtoStreamObjectSource::renderers_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag source_renderers_init_;
+
+
+void ProtoStreamObjectSource::InitRendererMap() {
+  renderers_ = new std::unordered_map<std::string,
+                                      ProtoStreamObjectSource::TypeRenderer>();
+  (*renderers_)["google.protobuf.Timestamp"] =
+      &ProtoStreamObjectSource::RenderTimestamp;
+  (*renderers_)["google.protobuf.Duration"] =
+      &ProtoStreamObjectSource::RenderDuration;
+  (*renderers_)["google.protobuf.DoubleValue"] =
+      &ProtoStreamObjectSource::RenderDouble;
+  (*renderers_)["google.protobuf.FloatValue"] =
+      &ProtoStreamObjectSource::RenderFloat;
+  (*renderers_)["google.protobuf.Int64Value"] =
+      &ProtoStreamObjectSource::RenderInt64;
+  (*renderers_)["google.protobuf.UInt64Value"] =
+      &ProtoStreamObjectSource::RenderUInt64;
+  (*renderers_)["google.protobuf.Int32Value"] =
+      &ProtoStreamObjectSource::RenderInt32;
+  (*renderers_)["google.protobuf.UInt32Value"] =
+      &ProtoStreamObjectSource::RenderUInt32;
+  (*renderers_)["google.protobuf.BoolValue"] =
+      &ProtoStreamObjectSource::RenderBool;
+  (*renderers_)["google.protobuf.StringValue"] =
+      &ProtoStreamObjectSource::RenderString;
+  (*renderers_)["google.protobuf.BytesValue"] =
+      &ProtoStreamObjectSource::RenderBytes;
+  (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
+  (*renderers_)["google.protobuf.Struct"] =
+      &ProtoStreamObjectSource::RenderStruct;
+  (*renderers_)["google.protobuf.Value"] =
+      &ProtoStreamObjectSource::RenderStructValue;
+  (*renderers_)["google.protobuf.ListValue"] =
+      &ProtoStreamObjectSource::RenderStructListValue;
+  (*renderers_)["google.protobuf.FieldMask"] =
+      &ProtoStreamObjectSource::RenderFieldMask;
+  ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
+}
+
+void ProtoStreamObjectSource::DeleteRendererMap() {
+  delete ProtoStreamObjectSource::renderers_;
+  renderers_ = nullptr;
+}
+
+// static
+ProtoStreamObjectSource::TypeRenderer*
+ProtoStreamObjectSource::FindTypeRenderer(const std::string& type_url) {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(source_renderers_init_,
+                                             InitRendererMap);
+  return FindOrNull(*renderers_, type_url);
+}
+
+util::Status ProtoStreamObjectSource::RenderField(
+    const google::protobuf::Field* field, StringPiece field_name,
+    ObjectWriter* ow) const {
+  // Short-circuit message types as it tends to call WriteMessage recursively
+  // and ends up using a lot of stack space. Keep the stack usage of this
+  // message small in order to preserve stack space and not crash.
+  if (field->kind() == google::protobuf::Field::TYPE_MESSAGE) {
+    uint32_t buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    // Get the nested message type for this field.
+    const google::protobuf::Type* type =
+        typeinfo_->GetTypeByTypeUrl(field->type_url());
+    if (type == nullptr) {
+      return util::InternalError(
+          StrCat("Invalid configuration. Could not find the type: ",
+                       field->type_url()));
+    }
+
+    // Short-circuit any special type rendering to save call-stack space.
+    const TypeRenderer* type_renderer = FindTypeRenderer(type->name());
+
+    RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name));
+    if (type_renderer != nullptr) {
+      RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
+    } else {
+      RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
+    }
+    --recursion_depth_;
+
+    if (!stream_->ConsumedEntireMessage()) {
+      return util::InvalidArgumentError(
+          "Nested protocol message not parsed in its entirety.");
+    }
+    stream_->PopLimit(old_limit);
+  } else {
+    // Render all other non-message types.
+    return RenderNonMessageField(field, field_name, ow);
+  }
+  return util::Status();
+}
+
+util::Status ProtoStreamObjectSource::RenderNonMessageField(
+    const google::protobuf::Field* field, StringPiece field_name,
+    ObjectWriter* ow) const {
+  // Temporary buffers of different types.
+  uint32_t buffer32 = 0;
+  uint64_t buffer64 = 0;
+  std::string strbuffer;
+  switch (field->kind()) {
+    case google::protobuf::Field::TYPE_BOOL: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderBool(field_name, buffer64 != 0);
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderInt32(field_name, bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderUint32(field_name, bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderInt32(field_name, bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED32: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderUint32(field_name, bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED64: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderFloat(field_name, bit_cast<float>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderDouble(field_name, bit_cast<double>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      stream_->ReadVarint32(&buffer32);
+
+      // If the field represents an explicit NULL value, render null.
+      if (field->type_url() == kStructNullValueTypeUrl) {
+        ow->RenderNull(field_name);
+        break;
+      }
+
+      // Get the nested enum type for this field.
+      // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
+      // up.
+      const google::protobuf::Enum* en =
+          typeinfo_->GetEnumByTypeUrl(field->type_url());
+      // Lookup the name of the enum, and render that. Unknown enum values
+      // are printed as integers.
+      if (en != nullptr) {
+        const google::protobuf::EnumValue* enum_value =
+            FindEnumValueByNumber(*en, buffer32);
+        if (enum_value != nullptr) {
+          if (render_options_.use_ints_for_enums) {
+            ow->RenderInt32(field_name, buffer32);
+          } else if (render_options_.use_lower_camel_for_enums) {
+            ow->RenderString(field_name,
+                             EnumValueNameToLowerCamelCase(enum_value->name()));
+          } else {
+            ow->RenderString(field_name, enum_value->name());
+          }
+        } else {
+            ow->RenderInt32(field_name, buffer32);
+        }
+      } else {
+          ow->RenderInt32(field_name, buffer32);
+      }
+      break;
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      stream_->ReadVarint32(&buffer32);  // string size.
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderString(field_name, strbuffer);
+      break;
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      stream_->ReadVarint32(&buffer32);  // bytes size.
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderBytes(field_name, strbuffer);
+      break;
+    }
+    default:
+      break;
+  }
+  return util::Status();
+}
+
+// TODO(skarvaje): Fix this to avoid code duplication.
+const std::string ProtoStreamObjectSource::ReadFieldValueAsString(
+    const google::protobuf::Field& field) const {
+  std::string result;
+  switch (field.kind()) {
+    case google::protobuf::Field::TYPE_BOOL: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = buffer64 != 0 ? "true" : "false";
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT32: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = StrCat(bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_INT64: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = StrCat(bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT32: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = StrCat(bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_UINT64: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = StrCat(bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT32: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = StrCat(WireFormatLite::ZigZagDecode32(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SINT64: {
+      uint64_t buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = StrCat(WireFormatLite::ZigZagDecode64(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED32: {
+      uint32_t buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = StrCat(bit_cast<int32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_SFIXED64: {
+      uint64_t buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = StrCat(bit_cast<int64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED32: {
+      uint32_t buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = StrCat(bit_cast<uint32_t>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FIXED64: {
+      uint64_t buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = StrCat(bit_cast<uint64_t>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_FLOAT: {
+      uint32_t buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = SimpleFtoa(bit_cast<float>(buffer32));
+      break;
+    }
+    case google::protobuf::Field::TYPE_DOUBLE: {
+      uint64_t buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = SimpleDtoa(bit_cast<double>(buffer64));
+      break;
+    }
+    case google::protobuf::Field::TYPE_ENUM: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);
+      // Get the nested enum type for this field.
+      // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
+      // up.
+      const google::protobuf::Enum* en =
+          typeinfo_->GetEnumByTypeUrl(field.type_url());
+      // Lookup the name of the enum, and render that. Skips unknown enums.
+      if (en != nullptr) {
+        const google::protobuf::EnumValue* enum_value =
+            FindEnumValueByNumber(*en, buffer32);
+        if (enum_value != nullptr) {
+          result = enum_value->name();
+        }
+      }
+      break;
+    }
+    case google::protobuf::Field::TYPE_STRING: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);  // string size.
+      stream_->ReadString(&result, buffer32);
+      break;
+    }
+    case google::protobuf::Field::TYPE_BYTES: {
+      uint32_t buffer32;
+      stream_->ReadVarint32(&buffer32);  // bytes size.
+      stream_->ReadString(&result, buffer32);
+      break;
+    }
+    default:
+      break;
+  }
+  return result;
+}
+
+// Field is a map if it is a repeated message and it has an option "map_type".
+// TODO(skarvaje): Consider pre-computing the IsMap() into Field directly.
+bool ProtoStreamObjectSource::IsMap(
+    const google::protobuf::Field& field) const {
+  const google::protobuf::Type* field_type =
+      typeinfo_->GetTypeByTypeUrl(field.type_url());
+  return field.kind() == google::protobuf::Field::TYPE_MESSAGE &&
+         util::converter::IsMap(field, *field_type);
+}
+
+std::pair<int64_t, int32_t> ProtoStreamObjectSource::ReadSecondsAndNanos(
+    const google::protobuf::Type& type) const {
+  uint64_t seconds = 0;
+  uint32_t nanos = 0;
+  uint32_t tag = 0;
+  int64_t signed_seconds = 0;
+  int32_t signed_nanos = 0;
+
+  for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
+    const google::protobuf::Field* field = FindAndVerifyField(type, tag);
+    if (field == nullptr) {
+      WireFormat::SkipField(stream_, tag, nullptr);
+      continue;
+    }
+    // 'seconds' has field number of 1 and 'nanos' has field number 2
+    // //google/protobuf/timestamp.proto & duration.proto
+    if (field->number() == 1) {
+      // read seconds
+      stream_->ReadVarint64(&seconds);
+      signed_seconds = bit_cast<int64_t>(seconds);
+    } else if (field->number() == 2) {
+      // read nanos
+      stream_->ReadVarint32(&nanos);
+      signed_nanos = bit_cast<int32_t>(nanos);
+    }
+  }
+  return std::pair<int64_t, int32_t>(signed_seconds, signed_nanos);
+}
+
+util::Status ProtoStreamObjectSource::IncrementRecursionDepth(
+    StringPiece type_name, StringPiece field_name) const {
+  if (++recursion_depth_ > max_recursion_depth_) {
+    return util::InvalidArgumentError(
+        StrCat("Message too deep. Max recursion depth reached for type '",
+                     type_name, "', field '", field_name, "'"));
+  }
+  return util::Status();
+}
+
+namespace {
+// TODO(skarvaje): Speed this up by not doing a linear scan.
+const google::protobuf::Field* FindFieldByNumber(
+    const google::protobuf::Type& type, int number) {
+  for (int i = 0; i < type.fields_size(); ++i) {
+    if (type.fields(i).number() == number) {
+      return &type.fields(i);
+    }
+  }
+  return nullptr;
+}
+
+// TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable()
+// using tech Field.
+bool IsPackable(const google::protobuf::Field& field) {
+  return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED &&
+         FieldDescriptor::IsTypePackable(
+             static_cast<FieldDescriptor::Type>(field.kind()));
+}
+
+// TODO(skarvaje): Speed this up by not doing a linear scan.
+const google::protobuf::EnumValue* FindEnumValueByNumber(
+    const google::protobuf::Enum& tech_enum, int number) {
+  for (int i = 0; i < tech_enum.enumvalue_size(); ++i) {
+    const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i);
+    if (ev.number() == number) {
+      return &ev;
+    }
+  }
+  return nullptr;
+}
+
+// TODO(skarvaje): Look into optimizing this by not doing computation on
+// double.
+const std::string FormatNanos(uint32_t nanos, bool with_trailing_zeros) {
+  if (nanos == 0) {
+    return with_trailing_zeros ? ".000" : "";
+  }
+
+  const int precision = (nanos % 1000 != 0)      ? 9
+                        : (nanos % 1000000 != 0) ? 6
+                                                 : 3;
+  std::string formatted = StringPrintf(
+      "%.*f", precision, static_cast<double>(nanos) / kNanosPerSecond);
+  // remove the leading 0 before decimal.
+  return formatted.substr(1);
+}
+}  // namespace
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/protostream_objectwriter.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/protostream_objectwriter.cpp
new file mode 100644
index 0000000..ce94cfc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/protostream_objectwriter.cpp
@@ -0,0 +1,1401 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+
+#include <cstdint>
+#include <functional>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using util::Status;
+using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
+using std::placeholders::_1;
+
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    TypeResolver* type_resolver, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener,
+    const ProtoStreamObjectWriter::Options& options)
+    : ProtoWriter(type_resolver, type, output, listener),
+      master_type_(type),
+      current_(nullptr),
+      options_(options) {
+  set_ignore_unknown_fields(options_.ignore_unknown_fields);
+  set_ignore_unknown_enum_values(options_.ignore_unknown_enum_values);
+  set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums);
+  set_case_insensitive_enum_parsing(options_.case_insensitive_enum_parsing);
+  set_use_json_name_in_missing_fields(options.use_json_name_in_missing_fields);
+}
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    const TypeInfo* typeinfo, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener,
+    const ProtoStreamObjectWriter::Options& options)
+    : ProtoWriter(typeinfo, type, output, listener),
+      master_type_(type),
+      current_(nullptr),
+      options_(options) {
+  set_ignore_unknown_fields(options_.ignore_unknown_fields);
+  set_use_lower_camel_for_enums(options.use_lower_camel_for_enums);
+  set_case_insensitive_enum_parsing(options_.case_insensitive_enum_parsing);
+  set_use_json_name_in_missing_fields(options.use_json_name_in_missing_fields);
+}
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    const TypeInfo* typeinfo, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener)
+    : ProtoWriter(typeinfo, type, output, listener),
+      master_type_(type),
+      current_(nullptr),
+      options_(ProtoStreamObjectWriter::Options::Defaults()) {}
+
+ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
+  if (current_ == nullptr) return;
+  // Cleanup explicitly in order to avoid destructor stack overflow when input
+  // is deeply nested.
+  // Cast to BaseElement to avoid doing additional checks (like missing fields)
+  // during pop().
+  std::unique_ptr<BaseElement> element(
+      static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
+  while (element != nullptr) {
+    element.reset(element->pop<BaseElement>());
+  }
+}
+
+namespace {
+// Utility method to split a string representation of Timestamp or Duration and
+// return the parts.
+void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
+                          StringPiece* nanos) {
+  size_t idx = input.rfind('.');
+  if (idx != std::string::npos) {
+    *seconds = input.substr(0, idx);
+    *nanos = input.substr(idx + 1);
+  } else {
+    *seconds = input;
+    *nanos = StringPiece();
+  }
+}
+
+Status GetNanosFromStringPiece(StringPiece s_nanos,
+                               const char* parse_failure_message,
+                               const char* exceeded_limit_message,
+                               int32_t* nanos) {
+  *nanos = 0;
+
+  // Count the number of leading 0s and consume them.
+  int num_leading_zeros = 0;
+  while (s_nanos.Consume("0")) {
+    num_leading_zeros++;
+  }
+  int32_t i_nanos = 0;
+  // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
+  // "0." + s_nanos.ToString() seconds. An int32_t is used for the
+  // conversion to 'nanos', rather than a double, so that there is no
+  // loss of precision.
+  if (!s_nanos.empty() && !safe_strto32(s_nanos, &i_nanos)) {
+    return util::InvalidArgumentError(parse_failure_message);
+  }
+  if (i_nanos > kNanosPerSecond || i_nanos < 0) {
+    return util::InvalidArgumentError(exceeded_limit_message);
+  }
+  // s_nanos should only have digits. No whitespace.
+  if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
+    return util::InvalidArgumentError(parse_failure_message);
+  }
+
+  if (i_nanos > 0) {
+    // 'scale' is the number of digits to the right of the decimal
+    // point in "0." + s_nanos.ToString()
+    int32_t scale = num_leading_zeros + s_nanos.size();
+    // 'conversion' converts i_nanos into nanoseconds.
+    // conversion = kNanosPerSecond / static_cast<int32_t>(std::pow(10, scale))
+    // For efficiency, we precompute the conversion factor.
+    int32_t conversion = 0;
+    switch (scale) {
+      case 1:
+        conversion = 100000000;
+        break;
+      case 2:
+        conversion = 10000000;
+        break;
+      case 3:
+        conversion = 1000000;
+        break;
+      case 4:
+        conversion = 100000;
+        break;
+      case 5:
+        conversion = 10000;
+        break;
+      case 6:
+        conversion = 1000;
+        break;
+      case 7:
+        conversion = 100;
+        break;
+      case 8:
+        conversion = 10;
+        break;
+      case 9:
+        conversion = 1;
+        break;
+      default:
+        return util::InvalidArgumentError(exceeded_limit_message);
+    }
+    *nanos = i_nanos * conversion;
+  }
+
+  return Status();
+}
+
+}  // namespace
+
+ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
+    : parent_(parent),
+      ow_(),
+      invalid_(false),
+      data_(),
+      output_(&data_),
+      depth_(0),
+      is_well_known_type_(false),
+      well_known_type_render_(nullptr) {}
+
+ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}
+
+void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
+  ++depth_;
+  // If an object writer is absent, that means we have not called StartAny()
+  // before reaching here, which happens when we have data before the "@type"
+  // field.
+  if (ow_ == nullptr) {
+    // Save data before the "@type" field for later replay.
+    uninterpreted_events_.push_back(Event(Event::START_OBJECT, name));
+  } else if (is_well_known_type_ && depth_ == 1) {
+    // For well-known types, the only other field besides "@type" should be a
+    // "value" field.
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    ow_->StartObject("");
+  } else {
+    // Forward the call to the child writer if:
+    //   1. the type is not a well-known type.
+    //   2. or, we are in a nested Any, Struct, or Value object.
+    ow_->StartObject(name);
+  }
+}
+
+bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
+  --depth_;
+  if (ow_ == nullptr) {
+    if (depth_ >= 0) {
+      // Save data before the "@type" field for later replay.
+      uninterpreted_events_.push_back(Event(Event::END_OBJECT));
+    }
+  } else if (depth_ >= 0 || !is_well_known_type_) {
+    // As long as depth_ >= 0, we know we haven't reached the end of Any.
+    // Propagate these EndObject() calls to the contained ow_. For regular
+    // message types, we propagate the end of Any as well.
+    ow_->EndObject();
+  }
+  // A negative depth_ implies that we have reached the end of Any
+  // object. Now we write out its contents.
+  if (depth_ < 0) {
+    WriteAny();
+    return false;
+  }
+  return true;
+}
+
+void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
+  ++depth_;
+  if (ow_ == nullptr) {
+    // Save data before the "@type" field for later replay.
+    uninterpreted_events_.push_back(Event(Event::START_LIST, name));
+  } else if (is_well_known_type_ && depth_ == 1) {
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    ow_->StartList("");
+  } else {
+    ow_->StartList(name);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::EndList() {
+  --depth_;
+  if (depth_ < 0) {
+    GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
+    depth_ = 0;
+  }
+  if (ow_ == nullptr) {
+    // Save data before the "@type" field for later replay.
+    uninterpreted_events_.push_back(Event(Event::END_LIST));
+  } else {
+    ow_->EndList();
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& value) {
+  // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type"
+  // should go to the contained ow_ as they indicate nested Anys.
+  if (depth_ == 0 && ow_ == nullptr && name == "@type") {
+    StartAny(value);
+  } else if (ow_ == nullptr) {
+    // Save data before the "@type" field.
+    uninterpreted_events_.push_back(Event(name, value));
+  } else if (depth_ == 0 && is_well_known_type_) {
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    if (well_known_type_render_ == nullptr) {
+      // Only Any and Struct don't have a special type render but both of
+      // them expect a JSON object (i.e., a StartObject() call).
+      if (value.type() != DataPiece::TYPE_NULL && !invalid_) {
+        parent_->InvalidValue("Any", "Expect a JSON object.");
+        invalid_ = true;
+      }
+    } else {
+      ow_->ProtoWriter::StartObject("");
+      Status status = (*well_known_type_render_)(ow_.get(), value);
+      if (!status.ok()) ow_->InvalidValue("Any", status.message());
+      ow_->ProtoWriter::EndObject();
+    }
+  } else {
+    ow_->RenderDataPiece(name, value);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
+  // Figure out the type url. This is a copy-paste from WriteString but we also
+  // need the value, so we can't just call through to that.
+  if (value.type() == DataPiece::TYPE_STRING) {
+    type_url_ = std::string(value.str());
+  } else {
+    util::StatusOr<std::string> s = value.ToString();
+    if (!s.ok()) {
+      parent_->InvalidValue("String", s.status().message());
+      invalid_ = true;
+      return;
+    }
+    type_url_ = s.value();
+  }
+  // Resolve the type url, and report an error if we failed to resolve it.
+  util::StatusOr<const google::protobuf::Type*> resolved_type =
+      parent_->typeinfo()->ResolveTypeUrl(type_url_);
+  if (!resolved_type.ok()) {
+    parent_->InvalidValue("Any", resolved_type.status().message());
+    invalid_ = true;
+    return;
+  }
+  // At this point, type is never null.
+  const google::protobuf::Type* type = resolved_type.value();
+
+  well_known_type_render_ = FindTypeRenderer(type_url_);
+  if (well_known_type_render_ != nullptr ||
+      // Explicitly list Any and Struct here because they don't have a
+      // custom renderer.
+      type->name() == kAnyType || type->name() == kStructType) {
+    is_well_known_type_ = true;
+  }
+
+  // Create our object writer and initialize it with the first StartObject
+  // call.
+  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
+                                        parent_->listener(),
+                                        parent_->options_));
+
+  // Don't call StartObject() for well-known types yet. Depending on the
+  // type of actual data, we may not need to call StartObject(). For
+  // example:
+  // {
+  //   "@type": "type.googleapis.com/google.protobuf.Value",
+  //   "value": [1, 2, 3],
+  // }
+  // With the above JSON representation, we will only call StartList() on the
+  // contained ow_.
+  if (!is_well_known_type_) {
+    ow_->StartObject("");
+  }
+
+  // Now we know the proto type and can interpret all data fields we gathered
+  // before the "@type" field.
+  for (size_t i = 0; i < uninterpreted_events_.size(); ++i) {
+    uninterpreted_events_[i].Replay(this);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
+  if (ow_ == nullptr) {
+    if (uninterpreted_events_.empty()) {
+      // We never got any content, so just return immediately, which is
+      // equivalent to writing an empty Any.
+      return;
+    } else {
+      // There are uninterpreted data, but we never got a "@type" field.
+      if (!invalid_) {
+        parent_->InvalidValue("Any",
+                              StrCat("Missing @type for any field in ",
+                                           parent_->master_type_.name()));
+        invalid_ = true;
+      }
+      return;
+    }
+  }
+  // Render the type_url and value fields directly to the stream.
+  // type_url has tag 1 and value has tag 2.
+  WireFormatLite::WriteString(1, type_url_, parent_->stream());
+  if (!data_.empty()) {
+    WireFormatLite::WriteBytes(2, data_, parent_->stream());
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::Event::Replay(
+    AnyWriter* writer) const {
+  switch (type_) {
+    case START_OBJECT:
+      writer->StartObject(name_);
+      break;
+    case END_OBJECT:
+      writer->EndObject();
+      break;
+    case START_LIST:
+      writer->StartList(name_);
+      break;
+    case END_LIST:
+      writer->EndList();
+      break;
+    case RENDER_DATA_PIECE:
+      writer->RenderDataPiece(name_, value_);
+      break;
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() {
+  // DataPiece only contains a string reference. To make sure the referenced
+  // string value stays valid, we make a copy of the string value and update
+  // DataPiece to reference our own copy.
+  if (value_.type() == DataPiece::TYPE_STRING) {
+    StrAppend(&value_storage_, value_.str());
+    value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding());
+  } else if (value_.type() == DataPiece::TYPE_BYTES) {
+    value_storage_ = value_.ToBytes().value();
+    value_ =
+        DataPiece(value_storage_, true, value_.use_strict_base64_decoding());
+  }
+}
+
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
+    : BaseElement(nullptr),
+      ow_(enclosing),
+      any_(),
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type_ == ANY) {
+    any_.reset(new AnyWriter(ow_));
+  }
+  if (item_type == MAP) {
+    map_keys_.reset(new std::unordered_set<std::string>);
+  }
+}
+
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
+    : BaseElement(parent),
+      ow_(this->parent()->ow_),
+      any_(),
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type == ANY) {
+    any_.reset(new AnyWriter(ow_));
+  }
+  if (item_type == MAP) {
+    map_keys_.reset(new std::unordered_set<std::string>);
+  }
+}
+
+bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
+    StringPiece map_key) {
+  return InsertIfNotPresent(map_keys_.get(), std::string(map_key));
+}
+
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
+    StringPiece name) {
+  if (invalid_depth() > 0) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Starting the root message. Create the root Item and return.
+  // ANY message type does not need special handling, just set the ItemType
+  // to ANY.
+  if (current_ == nullptr) {
+    ProtoWriter::StartObject(name);
+    current_.reset(new Item(
+        this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
+        false, false));
+
+    // If master type is a special type that needs extra values to be written to
+    // stream, we write those values.
+    if (master_type_.name() == kStructType) {
+      // Struct has a map<string, Value> field called "fields".
+      // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto
+      // "fields": [
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructValueType) {
+      // We got a StartObject call with google.protobuf.Value field. The only
+      // object within that type is a struct type. So start a struct.
+      //
+      // The struct field in Value type is named "struct_value"
+      // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto
+      // Also start the map field "fields" within the struct.
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      InvalidValue(kStructListValueType,
+                   "Cannot start root message with ListValue.");
+    }
+
+    return this;
+  }
+
+  // Send all ANY events to AnyWriter.
+  if (current_->IsAny()) {
+    current_->any()->StartObject(name);
+    return this;
+  }
+
+  // If we are within a map, we render name as keys and send StartObject to the
+  // value field.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Map is a repeated field of message type with a "key" and a "value" field.
+    // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
+    // message MapFieldEntry {
+    //   key_type key = 1;
+    //   value_type value = 2;
+    // }
+    //
+    // repeated MapFieldEntry map_field = N;
+    //
+    // That means, we render the following element within a list (hence no
+    // name):
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    Push("value", IsAny(*Lookup("value")) ? Item::ANY : Item::MESSAGE, true,
+         false);
+
+    // Make sure we are valid so far after starting map fields.
+    if (invalid_depth() > 0) return this;
+
+    // If top of stack is g.p.Struct type, start the struct the map field within
+    // it.
+    if (element() != nullptr && IsStruct(*element()->parent_field())) {
+      // Render "fields": [
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    // If top of stack is g.p.Value type, start the Struct within it.
+    if (element() != nullptr && IsStructValue(*element()->parent_field())) {
+      // Render
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
+    }
+    return this;
+  }
+
+  const google::protobuf::Field* field = BeginNamed(name, false);
+
+  if (field == nullptr) return this;
+
+  // Legacy JSON map is a list of key value pairs. Starts a map entry object.
+  if (options_.use_legacy_json_map_format && name.empty()) {
+    Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
+    return this;
+  }
+
+  if (IsMap(*field)) {
+    // Begin a map. A map is triggered by a StartObject() call if the current
+    // field has a map type.
+    // A map type is always repeated, hence set is_list to true.
+    // Render
+    // "<name>": [
+    Push(name, Item::MAP, false, true);
+    return this;
+  }
+
+  if (options_.disable_implicit_message_list) {
+    // If the incoming object is repeated, the top-level object on stack should
+    // be list. Report an error otherwise.
+    if (IsRepeated(*field) && !current_->is_list()) {
+      IncrementInvalidDepth();
+
+      if (!options_.suppress_implicit_message_list_error) {
+        InvalidValue(
+            field->name(),
+            "Starting an object in a repeated field but the parent object "
+            "is not a list");
+      }
+      return this;
+    }
+  }
+
+  if (IsStruct(*field)) {
+    // Start a struct object.
+    // Render
+    // "<name>": {
+    //   "fields": {
+    Push(name, Item::MESSAGE, false, false);
+    Push("fields", Item::MAP, true, true);
+    return this;
+  }
+
+  if (IsStructValue(*field)) {
+    // We got a StartObject call with google.protobuf.Value field.  The only
+    // object within that type is a struct type. So start a struct.
+    // Render
+    // "<name>": {
+    //   "struct_value": {
+    //     "fields": {
+    Push(name, Item::MESSAGE, false, false);
+    Push("struct_value", Item::MESSAGE, true, false);
+    Push("fields", Item::MAP, true, true);
+    return this;
+  }
+
+  if (field->kind() != google::protobuf::Field::TYPE_GROUP &&
+      field->kind() != google::protobuf::Field::TYPE_MESSAGE) {
+    IncrementInvalidDepth();
+    if (!options_.suppress_object_to_scalar_error) {
+      InvalidValue(field->name(), "Starting an object on a scalar field");
+    }
+
+    return this;
+  }
+
+  // A regular message type. Pass it directly to ProtoWriter.
+  // Render
+  // "<name>": {
+  Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
+  return this;
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
+  if (invalid_depth() > 0) {
+    DecrementInvalidDepth();
+    return this;
+  }
+
+  if (current_ == nullptr) return this;
+
+  if (current_->IsAny()) {
+    if (current_->any()->EndObject()) return this;
+  }
+
+  Pop();
+
+  return this;
+}
+
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(
+    StringPiece name) {
+  if (invalid_depth() > 0) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Since we cannot have a top-level repeated item in protobuf, the only way
+  // this is valid is if we start a special type google.protobuf.ListValue or
+  // google.protobuf.Value.
+  if (current_ == nullptr) {
+    if (!name.empty()) {
+      InvalidName(name, "Root element should not be named.");
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // If master type is a special type that needs extra values to be written to
+    // stream, we write those values.
+    if (master_type_.name() == kStructValueType) {
+      // We got a StartList with google.protobuf.Value master type. This means
+      // we have to start the "list_value" within google.protobuf.Value.
+      //
+      // See
+      // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto
+      //
+      // Render
+      // "<name>": {
+      //   "list_value": {
+      //     "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("list_value", Item::MESSAGE, true, false);
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      // We got a StartList with google.protobuf.ListValue master type. This
+      // means we have to start the "values" within google.protobuf.ListValue.
+      //
+      // Render
+      // "<name>": {
+      //   "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    // Send the event to ProtoWriter so proper errors can be reported.
+    //
+    // Render a regular list:
+    // "<name>": [
+    ProtoWriter::StartList(name);
+    current_.reset(new Item(this, Item::MESSAGE, false, true));
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->StartList(name);
+    return this;
+  }
+
+  // If the top of stack is a map, we are starting a list value within a map.
+  // Since map does not allow repeated values, this can only happen when the map
+  // value is of a special type that renders a list in JSON.  These can be one
+  // of 3 cases:
+  // i. We are rendering a list value within google.protobuf.Struct
+  // ii. We are rendering a list value within google.protobuf.Value
+  // iii. We are rendering a list value with type google.protobuf.ListValue.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Start the repeated map entry object.
+    // Render
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    Push("value", Item::MESSAGE, true, false);
+
+    // Make sure we are valid after pushing all above items.
+    if (invalid_depth() > 0) return this;
+
+    // case i and ii above. Start "list_value" field within g.p.Value
+    if (element() != nullptr && element()->parent_field() != nullptr) {
+      // Render
+      // "list_value": {
+      //   "values": [  // Start this list
+      if (IsStructValue(*element()->parent_field())) {
+        Push("list_value", Item::MESSAGE, true, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+
+      // Render
+      // "values": [
+      if (IsStructListValue(*element()->parent_field())) {
+        // case iii above. Bind directly to g.p.ListValue
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+    }
+
+    // Report an error.
+    InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
+                                     "') within a map."));
+    return this;
+  }
+
+  // When name is empty and stack is not empty, we are rendering an item within
+  // a list.
+  if (name.empty()) {
+    if (element() != nullptr && element()->parent_field() != nullptr) {
+      if (IsStructValue(*element()->parent_field())) {
+        // Since it is g.p.Value, we bind directly to the list_value.
+        // Render
+        // {  // g.p.Value item within the list
+        //   "list_value": {
+        //     "values": [
+        Push("", Item::MESSAGE, false, false);
+        Push("list_value", Item::MESSAGE, true, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+
+      if (IsStructListValue(*element()->parent_field())) {
+        // Since it is g.p.ListValue, we bind to it directly.
+        // Render
+        // {  // g.p.ListValue item within the list
+        //   "values": [
+        Push("", Item::MESSAGE, false, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+    }
+
+    // Pass the event to underlying ProtoWriter.
+    Push(name, Item::MESSAGE, false, true);
+    return this;
+  }
+
+  // name is not empty
+  const google::protobuf::Field* field = Lookup(name);
+
+  if (field == nullptr) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  if (IsStructValue(*field)) {
+    // If g.p.Value is repeated, start that list. Otherwise, start the
+    // "list_value" within it.
+    if (IsRepeated(*field)) {
+      // Render it just like a regular repeated field.
+      // "<name>": [
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+
+    // Start the "list_value" field.
+    // Render
+    // "<name>": {
+    //   "list_value": {
+    //     "values": [
+    Push(name, Item::MESSAGE, false, false);
+    Push("list_value", Item::MESSAGE, true, false);
+    Push("values", Item::MESSAGE, true, true);
+    return this;
+  }
+
+  if (IsStructListValue(*field)) {
+    // If g.p.ListValue is repeated, start that list. Otherwise, start the
+    // "values" within it.
+    if (IsRepeated(*field)) {
+      // Render it just like a regular repeated field.
+      // "<name>": [
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+
+    // Start the "values" field within g.p.ListValue.
+    // Render
+    // "<name>": {
+    //   "values": [
+    Push(name, Item::MESSAGE, false, false);
+    Push("values", Item::MESSAGE, true, true);
+    return this;
+  }
+
+  // If we are here, the field should be repeated. Report an error otherwise.
+  if (!IsRepeated(*field)) {
+    IncrementInvalidDepth();
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return this;
+  }
+
+  if (IsMap(*field)) {
+    if (options_.use_legacy_json_map_format) {
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+    InvalidValue("Map", StrCat("Cannot bind a list to map for field '",
+                                     name, "'."));
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Pass the event to ProtoWriter.
+  // Render
+  // "<name>": [
+  Push(name, Item::MESSAGE, false, true);
+  return this;
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
+  if (invalid_depth() > 0) {
+    DecrementInvalidDepth();
+    return this;
+  }
+
+  if (current_ == nullptr) return this;
+
+  if (current_->IsAny()) {
+    current_->any()->EndList();
+    return this;
+  }
+
+  Pop();
+  return this;
+}
+
+Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
+                                                  const DataPiece& data) {
+  std::string struct_field_name;
+  switch (data.type()) {
+    case DataPiece::TYPE_INT32: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<int32_t> int_value = data.ToInt32();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_UINT32: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<uint32_t> int_value = data.ToUint32();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_INT64: {
+      // If the option to treat integers as strings is set, then render them as
+      // strings. Otherwise, fallback to rendering them as double.
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<int64_t> int_value = data.ToInt64();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value", DataPiece(StrCat(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_UINT64: {
+      // If the option to treat integers as strings is set, then render them as
+      // strings. Otherwise, fallback to rendering them as double.
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<uint64_t> int_value = data.ToUint64();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value", DataPiece(StrCat(int_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_FLOAT: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<float> float_value = data.ToFloat();
+        if (float_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(float_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_DOUBLE: {
+      if (ow->options_.struct_integers_as_strings) {
+        util::StatusOr<double> double_value = data.ToDouble();
+        if (double_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleDtoa(double_value.value()), true));
+          return Status();
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_STRING: {
+      struct_field_name = "string_value";
+      break;
+    }
+    case DataPiece::TYPE_BOOL: {
+      struct_field_name = "bool_value";
+      break;
+    }
+    case DataPiece::TYPE_NULL: {
+      struct_field_name = "null_value";
+      break;
+    }
+    default: {
+      return util::InvalidArgumentError(
+          "Invalid struct data type. Only number, string, boolean or  null "
+          "values are supported.");
+    }
+  }
+  ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
+  return Status();
+}
+
+Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
+                                                const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid data type for timestamp, value is ",
+                     data.ValueAsStringOrDefault("")));
+  }
+
+  StringPiece value(data.str());
+
+  int64_t seconds;
+  int32_t nanos;
+  if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
+                                               &nanos)) {
+    return util::InvalidArgumentError(StrCat("Invalid time format: ", value));
+  }
+
+
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
+  return Status();
+}
+
+static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
+                                              StringPiece path) {
+  ow->ProtoWriter::RenderDataPiece(
+      "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
+  return Status();
+}
+
+Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
+                                                const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid data type for field mask, value is ",
+                     data.ValueAsStringOrDefault("")));
+  }
+
+  // TODO(tsun): figure out how to do proto descriptor based snake case
+  // conversions as much as possible. Because ToSnakeCase sometimes returns the
+  // wrong value.
+  return DecodeCompactFieldMaskPaths(data.str(),
+                                     std::bind(&RenderOneFieldPath, ow, _1));
+}
+
+Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
+                                               const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return util::InvalidArgumentError(
+        StrCat("Invalid data type for duration, value is ",
+                     data.ValueAsStringOrDefault("")));
+  }
+
+  StringPiece value(data.str());
+
+  if (!HasSuffixString(value, "s")) {
+    return util::InvalidArgumentError(
+        "Illegal duration format; duration must end with 's'");
+  }
+  value = value.substr(0, value.size() - 1);
+  int sign = 1;
+  if (HasPrefixString(value, "-")) {
+    sign = -1;
+    value = value.substr(1);
+  }
+
+  StringPiece s_secs, s_nanos;
+  SplitSecondsAndNanos(value, &s_secs, &s_nanos);
+  uint64_t unsigned_seconds;
+  if (!safe_strtou64(s_secs, &unsigned_seconds)) {
+    return util::InvalidArgumentError(
+        "Invalid duration format, failed to parse seconds");
+  }
+
+  int32_t nanos = 0;
+  Status nanos_status = GetNanosFromStringPiece(
+      s_nanos, "Invalid duration format, failed to parse nano seconds",
+      "Duration value exceeds limits", &nanos);
+  if (!nanos_status.ok()) {
+    return nanos_status;
+  }
+  nanos = sign * nanos;
+
+  int64_t seconds = sign * unsigned_seconds;
+  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
+      nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    return util::InvalidArgumentError("Duration value exceeds limits");
+  }
+
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
+  return Status();
+}
+
+Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
+                                                  const DataPiece& data) {
+  if (data.type() == DataPiece::TYPE_NULL) return Status();
+  ow->ProtoWriter::RenderDataPiece("value", data);
+  return Status();
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& data) {
+  Status status;
+  if (invalid_depth() > 0) return this;
+
+  if (current_ == nullptr) {
+    const TypeRenderer* type_renderer =
+        FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
+    if (type_renderer == nullptr) {
+      InvalidName(name, "Root element must be a message.");
+      return this;
+    }
+    // Render the special type.
+    // "<name>": {
+    //   ... Render special type ...
+    // }
+    ProtoWriter::StartObject(name);
+    status = (*type_renderer)(this, data);
+    if (!status.ok()) {
+      InvalidValue(master_type_.name(),
+                   StrCat("Field '", name, "', ", status.message()));
+    }
+    ProtoWriter::EndObject();
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->RenderDataPiece(name, data);
+    return this;
+  }
+
+  const google::protobuf::Field* field = nullptr;
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) return this;
+
+    field = Lookup("value");
+    if (field == nullptr) {
+      GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
+      return this;
+    }
+
+    if (options_.ignore_null_value_map_entry) {
+      // If we are rendering explicit null values and the backend proto field is
+      // not of the google.protobuf.NullType type, interpret null as absence.
+      if (data.type() == DataPiece::TYPE_NULL &&
+          field->type_url() != kStructNullValueTypeUrl) {
+        return this;
+      }
+    }
+
+    // Render an item in repeated map list.
+    // { "key": "<name>", "value":
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+
+    const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+    if (type_renderer != nullptr) {
+      // Map's value type is a special type. Render it like a message:
+      // "value": {
+      //   ... Render special type ...
+      // }
+      Push("value", Item::MESSAGE, true, false);
+      status = (*type_renderer)(this, data);
+      if (!status.ok()) {
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.message()));
+      }
+      Pop();
+      return this;
+    }
+
+    // If we are rendering explicit null values and the backend proto field is
+    // not of the google.protobuf.NullType type, we do nothing.
+    if (data.type() == DataPiece::TYPE_NULL &&
+        field->type_url() != kStructNullValueTypeUrl) {
+      Pop();
+      return this;
+    }
+
+    // Render the map value as a primitive type.
+    ProtoWriter::RenderDataPiece("value", data);
+    Pop();
+    return this;
+  }
+
+  field = Lookup(name);
+  if (field == nullptr) return this;
+
+  // Check if the field is of special type. Render it accordingly if so.
+  const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+  if (type_renderer != nullptr) {
+    // Pass through null value only for google.protobuf.Value. For other
+    // types we ignore null value just like for regular field types.
+    if (data.type() != DataPiece::TYPE_NULL ||
+        field->type_url() == kStructValueTypeUrl) {
+      Push(name, Item::MESSAGE, false, false);
+      status = (*type_renderer)(this, data);
+      if (!status.ok()) {
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.message()));
+      }
+      Pop();
+    }
+    return this;
+  }
+
+  // If we are rendering explicit null values and the backend proto field is
+  // not of the google.protobuf.NullType type, we do nothing.
+  if (data.type() == DataPiece::TYPE_NULL &&
+      field->type_url() != kStructNullValueTypeUrl) {
+    return this;
+  }
+
+  if (IsRepeated(*field) && !current_->is_list()) {
+    if (options_.disable_implicit_scalar_list) {
+      if (!options_.suppress_implicit_scalar_list_error) {
+        InvalidValue(
+            field->name(),
+            "Starting an primitive in a repeated field but the parent field "
+            "is not a list");
+      }
+
+      return this;
+    }
+  }
+
+  ProtoWriter::RenderDataPiece(name, data);
+  return this;
+}
+
+// Map of functions that are responsible for rendering well known type
+// represented by the key.
+std::unordered_map<std::string, ProtoStreamObjectWriter::TypeRenderer>*
+    ProtoStreamObjectWriter::renderers_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag writer_renderers_init_;
+
+void ProtoStreamObjectWriter::InitRendererMap() {
+  renderers_ = new std::unordered_map<std::string,
+                                      ProtoStreamObjectWriter::TypeRenderer>();
+  (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] =
+      &ProtoStreamObjectWriter::RenderTimestamp;
+  (*renderers_)["type.googleapis.com/google.protobuf.Duration"] =
+      &ProtoStreamObjectWriter::RenderDuration;
+  (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] =
+      &ProtoStreamObjectWriter::RenderFieldMask;
+  (*renderers_)["type.googleapis.com/google.protobuf.Double"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Float"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int64"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int32"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Bool"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.String"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Value"] =
+      &ProtoStreamObjectWriter::RenderStructValue;
+  ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
+}
+
+void ProtoStreamObjectWriter::DeleteRendererMap() {
+  delete ProtoStreamObjectWriter::renderers_;
+  renderers_ = nullptr;
+}
+
+ProtoStreamObjectWriter::TypeRenderer*
+ProtoStreamObjectWriter::FindTypeRenderer(const std::string& type_url) {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(writer_renderers_init_,
+                                             InitRendererMap);
+  return FindOrNull(*renderers_, type_url);
+}
+
+bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
+  if (current_ == nullptr) return true;
+
+  if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
+    listener()->InvalidName(
+        location(), unnormalized_name,
+        StrCat("Repeated map key: '", unnormalized_name,
+                     "' is already set."));
+    return false;
+  }
+
+  return true;
+}
+
+void ProtoStreamObjectWriter::Push(
+    StringPiece name, Item::ItemType item_type, bool is_placeholder,
+    bool is_list) {
+  is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
+
+  // invalid_depth == 0 means it is a successful StartObject or StartList.
+  if (invalid_depth() == 0)
+    current_.reset(
+        new Item(current_.release(), item_type, is_placeholder, is_list));
+}
+
+void ProtoStreamObjectWriter::Pop() {
+  // Pop all placeholder items sending StartObject or StartList events to
+  // ProtoWriter according to is_list value.
+  while (current_ != nullptr && current_->is_placeholder()) {
+    PopOneElement();
+  }
+  if (current_ != nullptr) {
+    PopOneElement();
+  }
+}
+
+void ProtoStreamObjectWriter::PopOneElement() {
+  current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
+  current_.reset(current_->pop<Item>());
+}
+
+bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
+  if (field.type_url().empty() ||
+      field.kind() != google::protobuf::Field::TYPE_MESSAGE ||
+      field.cardinality() != google::protobuf::Field::CARDINALITY_REPEATED) {
+    return false;
+  }
+  const google::protobuf::Type* field_type =
+      typeinfo()->GetTypeByTypeUrl(field.type_url());
+
+  return converter::IsMap(field, *field_type);
+}
+
+bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kAnyType;
+}
+
+bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructType;
+}
+
+bool ProtoStreamObjectWriter::IsStructValue(
+    const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
+}
+
+bool ProtoStreamObjectWriter::IsStructListValue(
+    const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/type_info.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/type_info.cpp
new file mode 100644
index 0000000..b6cf536
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/type_info.cpp
@@ -0,0 +1,182 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/type_info.h>
+
+#include <map>
+#include <set>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+// A TypeInfo that looks up information provided by a TypeResolver.
+class TypeInfoForTypeResolver : public TypeInfo {
+ public:
+  explicit TypeInfoForTypeResolver(TypeResolver* type_resolver)
+      : type_resolver_(type_resolver) {}
+
+  ~TypeInfoForTypeResolver() override {
+    DeleteCachedTypes(&cached_types_);
+    DeleteCachedTypes(&cached_enums_);
+  }
+
+  util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
+      StringPiece type_url) const override {
+    std::map<StringPiece, StatusOrType>::iterator it =
+        cached_types_.find(type_url);
+    if (it != cached_types_.end()) {
+      return it->second;
+    }
+    // Stores the string value so it can be referenced using StringPiece in the
+    // cached_types_ map.
+    const std::string& string_type_url =
+        *string_storage_.insert(std::string(type_url)).first;
+    std::unique_ptr<google::protobuf::Type> type(new google::protobuf::Type());
+    util::Status status =
+        type_resolver_->ResolveMessageType(string_type_url, type.get());
+    StatusOrType result =
+        status.ok() ? StatusOrType(type.release()) : StatusOrType(status);
+    cached_types_[string_type_url] = result;
+    return result;
+  }
+
+  const google::protobuf::Type* GetTypeByTypeUrl(
+      StringPiece type_url) const override {
+    StatusOrType result = ResolveTypeUrl(type_url);
+    return result.ok() ? result.value() : NULL;
+  }
+
+  const google::protobuf::Enum* GetEnumByTypeUrl(
+      StringPiece type_url) const override {
+    std::map<StringPiece, StatusOrEnum>::iterator it =
+        cached_enums_.find(type_url);
+    if (it != cached_enums_.end()) {
+      return it->second.ok() ? it->second.value() : NULL;
+    }
+    // Stores the string value so it can be referenced using StringPiece in the
+    // cached_enums_ map.
+    const std::string& string_type_url =
+        *string_storage_.insert(std::string(type_url)).first;
+    std::unique_ptr<google::protobuf::Enum> enum_type(
+        new google::protobuf::Enum());
+    util::Status status =
+        type_resolver_->ResolveEnumType(string_type_url, enum_type.get());
+    StatusOrEnum result =
+        status.ok() ? StatusOrEnum(enum_type.release()) : StatusOrEnum(status);
+    cached_enums_[string_type_url] = result;
+    return result.ok() ? result.value() : NULL;
+  }
+
+  const google::protobuf::Field* FindField(
+      const google::protobuf::Type* type,
+      StringPiece camel_case_name) const override {
+    std::map<const google::protobuf::Type*, CamelCaseNameTable>::const_iterator
+        it = indexed_types_.find(type);
+    const CamelCaseNameTable& camel_case_name_table =
+        (it == indexed_types_.end())
+            ? PopulateNameLookupTable(type, &indexed_types_[type])
+            : it->second;
+    StringPiece name = FindWithDefault(
+        camel_case_name_table, camel_case_name, StringPiece());
+    if (name.empty()) {
+      // Didn't find a mapping. Use whatever provided.
+      name = camel_case_name;
+    }
+    return FindFieldInTypeOrNull(type, name);
+  }
+
+ private:
+  typedef util::StatusOr<const google::protobuf::Type*> StatusOrType;
+  typedef util::StatusOr<const google::protobuf::Enum*> StatusOrEnum;
+  typedef std::map<StringPiece, StringPiece> CamelCaseNameTable;
+
+  template <typename T>
+  static void DeleteCachedTypes(std::map<StringPiece, T>* cached_types) {
+    for (typename std::map<StringPiece, T>::iterator it =
+             cached_types->begin();
+         it != cached_types->end(); ++it) {
+      if (it->second.ok()) {
+        delete it->second.value();
+      }
+    }
+  }
+
+  const CamelCaseNameTable& PopulateNameLookupTable(
+      const google::protobuf::Type* type,
+      CamelCaseNameTable* camel_case_name_table) const {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      StringPiece name = field.name();
+      StringPiece camel_case_name = field.json_name();
+      const StringPiece* existing = InsertOrReturnExisting(
+          camel_case_name_table, camel_case_name, name);
+      if (existing && *existing != name) {
+        GOOGLE_LOG(WARNING) << "Field '" << name << "' and '" << *existing
+                     << "' map to the same camel case name '" << camel_case_name
+                     << "'.";
+      }
+    }
+    return *camel_case_name_table;
+  }
+
+  TypeResolver* type_resolver_;
+
+  // Stores string values that will be referenced by StringPieces in
+  // cached_types_, cached_enums_.
+  mutable std::set<std::string> string_storage_;
+
+  mutable std::map<StringPiece, StatusOrType> cached_types_;
+  mutable std::map<StringPiece, StatusOrEnum> cached_enums_;
+
+  mutable std::map<const google::protobuf::Type*, CamelCaseNameTable>
+      indexed_types_;
+};
+}  // namespace
+
+TypeInfo* TypeInfo::NewTypeInfo(TypeResolver* type_resolver) {
+  return new TypeInfoForTypeResolver(type_resolver);
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/utility.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/utility.cpp
new file mode 100644
index 0000000..3c4ac08
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/internal/utility.cpp
@@ -0,0 +1,416 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/internal/utility.h>
+
+#include <algorithm>
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/stubs/map_util.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+bool GetBoolOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, bool default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return default_value;
+  }
+  return GetBoolFromAny(opt->value());
+}
+
+int64_t GetInt64OptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, int64_t default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return default_value;
+  }
+  return GetInt64FromAny(opt->value());
+}
+
+double GetDoubleOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, double default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return default_value;
+  }
+  return GetDoubleFromAny(opt->value());
+}
+
+std::string GetStringOptionOrDefault(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name, StringPiece default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == nullptr) {
+    return std::string(default_value);
+  }
+  return GetStringFromAny(opt->value());
+}
+
+template <typename T>
+void ParseFromAny(const std::string& data, T* result) {
+  result->ParseFromString(data);
+}
+
+// Returns a boolean value contained in Any type.
+// TODO(skarvaje): Add type checking & error messages here.
+bool GetBoolFromAny(const google::protobuf::Any& any) {
+  google::protobuf::BoolValue b;
+  ParseFromAny(any.value(), &b);
+  return b.value();
+}
+
+int64_t GetInt64FromAny(const google::protobuf::Any& any) {
+  google::protobuf::Int64Value i;
+  ParseFromAny(any.value(), &i);
+  return i.value();
+}
+
+double GetDoubleFromAny(const google::protobuf::Any& any) {
+  google::protobuf::DoubleValue i;
+  ParseFromAny(any.value(), &i);
+  return i.value();
+}
+
+std::string GetStringFromAny(const google::protobuf::Any& any) {
+  google::protobuf::StringValue s;
+  ParseFromAny(any.value(), &s);
+  return s.value();
+}
+
+const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
+  if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') {
+    return type_url.substr(kTypeUrlSize + 1);
+  } else {
+    size_t idx = type_url.rfind('/');
+    if (idx != type_url.npos) {
+      type_url.remove_prefix(idx + 1);
+    }
+    return type_url;
+  }
+}
+
+const std::string GetFullTypeWithUrl(StringPiece simple_type) {
+  return StrCat(kTypeServiceBaseUrl, "/", simple_type);
+}
+
+const google::protobuf::Option* FindOptionOrNull(
+    const RepeatedPtrField<google::protobuf::Option>& options,
+    StringPiece option_name) {
+  for (int i = 0; i < options.size(); ++i) {
+    const google::protobuf::Option& opt = options.Get(i);
+    if (opt.name() == option_name) {
+      return &opt;
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::Field* FindFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece field_name) {
+  if (type != nullptr) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.name() == field_name) {
+        return &field;
+      }
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name) {
+  if (type != nullptr) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.json_name() == json_name) {
+        return &field;
+      }
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::Field* FindFieldInTypeByNumberOrNull(
+    const google::protobuf::Type* type, int32_t number) {
+  if (type != nullptr) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.number() == number) {
+        return &field;
+      }
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
+  if (enum_type != nullptr) {
+    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
+      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
+      if (enum_value.name() == enum_name) {
+        return &enum_value;
+      }
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
+    const google::protobuf::Enum* enum_type, int32_t value) {
+  if (enum_type != nullptr) {
+    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
+      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
+      if (enum_value.number() == value) {
+        return &enum_value;
+      }
+    }
+  }
+  return nullptr;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
+  if (enum_type != nullptr) {
+    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
+      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
+      std::string enum_name_without_underscore = enum_value.name();
+
+      // Remove underscore from the name.
+      enum_name_without_underscore.erase(
+          std::remove(enum_name_without_underscore.begin(),
+                      enum_name_without_underscore.end(), '_'),
+          enum_name_without_underscore.end());
+      // Make the name uppercase.
+      for (std::string::iterator it = enum_name_without_underscore.begin();
+           it != enum_name_without_underscore.end(); ++it) {
+        *it = ascii_toupper(*it);
+      }
+
+      if (enum_name_without_underscore == enum_name) {
+        return &enum_value;
+      }
+    }
+  }
+  return nullptr;
+}
+
+std::string EnumValueNameToLowerCamelCase(StringPiece input) {
+  std::string input_string(input);
+  std::transform(input_string.begin(), input_string.end(), input_string.begin(),
+                 ::tolower);
+  return ToCamelCase(input_string);
+}
+
+std::string ToCamelCase(StringPiece input) {
+  bool capitalize_next = false;
+  bool was_cap = true;
+  bool is_cap = false;
+  bool first_word = true;
+  std::string result;
+  result.reserve(input.size());
+
+  for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) {
+    is_cap = ascii_isupper(input[i]);
+    if (input[i] == '_') {
+      capitalize_next = true;
+      if (!result.empty()) first_word = false;
+      continue;
+    } else if (first_word) {
+      // Consider when the current character B is capitalized,
+      // first word ends when:
+      // 1) following a lowercase:   "...aB..."
+      // 2) followed by a lowercase: "...ABc..."
+      if (!result.empty() && is_cap &&
+          (!was_cap ||
+           (i + 1 < input.size() && ascii_islower(input[i + 1])))) {
+        first_word = false;
+        result.push_back(input[i]);
+      } else {
+        result.push_back(ascii_tolower(input[i]));
+        continue;
+      }
+    } else if (capitalize_next) {
+      capitalize_next = false;
+      if (ascii_islower(input[i])) {
+        result.push_back(ascii_toupper(input[i]));
+        continue;
+      } else {
+        result.push_back(input[i]);
+        continue;
+      }
+    } else {
+      result.push_back(ascii_tolower(input[i]));
+    }
+  }
+  return result;
+}
+
+std::string ToSnakeCase(StringPiece input) {
+  bool was_not_underscore = false;  // Initialize to false for case 1 (below)
+  bool was_not_cap = false;
+  std::string result;
+  result.reserve(input.size() << 1);
+
+  for (size_t i = 0; i < input.size(); ++i) {
+    if (ascii_isupper(input[i])) {
+      // Consider when the current character B is capitalized:
+      // 1) At beginning of input:   "B..." => "b..."
+      //    (e.g. "Biscuit" => "biscuit")
+      // 2) Following a lowercase:   "...aB..." => "...a_b..."
+      //    (e.g. "gBike" => "g_bike")
+      // 3) At the end of input:     "...AB" => "...ab"
+      //    (e.g. "GoogleLAB" => "google_lab")
+      // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
+      //    (e.g. "GBike" => "g_bike")
+      if (was_not_underscore &&                     //            case 1 out
+          (was_not_cap ||                           // case 2 in, case 3 out
+           (i + 1 < input.size() &&                 //            case 3 out
+            ascii_islower(input[i + 1])))) {  // case 4 in
+        // We add an underscore for case 2 and case 4.
+        result.push_back('_');
+      }
+      result.push_back(ascii_tolower(input[i]));
+      was_not_underscore = true;
+      was_not_cap = false;
+    } else {
+      result.push_back(input[i]);
+      was_not_underscore = input[i] != '_';
+      was_not_cap = true;
+    }
+  }
+  return result;
+}
+
+std::set<std::string>* well_known_types_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag well_known_types_init_;
+const char* well_known_types_name_array_[] = {
+    "google.protobuf.Timestamp",   "google.protobuf.Duration",
+    "google.protobuf.DoubleValue", "google.protobuf.FloatValue",
+    "google.protobuf.Int64Value",  "google.protobuf.UInt64Value",
+    "google.protobuf.Int32Value",  "google.protobuf.UInt32Value",
+    "google.protobuf.BoolValue",   "google.protobuf.StringValue",
+    "google.protobuf.BytesValue",  "google.protobuf.FieldMask"};
+
+void DeleteWellKnownTypes() { delete well_known_types_; }
+
+void InitWellKnownTypes() {
+  well_known_types_ = new std::set<std::string>;
+  for (size_t i = 0; i < GOOGLE_ARRAYSIZE(well_known_types_name_array_); ++i) {
+    well_known_types_->insert(well_known_types_name_array_[i]);
+  }
+  google::protobuf::internal::OnShutdown(&DeleteWellKnownTypes);
+}
+
+bool IsWellKnownType(const std::string& type_name) {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(well_known_types_init_,
+                                             InitWellKnownTypes);
+  return ContainsKey(*well_known_types_, type_name);
+}
+
+bool IsValidBoolString(StringPiece bool_string) {
+  return bool_string == "true" || bool_string == "false" ||
+         bool_string == "1" || bool_string == "0";
+}
+
+bool IsMap(const google::protobuf::Field& field,
+           const google::protobuf::Type& type) {
+  return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED &&
+         (GetBoolOptionOrDefault(type.options(), "map_entry", false) ||
+          GetBoolOptionOrDefault(type.options(),
+                                 "google.protobuf.MessageOptions.map_entry",
+                                 false));
+}
+
+bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
+  return GetBoolOptionOrDefault(type.options(), "message_set_wire_format",
+                                false) ||
+         GetBoolOptionOrDefault(
+             type.options(),
+             "google.protobuf.MessageOptions.message_set_wire_format", false);
+}
+
+std::string DoubleAsString(double value) {
+  if (value == std::numeric_limits<double>::infinity()) return "Infinity";
+  if (value == -std::numeric_limits<double>::infinity()) return "-Infinity";
+  if (std::isnan(value)) return "NaN";
+
+  return SimpleDtoa(value);
+}
+
+std::string FloatAsString(float value) {
+  if (std::isfinite(value)) return SimpleFtoa(value);
+  return DoubleAsString(value);
+}
+
+bool SafeStrToFloat(StringPiece str, float* value) {
+  double double_value;
+  if (!safe_strtod(str, &double_value)) {
+    return false;
+  }
+
+  if (std::isinf(double_value) || std::isnan(double_value)) return false;
+
+  // Fail if the value is not representable in float.
+  if (double_value > std::numeric_limits<float>::max() ||
+      double_value < -std::numeric_limits<float>::max()) {
+    return false;
+  }
+
+  *value = static_cast<float>(double_value);
+  return true;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/json_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/json_util.cpp
new file mode 100644
index 0000000..a9b1c52
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/json_util.cpp
@@ -0,0 +1,284 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/json_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/json_objectwriter.h>
+#include <google/protobuf/util/internal/json_stream_parser.h>
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/util/type_resolver_util.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+namespace internal {
+ZeroCopyStreamByteSink::~ZeroCopyStreamByteSink() {
+  if (buffer_size_ > 0) {
+    stream_->BackUp(buffer_size_);
+  }
+}
+
+void ZeroCopyStreamByteSink::Append(const char* bytes, size_t len) {
+  while (true) {
+    if (static_cast<int>(len) <= buffer_size_) {  // NOLINT
+      memcpy(buffer_, bytes, len);
+      buffer_ = static_cast<char*>(buffer_) + len;
+      buffer_size_ -= len;
+      return;
+    }
+    if (buffer_size_ > 0) {
+      memcpy(buffer_, bytes, buffer_size_);
+      bytes += buffer_size_;
+      len -= buffer_size_;
+    }
+    if (!stream_->Next(&buffer_, &buffer_size_)) {
+      // There isn't a way for ByteSink to report errors.
+      buffer_size_ = 0;
+      return;
+    }
+  }
+}
+}  // namespace internal
+
+util::Status BinaryToJsonStream(TypeResolver* resolver,
+                                const std::string& type_url,
+                                io::ZeroCopyInputStream* binary_input,
+                                io::ZeroCopyOutputStream* json_output,
+                                const JsonPrintOptions& options) {
+  io::CodedInputStream in_stream(binary_input);
+  google::protobuf::Type type;
+  RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
+  converter::ProtoStreamObjectSource::RenderOptions render_options;
+  render_options.use_ints_for_enums = options.always_print_enums_as_ints;
+  render_options.preserve_proto_field_names =
+      options.preserve_proto_field_names;
+  converter::ProtoStreamObjectSource proto_source(&in_stream, resolver, type,
+                                                  render_options);
+  io::CodedOutputStream out_stream(json_output);
+  converter::JsonObjectWriter json_writer(options.add_whitespace ? " " : "",
+                                          &out_stream);
+  if (options.always_print_primitive_fields) {
+    converter::DefaultValueObjectWriter default_value_writer(resolver, type,
+                                                             &json_writer);
+    default_value_writer.set_preserve_proto_field_names(
+        options.preserve_proto_field_names);
+    default_value_writer.set_print_enums_as_ints(
+        options.always_print_enums_as_ints);
+    return proto_source.WriteTo(&default_value_writer);
+  } else {
+    return proto_source.WriteTo(&json_writer);
+  }
+}
+
+util::Status BinaryToJsonString(TypeResolver* resolver,
+                                const std::string& type_url,
+                                const std::string& binary_input,
+                                std::string* json_output,
+                                const JsonPrintOptions& options) {
+  io::ArrayInputStream input_stream(binary_input.data(), binary_input.size());
+  io::StringOutputStream output_stream(json_output);
+  return BinaryToJsonStream(resolver, type_url, &input_stream, &output_stream,
+                            options);
+}
+
+namespace {
+class StatusErrorListener : public converter::ErrorListener {
+ public:
+  StatusErrorListener() {}
+  ~StatusErrorListener() override {}
+
+  util::Status GetStatus() { return status_; }
+
+  void InvalidName(const converter::LocationTrackerInterface& loc,
+                   StringPiece unknown_name,
+                   StringPiece message) override {
+    std::string loc_string = GetLocString(loc);
+    if (!loc_string.empty()) {
+      loc_string.append(" ");
+    }
+    status_ = util::InvalidArgumentError(
+        StrCat(loc_string, unknown_name, ": ", message));
+  }
+
+  void InvalidValue(const converter::LocationTrackerInterface& loc,
+                    StringPiece type_name,
+                    StringPiece value) override {
+    status_ = util::InvalidArgumentError(
+        StrCat(GetLocString(loc), ": invalid value ", std::string(value),
+                     " for type ", std::string(type_name)));
+  }
+
+  void MissingField(const converter::LocationTrackerInterface& loc,
+                    StringPiece missing_name) override {
+    status_ = util::InvalidArgumentError(StrCat(
+        GetLocString(loc), ": missing field ", std::string(missing_name)));
+  }
+
+ private:
+  util::Status status_;
+
+  std::string GetLocString(const converter::LocationTrackerInterface& loc) {
+    std::string loc_string = loc.ToString();
+    StripWhitespace(&loc_string);
+    if (!loc_string.empty()) {
+      loc_string = StrCat("(", loc_string, ")");
+    }
+    return loc_string;
+  }
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StatusErrorListener);
+};
+}  // namespace
+
+util::Status JsonToBinaryStream(TypeResolver* resolver,
+                                const std::string& type_url,
+                                io::ZeroCopyInputStream* json_input,
+                                io::ZeroCopyOutputStream* binary_output,
+                                const JsonParseOptions& options) {
+  google::protobuf::Type type;
+  RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
+  internal::ZeroCopyStreamByteSink sink(binary_output);
+  StatusErrorListener listener;
+  converter::ProtoStreamObjectWriter::Options proto_writer_options;
+  proto_writer_options.ignore_unknown_fields = options.ignore_unknown_fields;
+  proto_writer_options.ignore_unknown_enum_values =
+      options.ignore_unknown_fields;
+  proto_writer_options.case_insensitive_enum_parsing =
+      options.case_insensitive_enum_parsing;
+  converter::ProtoStreamObjectWriter proto_writer(
+      resolver, type, &sink, &listener, proto_writer_options);
+
+  converter::JsonStreamParser parser(&proto_writer);
+  const void* buffer;
+  int length;
+  while (json_input->Next(&buffer, &length)) {
+    if (length == 0) continue;
+    RETURN_IF_ERROR(parser.Parse(
+        StringPiece(static_cast<const char*>(buffer), length)));
+  }
+  RETURN_IF_ERROR(parser.FinishParse());
+
+  return listener.GetStatus();
+}
+
+util::Status JsonToBinaryString(TypeResolver* resolver,
+                                const std::string& type_url,
+                                StringPiece json_input,
+                                std::string* binary_output,
+                                const JsonParseOptions& options) {
+  io::ArrayInputStream input_stream(json_input.data(), json_input.size());
+  io::StringOutputStream output_stream(binary_output);
+  return JsonToBinaryStream(resolver, type_url, &input_stream, &output_stream,
+                            options);
+}
+
+namespace {
+const char* kTypeUrlPrefix = "type.googleapis.com";
+TypeResolver* generated_type_resolver_ = nullptr;
+PROTOBUF_NAMESPACE_ID::internal::once_flag generated_type_resolver_init_;
+
+std::string GetTypeUrl(const Message& message) {
+  return std::string(kTypeUrlPrefix) + "/" +
+         message.GetDescriptor()->full_name();
+}
+
+void DeleteGeneratedTypeResolver() {  // NOLINT
+  delete generated_type_resolver_;
+}
+
+void InitGeneratedTypeResolver() {
+  generated_type_resolver_ = NewTypeResolverForDescriptorPool(
+      kTypeUrlPrefix, DescriptorPool::generated_pool());
+  ::google::protobuf::internal::OnShutdown(&DeleteGeneratedTypeResolver);
+}
+
+TypeResolver* GetGeneratedTypeResolver() {
+  PROTOBUF_NAMESPACE_ID::internal::call_once(generated_type_resolver_init_,
+                                             InitGeneratedTypeResolver);
+  return generated_type_resolver_;
+}
+}  // namespace
+
+util::Status MessageToJsonString(const Message& message, std::string* output,
+                                 const JsonOptions& options) {
+  const DescriptorPool* pool = message.GetDescriptor()->file()->pool();
+  TypeResolver* resolver =
+      pool == DescriptorPool::generated_pool()
+          ? GetGeneratedTypeResolver()
+          : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool);
+  util::Status result =
+      BinaryToJsonString(resolver, GetTypeUrl(message),
+                         message.SerializeAsString(), output, options);
+  if (pool != DescriptorPool::generated_pool()) {
+    delete resolver;
+  }
+  return result;
+}
+
+util::Status JsonStringToMessage(StringPiece input, Message* message,
+                                 const JsonParseOptions& options) {
+  const DescriptorPool* pool = message->GetDescriptor()->file()->pool();
+  TypeResolver* resolver =
+      pool == DescriptorPool::generated_pool()
+          ? GetGeneratedTypeResolver()
+          : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool);
+  std::string binary;
+  util::Status result = JsonToBinaryString(resolver, GetTypeUrl(*message),
+                                           input, &binary, options);
+  if (result.ok() && !message->ParseFromString(binary)) {
+    result = util::InvalidArgumentError(
+        "JSON transcoder produced invalid protobuf output.");
+  }
+  if (pool != DescriptorPool::generated_pool()) {
+    delete resolver;
+  }
+  return result;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/message_differencer.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/message_differencer.cpp
new file mode 100644
index 0000000..30560ed
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/message_differencer.cpp
@@ -0,0 +1,2246 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/util/message_differencer.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/util/field_comparator.h>
+
+// Always include as last one, otherwise it can break compilation
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+namespace util {
+
+namespace {
+
+std::string PrintShortTextFormat(const google::protobuf::Message& message) {
+  std::string debug_string;
+
+  google::protobuf::TextFormat::Printer printer;
+  printer.SetSingleLineMode(true);
+  printer.SetExpandAny(true);
+
+  printer.PrintToString(message, &debug_string);
+  // Single line mode currently might have an extra space at the end.
+  if (!debug_string.empty() && debug_string[debug_string.size() - 1] == ' ') {
+    debug_string.resize(debug_string.size() - 1);
+  }
+
+  return debug_string;
+}
+
+}  // namespace
+
+// A reporter to report the total number of diffs.
+// TODO(ykzhu): we can improve this to take into account the value differencers.
+class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Reporter {
+ public:
+  NumDiffsReporter() : num_diffs_(0) {}
+
+  // Returns the total number of diffs.
+  int32_t GetNumDiffs() const { return num_diffs_; }
+  void Reset() { num_diffs_ = 0; }
+
+  // Report that a field has been added into Message2.
+  void ReportAdded(
+      const google::protobuf::Message& /* message1 */,
+      const google::protobuf::Message& /* message2 */,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+      /*field_path*/) override {
+    ++num_diffs_;
+  }
+
+  // Report that a field has been deleted from Message1.
+  void ReportDeleted(
+      const google::protobuf::Message& /* message1 */,
+      const google::protobuf::Message& /* message2 */,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+      /*field_path*/) override {
+    ++num_diffs_;
+  }
+
+  // Report that the value of a field has been modified.
+  void ReportModified(
+      const google::protobuf::Message& /* message1 */,
+      const google::protobuf::Message& /* message2 */,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+      /*field_path*/) override {
+    ++num_diffs_;
+  }
+
+ private:
+  int32_t num_diffs_;
+};
+
+// When comparing a repeated field as map, MultipleFieldMapKeyComparator can
+// be used to specify multiple fields as key for key comparison.
+// Two elements of a repeated field will be regarded as having the same key
+// iff they have the same value for every specified key field.
+// Note that you can also specify only one field as key.
+class MessageDifferencer::MultipleFieldsMapKeyComparator
+    : public MessageDifferencer::MapKeyComparator {
+ public:
+  MultipleFieldsMapKeyComparator(
+      MessageDifferencer* message_differencer,
+      const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths)
+      : message_differencer_(message_differencer),
+        key_field_paths_(key_field_paths) {
+    GOOGLE_CHECK(!key_field_paths_.empty());
+    for (const auto& path : key_field_paths_) {
+      GOOGLE_CHECK(!path.empty());
+    }
+  }
+  MultipleFieldsMapKeyComparator(MessageDifferencer* message_differencer,
+                                 const FieldDescriptor* key)
+      : message_differencer_(message_differencer) {
+    std::vector<const FieldDescriptor*> key_field_path;
+    key_field_path.push_back(key);
+    key_field_paths_.push_back(key_field_path);
+  }
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
+    for (const auto& path : key_field_paths_) {
+      if (!IsMatchInternal(message1, message2, parent_fields, path, 0)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  bool IsMatchInternal(
+      const Message& message1, const Message& message2,
+      const std::vector<SpecificField>& parent_fields,
+      const std::vector<const FieldDescriptor*>& key_field_path,
+      int path_index) const {
+    const FieldDescriptor* field = key_field_path[path_index];
+    std::vector<SpecificField> current_parent_fields(parent_fields);
+    if (path_index == static_cast<int64_t>(key_field_path.size() - 1)) {
+      if (field->is_map()) {
+        return message_differencer_->CompareMapField(message1, message2, field,
+                                                     &current_parent_fields);
+      } else if (field->is_repeated()) {
+        return message_differencer_->CompareRepeatedField(
+            message1, message2, field, &current_parent_fields);
+      } else {
+        return message_differencer_->CompareFieldValueUsingParentFields(
+            message1, message2, field, -1, -1, &current_parent_fields);
+      }
+    } else {
+      const Reflection* reflection1 = message1.GetReflection();
+      const Reflection* reflection2 = message2.GetReflection();
+      bool has_field1 = reflection1->HasField(message1, field);
+      bool has_field2 = reflection2->HasField(message2, field);
+      if (!has_field1 && !has_field2) {
+        return true;
+      }
+      if (has_field1 != has_field2) {
+        return false;
+      }
+      SpecificField specific_field;
+      specific_field.field = field;
+      current_parent_fields.push_back(specific_field);
+      return IsMatchInternal(reflection1->GetMessage(message1, field),
+                             reflection2->GetMessage(message2, field),
+                             current_parent_fields, key_field_path,
+                             path_index + 1);
+    }
+  }
+  MessageDifferencer* message_differencer_;
+  std::vector<std::vector<const FieldDescriptor*> > key_field_paths_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
+};
+
+// Preserve the order when treating repeated field as SMART_LIST. The current
+// implementation is to find the longest matching sequence from the first
+// element. The optimal solution requires to use //util/diff/lcs.h, which is
+// not open sourced yet. Overwrite this method if you want to have that.
+// TODO(ykzhu): change to use LCS once it is open sourced.
+void MatchIndicesPostProcessorForSmartList(std::vector<int>* match_list1,
+                                           std::vector<int>* match_list2) {
+  int last_matched_index = -1;
+  for (size_t i = 0; i < match_list1->size(); ++i) {
+    if (match_list1->at(i) < 0) {
+      continue;
+    }
+    if (last_matched_index < 0 || match_list1->at(i) > last_matched_index) {
+      last_matched_index = match_list1->at(i);
+    } else {
+      match_list2->at(match_list1->at(i)) = -1;
+      match_list1->at(i) = -1;
+    }
+  }
+}
+
+void AddSpecificIndex(
+    google::protobuf::util::MessageDifferencer::SpecificField* specific_field,
+    const Message& message, const FieldDescriptor* field, int index) {
+  if (field->is_map()) {
+    const Reflection* reflection = message.GetReflection();
+    specific_field->map_entry1 =
+        &reflection->GetRepeatedMessage(message, field, index);
+  }
+  specific_field->index = index;
+}
+
+void AddSpecificNewIndex(
+    google::protobuf::util::MessageDifferencer::SpecificField* specific_field,
+    const Message& message, const FieldDescriptor* field, int index) {
+  if (field->is_map()) {
+    const Reflection* reflection = message.GetReflection();
+    specific_field->map_entry2 =
+        &reflection->GetRepeatedMessage(message, field, index);
+  }
+  specific_field->new_index = index;
+}
+
+MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
+    MessageDifferencer* message_differencer)
+    : message_differencer_(message_differencer) {}
+
+bool MessageDifferencer::MapEntryKeyComparator::IsMatch(
+    const Message& message1, const Message& message2,
+    const std::vector<SpecificField>& parent_fields) const {
+  // Map entry has its key in the field with tag 1.  See the comment for
+  // map_entry in MessageOptions.
+  const FieldDescriptor* key = message1.GetDescriptor()->FindFieldByNumber(1);
+  // If key is not present in message1 and we're doing partial comparison or if
+  // map key is explicitly ignored treat the field as set instead,
+  const bool treat_as_set =
+      (message_differencer_->scope() == PARTIAL &&
+       !message1.GetReflection()->HasField(message1, key)) ||
+      message_differencer_->IsIgnored(message1, message2, key, parent_fields);
+
+  std::vector<SpecificField> current_parent_fields(parent_fields);
+  if (treat_as_set) {
+    return message_differencer_->Compare(message1, message2,
+                                         &current_parent_fields);
+  }
+  return message_differencer_->CompareFieldValueUsingParentFields(
+      message1, message2, key, -1, -1, &current_parent_fields);
+}
+
+bool MessageDifferencer::Equals(const Message& message1,
+                                const Message& message2) {
+  MessageDifferencer differencer;
+
+  return differencer.Compare(message1, message2);
+}
+
+bool MessageDifferencer::Equivalent(const Message& message1,
+                                    const Message& message2) {
+  MessageDifferencer differencer;
+  differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
+
+  return differencer.Compare(message1, message2);
+}
+
+bool MessageDifferencer::ApproximatelyEquals(const Message& message1,
+                                             const Message& message2) {
+  MessageDifferencer differencer;
+  differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
+
+  return differencer.Compare(message1, message2);
+}
+
+bool MessageDifferencer::ApproximatelyEquivalent(const Message& message1,
+                                                 const Message& message2) {
+  MessageDifferencer differencer;
+  differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
+  differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
+
+  return differencer.Compare(message1, message2);
+}
+
+// ===========================================================================
+
+MessageDifferencer::MessageDifferencer()
+    : reporter_(NULL),
+      message_field_comparison_(EQUAL),
+      scope_(FULL),
+      repeated_field_comparison_(AS_LIST),
+      map_entry_key_comparator_(this),
+      report_matches_(false),
+      report_moves_(true),
+      report_ignores_(true),
+      output_string_(nullptr),
+      match_indices_for_smart_list_callback_(
+          MatchIndicesPostProcessorForSmartList) {}
+
+MessageDifferencer::~MessageDifferencer() {
+  for (MapKeyComparator* comparator : owned_key_comparators_) {
+    delete comparator;
+  }
+  for (IgnoreCriteria* criteria : ignore_criteria_) {
+    delete criteria;
+  }
+}
+
+void MessageDifferencer::set_field_comparator(FieldComparator* comparator) {
+  GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
+  field_comparator_kind_ = kFCBase;
+  field_comparator_.base = comparator;
+}
+
+#ifdef PROTOBUF_FUTURE_BREAKING_CHANGES
+void MessageDifferencer::set_field_comparator(
+    DefaultFieldComparator* comparator) {
+  GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
+  field_comparator_kind_ = kFCDefault;
+  field_comparator_.default_impl = comparator;
+}
+#endif  // PROTOBUF_FUTURE_BREAKING_CHANGES
+
+void MessageDifferencer::set_message_field_comparison(
+    MessageFieldComparison comparison) {
+  message_field_comparison_ = comparison;
+}
+
+MessageDifferencer::MessageFieldComparison
+MessageDifferencer::message_field_comparison() const {
+  return message_field_comparison_;
+}
+
+void MessageDifferencer::set_scope(Scope scope) { scope_ = scope; }
+
+MessageDifferencer::Scope MessageDifferencer::scope() const { return scope_; }
+
+void MessageDifferencer::set_float_comparison(FloatComparison comparison) {
+  default_field_comparator_.set_float_comparison(
+      comparison == EXACT ? DefaultFieldComparator::EXACT
+                          : DefaultFieldComparator::APPROXIMATE);
+}
+
+void MessageDifferencer::set_repeated_field_comparison(
+    RepeatedFieldComparison comparison) {
+  repeated_field_comparison_ = comparison;
+}
+
+MessageDifferencer::RepeatedFieldComparison
+MessageDifferencer::repeated_field_comparison() const {
+  return repeated_field_comparison_;
+}
+
+void MessageDifferencer::CheckRepeatedFieldComparisons(
+    const FieldDescriptor* field,
+    const RepeatedFieldComparison& new_comparison) {
+  GOOGLE_CHECK(field->is_repeated())
+      << "Field must be repeated: " << field->full_name();
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
+  GOOGLE_CHECK(key_comparator == NULL)
+      << "Cannot treat this repeated field as both MAP and " << new_comparison
+      << " for comparison.  Field name is: " << field->full_name();
+}
+
+void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SET);
+  repeated_field_comparisons_[field] = AS_SET;
+}
+
+void MessageDifferencer::TreatAsSmartSet(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SMART_SET);
+  repeated_field_comparisons_[field] = AS_SMART_SET;
+}
+
+void MessageDifferencer::SetMatchIndicesForSmartListCallback(
+    std::function<void(std::vector<int>*, std::vector<int>*)> callback) {
+  match_indices_for_smart_list_callback_ = callback;
+}
+
+void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_LIST);
+  repeated_field_comparisons_[field] = AS_LIST;
+}
+
+void MessageDifferencer::TreatAsSmartList(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SMART_LIST);
+  repeated_field_comparisons_[field] = AS_SMART_LIST;
+}
+
+void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
+                                    const FieldDescriptor* key) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
+      << "Field has to be message type.  Field name is: " << field->full_name();
+  GOOGLE_CHECK(key->containing_type() == field->message_type())
+      << key->full_name()
+      << " must be a direct subfield within the repeated field "
+      << field->full_name() << ", not " << key->containing_type()->full_name();
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: " << field->full_name();
+  MapKeyComparator* key_comparator =
+      new MultipleFieldsMapKeyComparator(this, key);
+  owned_key_comparators_.push_back(key_comparator);
+  map_field_key_comparator_[field] = key_comparator;
+}
+
+void MessageDifferencer::TreatAsMapWithMultipleFieldsAsKey(
+    const FieldDescriptor* field,
+    const std::vector<const FieldDescriptor*>& key_fields) {
+  std::vector<std::vector<const FieldDescriptor*> > key_field_paths;
+  for (const FieldDescriptor* key_filed : key_fields) {
+    std::vector<const FieldDescriptor*> key_field_path;
+    key_field_path.push_back(key_filed);
+    key_field_paths.push_back(key_field_path);
+  }
+  TreatAsMapWithMultipleFieldPathsAsKey(field, key_field_paths);
+}
+
+void MessageDifferencer::TreatAsMapWithMultipleFieldPathsAsKey(
+    const FieldDescriptor* field,
+    const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
+  GOOGLE_CHECK(field->is_repeated())
+      << "Field must be repeated: " << field->full_name();
+  GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
+      << "Field has to be message type.  Field name is: " << field->full_name();
+  for (const auto& key_field_path : key_field_paths) {
+    for (size_t j = 0; j < key_field_path.size(); ++j) {
+      const FieldDescriptor* parent_field =
+          j == 0 ? field : key_field_path[j - 1];
+      const FieldDescriptor* child_field = key_field_path[j];
+      GOOGLE_CHECK(child_field->containing_type() == parent_field->message_type())
+          << child_field->full_name()
+          << " must be a direct subfield within the field: "
+          << parent_field->full_name();
+      if (j != 0) {
+        GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, parent_field->cpp_type())
+            << parent_field->full_name() << " has to be of type message.";
+        GOOGLE_CHECK(!parent_field->is_repeated())
+            << parent_field->full_name() << " cannot be a repeated field.";
+      }
+    }
+  }
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: " << field->full_name();
+  MapKeyComparator* key_comparator =
+      new MultipleFieldsMapKeyComparator(this, key_field_paths);
+  owned_key_comparators_.push_back(key_comparator);
+  map_field_key_comparator_[field] = key_comparator;
+}
+
+void MessageDifferencer::TreatAsMapUsingKeyComparator(
+    const FieldDescriptor* field, const MapKeyComparator* key_comparator) {
+  GOOGLE_CHECK(field->is_repeated())
+      << "Field must be repeated: " << field->full_name();
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: " << field->full_name();
+  map_field_key_comparator_[field] = key_comparator;
+}
+
+void MessageDifferencer::AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) {
+  ignore_criteria_.push_back(ignore_criteria);
+}
+
+void MessageDifferencer::IgnoreField(const FieldDescriptor* field) {
+  ignored_fields_.insert(field);
+}
+
+void MessageDifferencer::SetFractionAndMargin(const FieldDescriptor* field,
+                                              double fraction, double margin) {
+  default_field_comparator_.SetFractionAndMargin(field, fraction, margin);
+}
+
+void MessageDifferencer::ReportDifferencesToString(std::string* output) {
+  GOOGLE_DCHECK(output) << "Specified output string was NULL";
+
+  output_string_ = output;
+  output_string_->clear();
+}
+
+void MessageDifferencer::ReportDifferencesTo(Reporter* reporter) {
+  // If an output string is set, clear it to prevent
+  // it superseding the specified reporter.
+  if (output_string_) {
+    output_string_ = NULL;
+  }
+
+  reporter_ = reporter;
+}
+
+bool MessageDifferencer::FieldBefore(const FieldDescriptor* field1,
+                                     const FieldDescriptor* field2) {
+  // Handle sentinel values (i.e. make sure NULLs are always ordered
+  // at the end of the list).
+  if (field1 == NULL) {
+    return false;
+  }
+
+  if (field2 == NULL) {
+    return true;
+  }
+
+  // Always order fields by their tag number
+  return (field1->number() < field2->number());
+}
+
+bool MessageDifferencer::Compare(const Message& message1,
+                                 const Message& message2) {
+  std::vector<SpecificField> parent_fields;
+
+  bool result = false;
+  // Setup the internal reporter if need be.
+  if (output_string_) {
+    io::StringOutputStream output_stream(output_string_);
+    StreamReporter reporter(&output_stream);
+    reporter.SetMessages(message1, message2);
+    reporter_ = &reporter;
+    result = Compare(message1, message2, &parent_fields);
+    reporter_ = NULL;
+  } else {
+    result = Compare(message1, message2, &parent_fields);
+  }
+  return result;
+}
+
+bool MessageDifferencer::CompareWithFields(
+    const Message& message1, const Message& message2,
+    const std::vector<const FieldDescriptor*>& message1_fields_arg,
+    const std::vector<const FieldDescriptor*>& message2_fields_arg) {
+  if (message1.GetDescriptor() != message2.GetDescriptor()) {
+    GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
+                << "descriptors.";
+    return false;
+  }
+
+  std::vector<SpecificField> parent_fields;
+
+  bool result = false;
+
+  FieldDescriptorArray message1_fields(message1_fields_arg.size() + 1);
+  FieldDescriptorArray message2_fields(message2_fields_arg.size() + 1);
+
+  std::copy(message1_fields_arg.cbegin(), message1_fields_arg.cend(),
+            message1_fields.begin());
+  std::copy(message2_fields_arg.cbegin(), message2_fields_arg.cend(),
+            message2_fields.begin());
+
+  // Append sentinel values.
+  message1_fields[message1_fields_arg.size()] = nullptr;
+  message2_fields[message2_fields_arg.size()] = nullptr;
+
+  std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore);
+  std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore);
+
+  // Setup the internal reporter if need be.
+  if (output_string_) {
+    io::StringOutputStream output_stream(output_string_);
+    StreamReporter reporter(&output_stream);
+    reporter_ = &reporter;
+    result = CompareRequestedFieldsUsingSettings(
+        message1, message2, message1_fields, message2_fields, &parent_fields);
+    reporter_ = NULL;
+  } else {
+    result = CompareRequestedFieldsUsingSettings(
+        message1, message2, message1_fields, message2_fields, &parent_fields);
+  }
+
+  return result;
+}
+
+bool MessageDifferencer::Compare(const Message& message1,
+                                 const Message& message2,
+                                 std::vector<SpecificField>* parent_fields) {
+  const Descriptor* descriptor1 = message1.GetDescriptor();
+  const Descriptor* descriptor2 = message2.GetDescriptor();
+  if (descriptor1 != descriptor2) {
+    GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
+                << "descriptors. " << descriptor1->full_name() << " vs "
+                << descriptor2->full_name();
+    return false;
+  }
+
+  // Expand google.protobuf.Any payload if possible.
+  if (descriptor1->full_name() == internal::kAnyFullTypeName) {
+    std::unique_ptr<Message> data1;
+    std::unique_ptr<Message> data2;
+    if (unpack_any_field_.UnpackAny(message1, &data1) &&
+        unpack_any_field_.UnpackAny(message2, &data2)) {
+      // Avoid DFATAL for different descriptors in google.protobuf.Any payloads.
+      if (data1->GetDescriptor() != data2->GetDescriptor()) {
+        return false;
+      }
+      return Compare(*data1, *data2, parent_fields);
+    }
+  }
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  bool unknown_compare_result = true;
+  // Ignore unknown fields in EQUIVALENT mode
+  if (message_field_comparison_ != EQUIVALENT) {
+    const UnknownFieldSet& unknown_field_set1 =
+        reflection1->GetUnknownFields(message1);
+    const UnknownFieldSet& unknown_field_set2 =
+        reflection2->GetUnknownFields(message2);
+    if (!CompareUnknownFields(message1, message2, unknown_field_set1,
+                              unknown_field_set2, parent_fields)) {
+      if (reporter_ == NULL) {
+        return false;
+      }
+      unknown_compare_result = false;
+    }
+  }
+
+  FieldDescriptorArray message1_fields = RetrieveFields(message1, true);
+  FieldDescriptorArray message2_fields = RetrieveFields(message2, false);
+
+  return CompareRequestedFieldsUsingSettings(message1, message2,
+                                             message1_fields, message2_fields,
+                                             parent_fields) &&
+         unknown_compare_result;
+}
+
+FieldDescriptorArray MessageDifferencer::RetrieveFields(const Message& message,
+                                                        bool base_message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+
+  tmp_message_fields_.clear();
+  tmp_message_fields_.reserve(descriptor->field_count() + 1);
+
+  const Reflection* reflection = message.GetReflection();
+  if (descriptor->options().map_entry()) {
+    if (this->scope_ == PARTIAL && base_message) {
+      reflection->ListFields(message, &tmp_message_fields_);
+    } else {
+      // Map entry fields are always considered present.
+      for (int i = 0; i < descriptor->field_count(); i++) {
+        tmp_message_fields_.push_back(descriptor->field(i));
+      }
+    }
+  } else {
+    reflection->ListFields(message, &tmp_message_fields_);
+  }
+  // Add sentinel values to deal with the
+  // case where the number of the fields in
+  // each list are different.
+  tmp_message_fields_.push_back(nullptr);
+
+  FieldDescriptorArray message_fields(tmp_message_fields_.begin(),
+                                      tmp_message_fields_.end());
+
+  return message_fields;
+}
+
+bool MessageDifferencer::CompareRequestedFieldsUsingSettings(
+    const Message& message1, const Message& message2,
+    const FieldDescriptorArray& message1_fields,
+    const FieldDescriptorArray& message2_fields,
+    std::vector<SpecificField>* parent_fields) {
+  if (scope_ == FULL) {
+    if (message_field_comparison_ == EQUIVALENT) {
+      // We need to merge the field lists of both messages (i.e.
+      // we are merely checking for a difference in field values,
+      // rather than the addition or deletion of fields).
+      FieldDescriptorArray fields_union =
+          CombineFields(message1_fields, FULL, message2_fields, FULL);
+      return CompareWithFieldsInternal(message1, message2, fields_union,
+                                       fields_union, parent_fields);
+    } else {
+      // Simple equality comparison, use the unaltered field lists.
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       message2_fields, parent_fields);
+    }
+  } else {
+    if (message_field_comparison_ == EQUIVALENT) {
+      // We use the list of fields for message1 for both messages when
+      // comparing.  This way, extra fields in message2 are ignored,
+      // and missing fields in message2 use their default value.
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       message1_fields, parent_fields);
+    } else {
+      // We need to consider the full list of fields for message1
+      // but only the intersection for message2.  This way, any fields
+      // only present in message2 will be ignored, but any fields only
+      // present in message1 will be marked as a difference.
+      FieldDescriptorArray fields_intersection =
+          CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL);
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       fields_intersection, parent_fields);
+    }
+  }
+}
+
+FieldDescriptorArray MessageDifferencer::CombineFields(
+    const FieldDescriptorArray& fields1, Scope fields1_scope,
+    const FieldDescriptorArray& fields2, Scope fields2_scope) {
+  size_t index1 = 0;
+  size_t index2 = 0;
+
+  tmp_message_fields_.clear();
+
+  while (index1 < fields1.size() && index2 < fields2.size()) {
+    const FieldDescriptor* field1 = fields1[index1];
+    const FieldDescriptor* field2 = fields2[index2];
+
+    if (FieldBefore(field1, field2)) {
+      if (fields1_scope == FULL) {
+        tmp_message_fields_.push_back(fields1[index1]);
+      }
+      ++index1;
+    } else if (FieldBefore(field2, field1)) {
+      if (fields2_scope == FULL) {
+        tmp_message_fields_.push_back(fields2[index2]);
+      }
+      ++index2;
+    } else {
+      tmp_message_fields_.push_back(fields1[index1]);
+      ++index1;
+      ++index2;
+    }
+  }
+
+  tmp_message_fields_.push_back(nullptr);
+
+  FieldDescriptorArray combined_fields(tmp_message_fields_.begin(),
+                                       tmp_message_fields_.end());
+
+  return combined_fields;
+}
+
+bool MessageDifferencer::CompareWithFieldsInternal(
+    const Message& message1, const Message& message2,
+    const FieldDescriptorArray& message1_fields,
+    const FieldDescriptorArray& message2_fields,
+    std::vector<SpecificField>* parent_fields) {
+  bool isDifferent = false;
+  int field_index1 = 0;
+  int field_index2 = 0;
+
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  while (true) {
+    const FieldDescriptor* field1 = message1_fields[field_index1];
+    const FieldDescriptor* field2 = message2_fields[field_index2];
+
+    // Once we have reached sentinel values, we are done the comparison.
+    if (field1 == NULL && field2 == NULL) {
+      break;
+    }
+
+    // Check for differences in the field itself.
+    if (FieldBefore(field1, field2)) {
+      // Field 1 is not in the field list for message 2.
+      if (IsIgnored(message1, message2, field1, *parent_fields)) {
+        // We are ignoring field1. Report the ignore and move on to
+        // the next field in message1_fields.
+        if (reporter_ != NULL) {
+          SpecificField specific_field;
+          specific_field.field = field1;
+          parent_fields->push_back(specific_field);
+          if (report_ignores_) {
+            reporter_->ReportIgnored(message1, message2, *parent_fields);
+          }
+          parent_fields->pop_back();
+        }
+        ++field_index1;
+        continue;
+      }
+
+      if (reporter_ != NULL) {
+        assert(field1 != NULL);
+        int count = field1->is_repeated()
+                        ? reflection1->FieldSize(message1, field1)
+                        : 1;
+
+        for (int i = 0; i < count; ++i) {
+          SpecificField specific_field;
+          specific_field.field = field1;
+          if (field1->is_repeated()) {
+            AddSpecificIndex(&specific_field, message1, field1, i);
+          } else {
+            specific_field.index = -1;
+          }
+
+          parent_fields->push_back(specific_field);
+          reporter_->ReportDeleted(message1, message2, *parent_fields);
+          parent_fields->pop_back();
+        }
+
+        isDifferent = true;
+      } else {
+        return false;
+      }
+
+      ++field_index1;
+      continue;
+    } else if (FieldBefore(field2, field1)) {
+      // Field 2 is not in the field list for message 1.
+      if (IsIgnored(message1, message2, field2, *parent_fields)) {
+        // We are ignoring field2. Report the ignore and move on to
+        // the next field in message2_fields.
+        if (reporter_ != NULL) {
+          SpecificField specific_field;
+          specific_field.field = field2;
+          parent_fields->push_back(specific_field);
+          if (report_ignores_) {
+            reporter_->ReportIgnored(message1, message2, *parent_fields);
+          }
+          parent_fields->pop_back();
+        }
+        ++field_index2;
+        continue;
+      }
+
+      if (reporter_ != NULL) {
+        int count = field2->is_repeated()
+                        ? reflection2->FieldSize(message2, field2)
+                        : 1;
+
+        for (int i = 0; i < count; ++i) {
+          SpecificField specific_field;
+          specific_field.field = field2;
+          if (field2->is_repeated()) {
+            specific_field.index = i;
+            AddSpecificNewIndex(&specific_field, message2, field2, i);
+          } else {
+            specific_field.index = -1;
+            specific_field.new_index = -1;
+          }
+
+          parent_fields->push_back(specific_field);
+          reporter_->ReportAdded(message1, message2, *parent_fields);
+          parent_fields->pop_back();
+        }
+
+        isDifferent = true;
+      } else {
+        return false;
+      }
+
+      ++field_index2;
+      continue;
+    }
+
+    // By this point, field1 and field2 are guaranteed to point to the same
+    // field, so we can now compare the values.
+    if (IsIgnored(message1, message2, field1, *parent_fields)) {
+      // Ignore this field. Report and move on.
+      if (reporter_ != NULL) {
+        SpecificField specific_field;
+        specific_field.field = field1;
+        parent_fields->push_back(specific_field);
+        if (report_ignores_) {
+          reporter_->ReportIgnored(message1, message2, *parent_fields);
+        }
+        parent_fields->pop_back();
+      }
+
+      ++field_index1;
+      ++field_index2;
+      continue;
+    }
+
+    bool fieldDifferent = false;
+    assert(field1 != NULL);
+    if (field1->is_map()) {
+      fieldDifferent =
+          !CompareMapField(message1, message2, field1, parent_fields);
+    } else if (field1->is_repeated()) {
+      fieldDifferent =
+          !CompareRepeatedField(message1, message2, field1, parent_fields);
+    } else {
+      fieldDifferent = !CompareFieldValueUsingParentFields(
+          message1, message2, field1, -1, -1, parent_fields);
+
+      if (reporter_ != nullptr) {
+        SpecificField specific_field;
+        specific_field.field = field1;
+        parent_fields->push_back(specific_field);
+        if (fieldDifferent) {
+          reporter_->ReportModified(message1, message2, *parent_fields);
+          isDifferent = true;
+        } else if (report_matches_) {
+          reporter_->ReportMatched(message1, message2, *parent_fields);
+        }
+        parent_fields->pop_back();
+      }
+    }
+    if (fieldDifferent) {
+      if (reporter_ == nullptr) return false;
+      isDifferent = true;
+    }
+    // Increment the field indices.
+    ++field_index1;
+    ++field_index2;
+  }
+
+  return !isDifferent;
+}
+
+bool MessageDifferencer::IsMatch(
+    const FieldDescriptor* repeated_field,
+    const MapKeyComparator* key_comparator, const Message* message1,
+    const Message* message2, const std::vector<SpecificField>& parent_fields,
+    Reporter* reporter, int index1, int index2) {
+  std::vector<SpecificField> current_parent_fields(parent_fields);
+  if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    return CompareFieldValueUsingParentFields(*message1, *message2,
+                                              repeated_field, index1, index2,
+                                              &current_parent_fields);
+  }
+  // Back up the Reporter and output_string_.  They will be reset in the
+  // following code.
+  Reporter* backup_reporter = reporter_;
+  std::string* output_string = output_string_;
+  reporter_ = reporter;
+  output_string_ = NULL;
+  bool match;
+
+  if (key_comparator == NULL) {
+    match = CompareFieldValueUsingParentFields(*message1, *message2,
+                                               repeated_field, index1, index2,
+                                               &current_parent_fields);
+  } else {
+    const Reflection* reflection1 = message1->GetReflection();
+    const Reflection* reflection2 = message2->GetReflection();
+    const Message& m1 =
+        reflection1->GetRepeatedMessage(*message1, repeated_field, index1);
+    const Message& m2 =
+        reflection2->GetRepeatedMessage(*message2, repeated_field, index2);
+    SpecificField specific_field;
+    specific_field.field = repeated_field;
+    if (repeated_field->is_map()) {
+      specific_field.map_entry1 = &m1;
+      specific_field.map_entry2 = &m2;
+    }
+    specific_field.index = index1;
+    specific_field.new_index = index2;
+    current_parent_fields.push_back(specific_field);
+    match = key_comparator->IsMatch(m1, m2, current_parent_fields);
+  }
+
+  reporter_ = backup_reporter;
+  output_string_ = output_string;
+  return match;
+}
+
+bool MessageDifferencer::CompareMapFieldByMapReflection(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* map_field, std::vector<SpecificField>* parent_fields,
+    DefaultFieldComparator* comparator) {
+  GOOGLE_DCHECK_EQ(nullptr, reporter_);
+  GOOGLE_DCHECK(map_field->is_map());
+  GOOGLE_DCHECK(map_field_key_comparator_.find(map_field) ==
+         map_field_key_comparator_.end());
+  GOOGLE_DCHECK_EQ(repeated_field_comparison_, AS_LIST);
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+  const int count1 = reflection1->MapSize(message1, map_field);
+  const int count2 = reflection2->MapSize(message2, map_field);
+  const bool treated_as_subset = IsTreatedAsSubset(map_field);
+  if (count1 != count2 && !treated_as_subset) {
+    return false;
+  }
+  if (count1 > count2) {
+    return false;
+  }
+
+  // First pass: check whether the same keys are present.
+  for (MapIterator it = reflection1->MapBegin(const_cast<Message*>(&message1),
+                                              map_field),
+                   it_end = reflection1->MapEnd(const_cast<Message*>(&message1),
+                                                map_field);
+       it != it_end; ++it) {
+    if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) {
+      return false;
+    }
+  }
+
+  // Second pass: compare values for matching keys.
+  const FieldDescriptor* val_des = map_field->message_type()->map_value();
+  switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, METHOD, COMPAREMETHOD)                           \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                                  \
+    for (MapIterator it = reflection1->MapBegin(                              \
+                         const_cast<Message*>(&message1), map_field),         \
+                     it_end = reflection1->MapEnd(                            \
+                         const_cast<Message*>(&message1), map_field);         \
+         it != it_end; ++it) {                                                \
+      MapValueConstRef value2;                                                \
+      reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2); \
+      if (!comparator->Compare##COMPAREMETHOD(*val_des,                       \
+                                              it.GetValueRef().Get##METHOD(), \
+                                              value2.Get##METHOD())) {        \
+        return false;                                                         \
+      }                                                                       \
+    }                                                                         \
+    break;                                                                    \
+  }
+    HANDLE_TYPE(INT32, Int32Value, Int32);
+    HANDLE_TYPE(INT64, Int64Value, Int64);
+    HANDLE_TYPE(UINT32, UInt32Value, UInt32);
+    HANDLE_TYPE(UINT64, UInt64Value, UInt64);
+    HANDLE_TYPE(DOUBLE, DoubleValue, Double);
+    HANDLE_TYPE(FLOAT, FloatValue, Float);
+    HANDLE_TYPE(BOOL, BoolValue, Bool);
+    HANDLE_TYPE(STRING, StringValue, String);
+    HANDLE_TYPE(ENUM, EnumValue, Int32);
+#undef HANDLE_TYPE
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      for (MapIterator it = reflection1->MapBegin(
+               const_cast<Message*>(&message1), map_field);
+           it !=
+           reflection1->MapEnd(const_cast<Message*>(&message1), map_field);
+           ++it) {
+        if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) {
+          return false;
+        }
+        bool compare_result;
+        MapValueConstRef value2;
+        reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2);
+        // Append currently compared field to the end of parent_fields.
+        SpecificField specific_value_field;
+        specific_value_field.field = val_des;
+        parent_fields->push_back(specific_value_field);
+        compare_result = Compare(it.GetValueRef().GetMessageValue(),
+                                 value2.GetMessageValue(), parent_fields);
+        parent_fields->pop_back();
+        if (!compare_result) {
+          return false;
+        }
+      }
+      break;
+    }
+  }
+  return true;
+}
+
+bool MessageDifferencer::CompareMapField(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    std::vector<SpecificField>* parent_fields) {
+  GOOGLE_DCHECK(repeated_field->is_map());
+
+  // the input FieldDescriptor is guaranteed to be repeated field.
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  // When both map fields are on map, do not sync to repeated field.
+  if (reflection1->GetMapData(message1, repeated_field)->IsMapValid() &&
+      reflection2->GetMapData(message2, repeated_field)->IsMapValid() &&
+      // TODO(jieluo): Add support for reporter
+      reporter_ == nullptr &&
+      // Users didn't set custom map field key comparator
+      map_field_key_comparator_.find(repeated_field) ==
+          map_field_key_comparator_.end() &&
+      // Users didn't set repeated field comparison
+      repeated_field_comparison_ == AS_LIST &&
+      // Users didn't set their own FieldComparator implementation
+      field_comparator_kind_ == kFCDefault) {
+    const FieldDescriptor* key_des = repeated_field->message_type()->map_key();
+    const FieldDescriptor* val_des =
+        repeated_field->message_type()->map_value();
+    std::vector<SpecificField> current_parent_fields(*parent_fields);
+    SpecificField specific_field;
+    specific_field.field = repeated_field;
+    current_parent_fields.push_back(specific_field);
+    if (!IsIgnored(message1, message2, key_des, current_parent_fields) &&
+        !IsIgnored(message1, message2, val_des, current_parent_fields)) {
+      return CompareMapFieldByMapReflection(message1, message2, repeated_field,
+                                            &current_parent_fields,
+                                            field_comparator_.default_impl);
+    }
+  }
+
+  return CompareRepeatedRep(message1, message2, repeated_field, parent_fields);
+}
+
+bool MessageDifferencer::CompareRepeatedField(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    std::vector<SpecificField>* parent_fields) {
+  GOOGLE_DCHECK(!repeated_field->is_map());
+  return CompareRepeatedRep(message1, message2, repeated_field, parent_fields);
+}
+
+bool MessageDifferencer::CompareRepeatedRep(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    std::vector<SpecificField>* parent_fields) {
+  // the input FieldDescriptor is guaranteed to be repeated field.
+  GOOGLE_DCHECK(repeated_field->is_repeated());
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  const int count1 = reflection1->FieldSize(message1, repeated_field);
+  const int count2 = reflection2->FieldSize(message2, repeated_field);
+  const bool treated_as_subset = IsTreatedAsSubset(repeated_field);
+
+  // If the field is not treated as subset and no detailed reports is needed,
+  // we do a quick check on the number of the elements to avoid unnecessary
+  // comparison.
+  if (count1 != count2 && reporter_ == NULL && !treated_as_subset) {
+    return false;
+  }
+  // A match can never be found if message1 has more items than message2.
+  if (count1 > count2 && reporter_ == NULL) {
+    return false;
+  }
+
+  // These two list are used for store the index of the correspondent
+  // element in peer repeated field.
+  std::vector<int> match_list1;
+  std::vector<int> match_list2;
+
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(repeated_field);
+  bool smart_list = IsTreatedAsSmartList(repeated_field);
+  bool simple_list = key_comparator == nullptr &&
+                     !IsTreatedAsSet(repeated_field) &&
+                     !IsTreatedAsSmartSet(repeated_field) && !smart_list;
+
+  // For simple lists, we avoid matching repeated field indices, saving the
+  // memory allocations that would otherwise be needed for match_list1 and
+  // match_list2.
+  if (!simple_list) {
+    // Try to match indices of the repeated fields. Return false if match fails.
+    if (!MatchRepeatedFieldIndices(message1, message2, repeated_field,
+                                   key_comparator, *parent_fields, &match_list1,
+                                   &match_list2) &&
+        reporter_ == nullptr) {
+      return false;
+    }
+  }
+
+  bool fieldDifferent = false;
+  SpecificField specific_field;
+  specific_field.field = repeated_field;
+
+  // At this point, we have already matched pairs of fields (with the reporting
+  // to be done later). Now to check if the paired elements are different.
+  int next_unmatched_index = 0;
+  for (int i = 0; i < count1; i++) {
+    if (simple_list && i >= count2) {
+      break;
+    }
+    if (!simple_list && match_list1[i] == -1) {
+      if (smart_list) {
+        if (reporter_ == nullptr) return false;
+        AddSpecificIndex(&specific_field, message1, repeated_field, i);
+        parent_fields->push_back(specific_field);
+        reporter_->ReportDeleted(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+        fieldDifferent = true;
+        // Use -2 to mark this element has been reported.
+        match_list1[i] = -2;
+      }
+      continue;
+    }
+    if (smart_list) {
+      for (int j = next_unmatched_index; j < match_list1[i]; ++j) {
+        GOOGLE_CHECK_LE(0, j);
+        if (reporter_ == nullptr) return false;
+        specific_field.index = j;
+        AddSpecificNewIndex(&specific_field, message2, repeated_field, j);
+        parent_fields->push_back(specific_field);
+        reporter_->ReportAdded(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+        fieldDifferent = true;
+        // Use -2 to mark this element has been reported.
+        match_list2[j] = -2;
+      }
+    }
+    AddSpecificIndex(&specific_field, message1, repeated_field, i);
+    if (simple_list) {
+      AddSpecificNewIndex(&specific_field, message2, repeated_field, i);
+    } else {
+      AddSpecificNewIndex(&specific_field, message2, repeated_field,
+                          match_list1[i]);
+      next_unmatched_index = match_list1[i] + 1;
+    }
+
+    const bool result = CompareFieldValueUsingParentFields(
+        message1, message2, repeated_field, i, specific_field.new_index,
+        parent_fields);
+
+    // If we have found differences, either report them or terminate if
+    // no reporter is present. Note that ReportModified, ReportMoved, and
+    // ReportMatched are all mutually exclusive.
+    if (!result) {
+      if (reporter_ == NULL) return false;
+      parent_fields->push_back(specific_field);
+      reporter_->ReportModified(message1, message2, *parent_fields);
+      parent_fields->pop_back();
+      fieldDifferent = true;
+    } else if (reporter_ != NULL &&
+               specific_field.index != specific_field.new_index &&
+               !specific_field.field->is_map() && report_moves_) {
+      parent_fields->push_back(specific_field);
+      reporter_->ReportMoved(message1, message2, *parent_fields);
+      parent_fields->pop_back();
+    } else if (report_matches_ && reporter_ != NULL) {
+      parent_fields->push_back(specific_field);
+      reporter_->ReportMatched(message1, message2, *parent_fields);
+      parent_fields->pop_back();
+    }
+  }
+
+  // Report any remaining additions or deletions.
+  for (int i = 0; i < count2; ++i) {
+    if (!simple_list && match_list2[i] != -1) continue;
+    if (simple_list && i < count1) continue;
+    if (!treated_as_subset) {
+      fieldDifferent = true;
+    }
+
+    if (reporter_ == NULL) continue;
+    specific_field.index = i;
+    AddSpecificNewIndex(&specific_field, message2, repeated_field, i);
+    parent_fields->push_back(specific_field);
+    reporter_->ReportAdded(message1, message2, *parent_fields);
+    parent_fields->pop_back();
+  }
+
+  for (int i = 0; i < count1; ++i) {
+    if (!simple_list && match_list1[i] != -1) continue;
+    if (simple_list && i < count2) continue;
+    assert(reporter_ != NULL);
+    AddSpecificIndex(&specific_field, message1, repeated_field, i);
+    parent_fields->push_back(specific_field);
+    reporter_->ReportDeleted(message1, message2, *parent_fields);
+    parent_fields->pop_back();
+    fieldDifferent = true;
+  }
+  return !fieldDifferent;
+}
+
+bool MessageDifferencer::CompareFieldValue(const Message& message1,
+                                           const Message& message2,
+                                           const FieldDescriptor* field,
+                                           int index1, int index2) {
+  return CompareFieldValueUsingParentFields(message1, message2, field, index1,
+                                            index2, NULL);
+}
+
+bool MessageDifferencer::CompareFieldValueUsingParentFields(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* field, int index1, int index2,
+    std::vector<SpecificField>* parent_fields) {
+  FieldContext field_context(parent_fields);
+  FieldComparator::ComparisonResult result = GetFieldComparisonResult(
+      message1, message2, field, index1, index2, &field_context);
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      result == FieldComparator::RECURSE) {
+    // Get the nested messages and compare them using one of the Compare
+    // methods.
+    const Reflection* reflection1 = message1.GetReflection();
+    const Reflection* reflection2 = message2.GetReflection();
+    const Message& m1 =
+        field->is_repeated()
+            ? reflection1->GetRepeatedMessage(message1, field, index1)
+            : reflection1->GetMessage(message1, field);
+    const Message& m2 =
+        field->is_repeated()
+            ? reflection2->GetRepeatedMessage(message2, field, index2)
+            : reflection2->GetMessage(message2, field);
+
+    // parent_fields is used in calls to Reporter methods.
+    if (parent_fields != NULL) {
+      // Append currently compared field to the end of parent_fields.
+      SpecificField specific_field;
+      specific_field.field = field;
+      AddSpecificIndex(&specific_field, message1, field, index1);
+      AddSpecificNewIndex(&specific_field, message2, field, index2);
+      parent_fields->push_back(specific_field);
+      const bool compare_result = Compare(m1, m2, parent_fields);
+      parent_fields->pop_back();
+      return compare_result;
+    } else {
+      // Recreates parent_fields as if m1 and m2 had no parents.
+      return Compare(m1, m2);
+    }
+  } else {
+    return (result == FieldComparator::SAME);
+  }
+}
+
+bool MessageDifferencer::CheckPathChanged(
+    const std::vector<SpecificField>& field_path) {
+  for (const SpecificField& specific_field : field_path) {
+    // Don't check indexes for map entries -- maps are unordered.
+    if (specific_field.field != nullptr && specific_field.field->is_map())
+      continue;
+    if (specific_field.index != specific_field.new_index) return true;
+  }
+  return false;
+}
+
+bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SET;
+  }
+  return GetMapKeyComparator(field) == nullptr &&
+         repeated_field_comparison_ == AS_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartSet(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SMART_SET;
+  }
+  return GetMapKeyComparator(field) == nullptr &&
+         repeated_field_comparison_ == AS_SMART_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartList(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SMART_LIST;
+  }
+  return GetMapKeyComparator(field) == nullptr &&
+         repeated_field_comparison_ == AS_SMART_LIST;
+}
+
+bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
+  return scope_ == PARTIAL &&
+         (IsTreatedAsSet(field) || GetMapKeyComparator(field) != NULL);
+}
+
+bool MessageDifferencer::IsIgnored(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* field,
+    const std::vector<SpecificField>& parent_fields) {
+  if (ignored_fields_.find(field) != ignored_fields_.end()) {
+    return true;
+  }
+  for (IgnoreCriteria* criteria : ignore_criteria_) {
+    if (criteria->IsIgnored(message1, message2, field, parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MessageDifferencer::IsUnknownFieldIgnored(
+    const Message& message1, const Message& message2,
+    const SpecificField& field,
+    const std::vector<SpecificField>& parent_fields) {
+  for (IgnoreCriteria* criteria : ignore_criteria_) {
+    if (criteria->IsUnknownFieldIgnored(message1, message2, field,
+                                        parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+const MessageDifferencer::MapKeyComparator*
+MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) const {
+  if (!field->is_repeated()) return NULL;
+  FieldKeyComparatorMap::const_iterator it =
+      map_field_key_comparator_.find(field);
+  if (it != map_field_key_comparator_.end()) {
+    return it->second;
+  }
+  if (field->is_map()) {
+    // field cannot already be treated as list or set since TreatAsList() and
+    // TreatAsSet() call GetMapKeyComparator() and fail if it returns non-NULL.
+    return &map_entry_key_comparator_;
+  }
+  return NULL;
+}
+
+namespace {
+
+typedef std::pair<int, const UnknownField*> IndexUnknownFieldPair;
+
+struct UnknownFieldOrdering {
+  inline bool operator()(const IndexUnknownFieldPair& a,
+                         const IndexUnknownFieldPair& b) const {
+    if (a.second->number() < b.second->number()) return true;
+    if (a.second->number() > b.second->number()) return false;
+    return a.second->type() < b.second->type();
+  }
+};
+
+}  // namespace
+
+bool MessageDifferencer::UnpackAnyField::UnpackAny(
+    const Message& any, std::unique_ptr<Message>* data) {
+  const Reflection* reflection = any.GetReflection();
+  const FieldDescriptor* type_url_field;
+  const FieldDescriptor* value_field;
+  if (!internal::GetAnyFieldDescriptors(any, &type_url_field, &value_field)) {
+    return false;
+  }
+  const std::string& type_url = reflection->GetString(any, type_url_field);
+  std::string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
+    return false;
+  }
+
+  const Descriptor* desc =
+      any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
+          full_type_name);
+  if (desc == NULL) {
+    GOOGLE_LOG(INFO) << "Proto type '" << full_type_name << "' not found";
+    return false;
+  }
+
+  if (dynamic_message_factory_ == NULL) {
+    dynamic_message_factory_.reset(new DynamicMessageFactory());
+  }
+  data->reset(dynamic_message_factory_->GetPrototype(desc)->New());
+  std::string serialized_value = reflection->GetString(any, value_field);
+  if (!(*data)->ParsePartialFromString(serialized_value)) {
+    GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name;
+    return false;
+  }
+  return true;
+}
+
+bool MessageDifferencer::CompareUnknownFields(
+    const Message& message1, const Message& message2,
+    const UnknownFieldSet& unknown_field_set1,
+    const UnknownFieldSet& unknown_field_set2,
+    std::vector<SpecificField>* parent_field) {
+  // Ignore unknown fields in EQUIVALENT mode.
+  if (message_field_comparison_ == EQUIVALENT) return true;
+
+  if (unknown_field_set1.empty() && unknown_field_set2.empty()) {
+    return true;
+  }
+
+  bool is_different = false;
+
+  // We first sort the unknown fields by field number and type (in other words,
+  // in tag order), making sure to preserve ordering of values with the same
+  // tag.  This allows us to report only meaningful differences between the
+  // two sets -- that is, differing values for the same tag.  We use
+  // IndexUnknownFieldPairs to keep track of the field's original index for
+  // reporting purposes.
+  std::vector<IndexUnknownFieldPair> fields1;  // unknown_field_set1, sorted
+  std::vector<IndexUnknownFieldPair> fields2;  // unknown_field_set2, sorted
+  fields1.reserve(unknown_field_set1.field_count());
+  fields2.reserve(unknown_field_set2.field_count());
+
+  for (int i = 0; i < unknown_field_set1.field_count(); i++) {
+    fields1.push_back(std::make_pair(i, &unknown_field_set1.field(i)));
+  }
+  for (int i = 0; i < unknown_field_set2.field_count(); i++) {
+    fields2.push_back(std::make_pair(i, &unknown_field_set2.field(i)));
+  }
+
+  UnknownFieldOrdering is_before;
+  std::stable_sort(fields1.begin(), fields1.end(), is_before);
+  std::stable_sort(fields2.begin(), fields2.end(), is_before);
+
+  // In order to fill in SpecificField::index, we have to keep track of how
+  // many values we've seen with the same field number and type.
+  // current_repeated points at the first field in this range, and
+  // current_repeated_start{1,2} are the indexes of the first field in the
+  // range within fields1 and fields2.
+  const UnknownField* current_repeated = NULL;
+  int current_repeated_start1 = 0;
+  int current_repeated_start2 = 0;
+
+  // Now that we have two sorted lists, we can detect fields which appear only
+  // in one list or the other by traversing them simultaneously.
+  size_t index1 = 0;
+  size_t index2 = 0;
+  while (index1 < fields1.size() || index2 < fields2.size()) {
+    enum {
+      ADDITION,
+      DELETION,
+      MODIFICATION,
+      COMPARE_GROUPS,
+      NO_CHANGE
+    } change_type;
+
+    // focus_field is the field we're currently reporting on.  (In the case
+    // of a modification, it's the field on the left side.)
+    const UnknownField* focus_field;
+    bool match = false;
+
+    if (index2 == fields2.size() ||
+        (index1 < fields1.size() &&
+         is_before(fields1[index1], fields2[index2]))) {
+      // fields1[index1] is not present in fields2.
+      change_type = DELETION;
+      focus_field = fields1[index1].second;
+    } else if (index1 == fields1.size() ||
+               is_before(fields2[index2], fields1[index1])) {
+      // fields2[index2] is not present in fields1.
+      if (scope_ == PARTIAL) {
+        // Ignore.
+        ++index2;
+        continue;
+      }
+      change_type = ADDITION;
+      focus_field = fields2[index2].second;
+    } else {
+      // Field type and number are the same.  See if the values differ.
+      change_type = MODIFICATION;
+      focus_field = fields1[index1].second;
+
+      switch (focus_field->type()) {
+        case UnknownField::TYPE_VARINT:
+          match = fields1[index1].second->varint() ==
+                  fields2[index2].second->varint();
+          break;
+        case UnknownField::TYPE_FIXED32:
+          match = fields1[index1].second->fixed32() ==
+                  fields2[index2].second->fixed32();
+          break;
+        case UnknownField::TYPE_FIXED64:
+          match = fields1[index1].second->fixed64() ==
+                  fields2[index2].second->fixed64();
+          break;
+        case UnknownField::TYPE_LENGTH_DELIMITED:
+          match = fields1[index1].second->length_delimited() ==
+                  fields2[index2].second->length_delimited();
+          break;
+        case UnknownField::TYPE_GROUP:
+          // We must deal with this later, after building the SpecificField.
+          change_type = COMPARE_GROUPS;
+          break;
+      }
+      if (match && change_type != COMPARE_GROUPS) {
+        change_type = NO_CHANGE;
+      }
+    }
+
+    if (current_repeated == NULL ||
+        focus_field->number() != current_repeated->number() ||
+        focus_field->type() != current_repeated->type()) {
+      // We've started a new repeated field.
+      current_repeated = focus_field;
+      current_repeated_start1 = index1;
+      current_repeated_start2 = index2;
+    }
+
+    if (change_type == NO_CHANGE && reporter_ == NULL) {
+      // Fields were already compared and matched and we have no reporter.
+      ++index1;
+      ++index2;
+      continue;
+    }
+
+    // Build the SpecificField.  This is slightly complicated.
+    SpecificField specific_field;
+    specific_field.unknown_field_number = focus_field->number();
+    specific_field.unknown_field_type = focus_field->type();
+
+    specific_field.unknown_field_set1 = &unknown_field_set1;
+    specific_field.unknown_field_set2 = &unknown_field_set2;
+
+    if (change_type != ADDITION) {
+      specific_field.unknown_field_index1 = fields1[index1].first;
+    }
+    if (change_type != DELETION) {
+      specific_field.unknown_field_index2 = fields2[index2].first;
+    }
+
+    // Calculate the field index.
+    if (change_type == ADDITION) {
+      specific_field.index = index2 - current_repeated_start2;
+      specific_field.new_index = index2 - current_repeated_start2;
+    } else {
+      specific_field.index = index1 - current_repeated_start1;
+      specific_field.new_index = index2 - current_repeated_start2;
+    }
+
+    if (IsUnknownFieldIgnored(message1, message2, specific_field,
+                              *parent_field)) {
+      if (report_ignores_ && reporter_ != NULL) {
+        parent_field->push_back(specific_field);
+        reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
+        parent_field->pop_back();
+      }
+      if (change_type != ADDITION) ++index1;
+      if (change_type != DELETION) ++index2;
+      continue;
+    }
+
+    if (change_type == ADDITION || change_type == DELETION ||
+        change_type == MODIFICATION) {
+      if (reporter_ == NULL) {
+        // We found a difference and we have no reporter.
+        return false;
+      }
+      is_different = true;
+    }
+
+    parent_field->push_back(specific_field);
+
+    switch (change_type) {
+      case ADDITION:
+        reporter_->ReportAdded(message1, message2, *parent_field);
+        ++index2;
+        break;
+      case DELETION:
+        reporter_->ReportDeleted(message1, message2, *parent_field);
+        ++index1;
+        break;
+      case MODIFICATION:
+        reporter_->ReportModified(message1, message2, *parent_field);
+        ++index1;
+        ++index2;
+        break;
+      case COMPARE_GROUPS:
+        if (!CompareUnknownFields(
+                message1, message2, fields1[index1].second->group(),
+                fields2[index2].second->group(), parent_field)) {
+          if (reporter_ == NULL) return false;
+          is_different = true;
+          reporter_->ReportModified(message1, message2, *parent_field);
+        }
+        ++index1;
+        ++index2;
+        break;
+      case NO_CHANGE:
+        ++index1;
+        ++index2;
+        if (report_matches_) {
+          reporter_->ReportMatched(message1, message2, *parent_field);
+        }
+    }
+
+    parent_field->pop_back();
+  }
+
+  return !is_different;
+}
+
+namespace {
+
+// Find maximum bipartite matching using the argumenting path algorithm.
+class MaximumMatcher {
+ public:
+  typedef std::function<bool(int, int)> NodeMatchCallback;
+  // MaximumMatcher takes ownership of the passed in callback and uses it to
+  // determine whether a node on the left side of the bipartial graph matches
+  // a node on the right side. count1 is the number of nodes on the left side
+  // of the graph and count2 to is the number of nodes on the right side.
+  // Every node is referred to using 0-based indices.
+  // If a maximum match is found, the result will be stored in match_list1 and
+  // match_list2. match_list1[i] == j means the i-th node on the left side is
+  // matched to the j-th node on the right side and match_list2[x] == y means
+  // the x-th node on the right side is matched to y-th node on the left side.
+  // match_list1[i] == -1 means the node is not matched. Same with match_list2.
+  MaximumMatcher(int count1, int count2, NodeMatchCallback callback,
+                 std::vector<int>* match_list1, std::vector<int>* match_list2);
+  // Find a maximum match and return the number of matched node pairs.
+  // If early_return is true, this method will return 0 immediately when it
+  // finds that not all nodes on the left side can be matched.
+  int FindMaximumMatch(bool early_return);
+
+ private:
+  // Determines whether the node on the left side of the bipartial graph
+  // matches the one on the right side.
+  bool Match(int left, int right);
+  // Find an argumenting path starting from the node v on the left side. If a
+  // path can be found, update match_list2_ to reflect the path and return
+  // true.
+  bool FindArgumentPathDFS(int v, std::vector<bool>* visited);
+
+  int count1_;
+  int count2_;
+  NodeMatchCallback match_callback_;
+  std::map<std::pair<int, int>, bool> cached_match_results_;
+  std::vector<int>* match_list1_;
+  std::vector<int>* match_list2_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MaximumMatcher);
+};
+
+MaximumMatcher::MaximumMatcher(int count1, int count2,
+                               NodeMatchCallback callback,
+                               std::vector<int>* match_list1,
+                               std::vector<int>* match_list2)
+    : count1_(count1),
+      count2_(count2),
+      match_callback_(std::move(callback)),
+      match_list1_(match_list1),
+      match_list2_(match_list2) {
+  match_list1_->assign(count1, -1);
+  match_list2_->assign(count2, -1);
+}
+
+int MaximumMatcher::FindMaximumMatch(bool early_return) {
+  int result = 0;
+  for (int i = 0; i < count1_; ++i) {
+    std::vector<bool> visited(count1_);
+    if (FindArgumentPathDFS(i, &visited)) {
+      ++result;
+    } else if (early_return) {
+      return 0;
+    }
+  }
+  // Backfill match_list1_ as we only filled match_list2_ when finding
+  // argumenting paths.
+  for (int i = 0; i < count2_; ++i) {
+    if ((*match_list2_)[i] != -1) {
+      (*match_list1_)[(*match_list2_)[i]] = i;
+    }
+  }
+  return result;
+}
+
+bool MaximumMatcher::Match(int left, int right) {
+  std::pair<int, int> p(left, right);
+  std::map<std::pair<int, int>, bool>::iterator it =
+      cached_match_results_.find(p);
+  if (it != cached_match_results_.end()) {
+    return it->second;
+  }
+  cached_match_results_[p] = match_callback_(left, right);
+  return cached_match_results_[p];
+}
+
+bool MaximumMatcher::FindArgumentPathDFS(int v, std::vector<bool>* visited) {
+  (*visited)[v] = true;
+  // We try to match those un-matched nodes on the right side first. This is
+  // the step that the naive greedy matching algorithm uses. In the best cases
+  // where the greedy algorithm can find a maximum matching, we will always
+  // find a match in this step and the performance will be identical to the
+  // greedy algorithm.
+  for (int i = 0; i < count2_; ++i) {
+    int matched = (*match_list2_)[i];
+    if (matched == -1 && Match(v, i)) {
+      (*match_list2_)[i] = v;
+      return true;
+    }
+  }
+  // Then we try those already matched nodes and see if we can find an
+  // alternative match for the node matched to them.
+  // The greedy algorithm will stop before this and fail to produce the
+  // correct result.
+  for (int i = 0; i < count2_; ++i) {
+    int matched = (*match_list2_)[i];
+    if (matched != -1 && Match(v, i)) {
+      if (!(*visited)[matched] && FindArgumentPathDFS(matched, visited)) {
+        (*match_list2_)[i] = v;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+bool MessageDifferencer::MatchRepeatedFieldIndices(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* repeated_field,
+    const MapKeyComparator* key_comparator,
+    const std::vector<SpecificField>& parent_fields,
+    std::vector<int>* match_list1, std::vector<int>* match_list2) {
+  const int count1 =
+      message1.GetReflection()->FieldSize(message1, repeated_field);
+  const int count2 =
+      message2.GetReflection()->FieldSize(message2, repeated_field);
+  const bool is_treated_as_smart_set = IsTreatedAsSmartSet(repeated_field);
+
+  match_list1->assign(count1, -1);
+  match_list2->assign(count2, -1);
+  // Ensure that we don't report differences during the matching process. Since
+  // field comparators could potentially use this message differencer object to
+  // perform further comparisons, turn off reporting here and re-enable it
+  // before returning.
+  Reporter* reporter = reporter_;
+  reporter_ = NULL;
+  NumDiffsReporter num_diffs_reporter;
+  std::vector<int32_t> num_diffs_list1;
+  if (is_treated_as_smart_set) {
+    num_diffs_list1.assign(count1, std::numeric_limits<int32_t>::max());
+  }
+
+  bool success = true;
+  // Find potential match if this is a special repeated field.
+  if (scope_ == PARTIAL) {
+    // When partial matching is enabled, Compare(a, b) && Compare(a, c)
+    // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
+    // algorithm will fail to find a maximum matching.
+    // Here we use the augmenting path algorithm.
+    auto callback = [&](int i1, int i2) {
+      return IsMatch(repeated_field, key_comparator, &message1, &message2,
+                     parent_fields, nullptr, i1, i2);
+    };
+    MaximumMatcher matcher(count1, count2, std::move(callback), match_list1,
+                           match_list2);
+    // If diff info is not needed, we should end the matching process as
+    // soon as possible if not all items can be matched.
+    bool early_return = (reporter == nullptr);
+    int match_count = matcher.FindMaximumMatch(early_return);
+    if (match_count != count1 && early_return) return false;
+    success = success && (match_count == count1);
+  } else {
+    int start_offset = 0;
+    // If the two repeated fields are treated as sets, optimize for the case
+    // where both start with same items stored in the same order.
+    if (IsTreatedAsSet(repeated_field) || is_treated_as_smart_set ||
+        IsTreatedAsSmartList(repeated_field)) {
+      start_offset = std::min(count1, count2);
+      for (int i = 0; i < count1 && i < count2; i++) {
+        if (IsMatch(repeated_field, key_comparator, &message1, &message2,
+                    parent_fields, nullptr, i, i)) {
+          match_list1->at(i) = i;
+          match_list2->at(i) = i;
+        } else {
+          start_offset = i;
+          break;
+        }
+      }
+    }
+    for (int i = start_offset; i < count1; ++i) {
+      // Indicates any matched elements for this repeated field.
+      bool match = false;
+      int matched_j = -1;
+
+      for (int j = start_offset; j < count2; j++) {
+        if (match_list2->at(j) != -1) {
+          if (!is_treated_as_smart_set || num_diffs_list1[i] == 0 ||
+              num_diffs_list1[match_list2->at(j)] == 0) {
+            continue;
+          }
+        }
+
+        if (is_treated_as_smart_set) {
+          num_diffs_reporter.Reset();
+          match = IsMatch(repeated_field, key_comparator, &message1, &message2,
+                          parent_fields, &num_diffs_reporter, i, j);
+        } else {
+          match = IsMatch(repeated_field, key_comparator, &message1, &message2,
+                          parent_fields, nullptr, i, j);
+        }
+
+        if (is_treated_as_smart_set) {
+          if (match) {
+            num_diffs_list1[i] = 0;
+          } else if (repeated_field->cpp_type() ==
+                     FieldDescriptor::CPPTYPE_MESSAGE) {
+            // Replace with the one with fewer diffs.
+            const int32_t num_diffs = num_diffs_reporter.GetNumDiffs();
+            if (num_diffs < num_diffs_list1[i]) {
+              // If j has been already matched to some element, ensure the
+              // current num_diffs is smaller.
+              if (match_list2->at(j) == -1 ||
+                  num_diffs < num_diffs_list1[match_list2->at(j)]) {
+                num_diffs_list1[i] = num_diffs;
+                match = true;
+              }
+            }
+          }
+        }
+
+        if (match) {
+          matched_j = j;
+          if (!is_treated_as_smart_set || num_diffs_list1[i] == 0) {
+            break;
+          }
+        }
+      }
+
+      match = (matched_j != -1);
+      if (match) {
+        if (is_treated_as_smart_set && match_list2->at(matched_j) != -1) {
+          // This is to revert the previously matched index in list2.
+          match_list1->at(match_list2->at(matched_j)) = -1;
+          match = false;
+        }
+        match_list1->at(i) = matched_j;
+        match_list2->at(matched_j) = i;
+      }
+      if (!match && reporter == nullptr) return false;
+      success = success && match;
+    }
+  }
+
+  if (IsTreatedAsSmartList(repeated_field)) {
+    match_indices_for_smart_list_callback_(match_list1, match_list2);
+  }
+
+  reporter_ = reporter;
+
+  return success;
+}
+
+FieldComparator::ComparisonResult MessageDifferencer::GetFieldComparisonResult(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* field, int index1, int index2,
+    const FieldContext* field_context) {
+  FieldComparator* comparator = field_comparator_kind_ == kFCBase
+                                    ? field_comparator_.base
+                                    : field_comparator_.default_impl;
+  return comparator->Compare(message1, message2, field, index1, index2,
+                             field_context);
+}
+
+// ===========================================================================
+
+MessageDifferencer::Reporter::Reporter() {}
+MessageDifferencer::Reporter::~Reporter() {}
+
+// ===========================================================================
+
+MessageDifferencer::MapKeyComparator::MapKeyComparator() {}
+MessageDifferencer::MapKeyComparator::~MapKeyComparator() {}
+
+// ===========================================================================
+
+MessageDifferencer::IgnoreCriteria::IgnoreCriteria() {}
+MessageDifferencer::IgnoreCriteria::~IgnoreCriteria() {}
+
+// ===========================================================================
+
+// Note that the printer's delimiter is not used, because if we are given a
+// printer, we don't know its delimiter.
+MessageDifferencer::StreamReporter::StreamReporter(
+    io::ZeroCopyOutputStream* output)
+    : printer_(new io::Printer(output, '$')),
+      delete_printer_(true),
+      report_modified_aggregates_(false),
+      message1_(nullptr),
+      message2_(nullptr) {}
+
+MessageDifferencer::StreamReporter::StreamReporter(io::Printer* printer)
+    : printer_(printer),
+      delete_printer_(false),
+      report_modified_aggregates_(false),
+      message1_(nullptr),
+      message2_(nullptr) {}
+
+MessageDifferencer::StreamReporter::~StreamReporter() {
+  if (delete_printer_) delete printer_;
+}
+
+void MessageDifferencer::StreamReporter::PrintPath(
+    const std::vector<SpecificField>& field_path, bool left_side) {
+  for (size_t i = 0; i < field_path.size(); ++i) {
+    SpecificField specific_field = field_path[i];
+
+    if (specific_field.field != nullptr &&
+        specific_field.field->name() == "value") {
+      // check to see if this the value label of a map value.  If so, skip it
+      // because it isn't meaningful
+      if (i > 0 && field_path[i - 1].field->is_map()) {
+        continue;
+      }
+    }
+    if (i > 0) {
+      printer_->Print(".");
+    }
+    if (specific_field.field != NULL) {
+      if (specific_field.field->is_extension()) {
+        printer_->Print("($name$)", "name", specific_field.field->full_name());
+      } else {
+        printer_->PrintRaw(specific_field.field->name());
+      }
+
+      if (specific_field.field->is_map()) {
+        PrintMapKey(left_side, specific_field);
+        continue;
+      }
+    } else {
+      printer_->PrintRaw(StrCat(specific_field.unknown_field_number));
+    }
+    if (left_side && specific_field.index >= 0) {
+      printer_->Print("[$name$]", "name", StrCat(specific_field.index));
+    }
+    if (!left_side && specific_field.new_index >= 0) {
+      printer_->Print("[$name$]", "name",
+                      StrCat(specific_field.new_index));
+    }
+  }
+}
+
+
+void MessageDifferencer::StreamReporter::PrintValue(
+    const Message& message, const std::vector<SpecificField>& field_path,
+    bool left_side) {
+  const SpecificField& specific_field = field_path.back();
+  const FieldDescriptor* field = specific_field.field;
+  if (field != NULL) {
+    std::string output;
+    int index = left_side ? specific_field.index : specific_field.new_index;
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      const Reflection* reflection = message.GetReflection();
+      const Message& field_message =
+          field->is_repeated()
+              ? reflection->GetRepeatedMessage(message, field, index)
+              : reflection->GetMessage(message, field);
+      const FieldDescriptor* fd = nullptr;
+
+      if (field->is_map() && message1_ != nullptr && message2_ != nullptr) {
+        fd = field_message.GetDescriptor()->field(1);
+        if (fd->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          output = PrintShortTextFormat(
+              field_message.GetReflection()->GetMessage(field_message, fd));
+        } else {
+          TextFormat::PrintFieldValueToString(field_message, fd, -1, &output);
+        }
+      } else {
+        output = PrintShortTextFormat(field_message);
+      }
+      if (output.empty()) {
+        printer_->Print("{ }");
+      } else {
+        if ((fd != nullptr) &&
+            (fd->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE)) {
+          printer_->PrintRaw(output);
+        } else {
+          printer_->Print("{ $name$ }", "name", output);
+        }
+      }
+    } else {
+      TextFormat::PrintFieldValueToString(message, field, index, &output);
+      printer_->PrintRaw(output);
+    }
+  } else {
+    const UnknownFieldSet* unknown_fields =
+        (left_side ? specific_field.unknown_field_set1
+                   : specific_field.unknown_field_set2);
+    const UnknownField* unknown_field =
+        &unknown_fields->field(left_side ? specific_field.unknown_field_index1
+                                         : specific_field.unknown_field_index2);
+    PrintUnknownFieldValue(unknown_field);
+  }
+}
+
+void MessageDifferencer::StreamReporter::PrintUnknownFieldValue(
+    const UnknownField* unknown_field) {
+  GOOGLE_CHECK(unknown_field != NULL) << " Cannot print NULL unknown_field.";
+
+  std::string output;
+  switch (unknown_field->type()) {
+    case UnknownField::TYPE_VARINT:
+      output = StrCat(unknown_field->varint());
+      break;
+    case UnknownField::TYPE_FIXED32:
+      output = StrCat(
+          "0x", strings::Hex(unknown_field->fixed32(), strings::ZERO_PAD_8));
+      break;
+    case UnknownField::TYPE_FIXED64:
+      output = StrCat(
+          "0x", strings::Hex(unknown_field->fixed64(), strings::ZERO_PAD_16));
+      break;
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      output = StringPrintf(
+          "\"%s\"", CEscape(unknown_field->length_delimited()).c_str());
+      break;
+    case UnknownField::TYPE_GROUP:
+      // TODO(kenton):  Print the contents of the group like we do for
+      //   messages.  Requires an equivalent of ShortDebugString() for
+      //   UnknownFieldSet.
+      output = "{ ... }";
+      break;
+  }
+  printer_->PrintRaw(output);
+}
+
+void MessageDifferencer::StreamReporter::Print(const std::string& str) {
+  printer_->Print(str.c_str());
+}
+
+void MessageDifferencer::StreamReporter::PrintMapKey(
+    bool left_side, const SpecificField& specific_field) {
+  if (message1_ == nullptr || message2_ == nullptr) {
+    GOOGLE_LOG(INFO) << "PrintPath cannot log map keys; "
+                 "use SetMessages to provide the messages "
+                 "being compared prior to any processing.";
+    return;
+  }
+
+  const Message* found_message =
+      left_side ? specific_field.map_entry1 : specific_field.map_entry2;
+  std::string key_string = "";
+  if (found_message != nullptr) {
+    // NB: the map key is always the first field
+    const FieldDescriptor* fd = found_message->GetDescriptor()->field(0);
+    if (fd->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      // Not using PrintFieldValueToString for strings to avoid extra
+      // characters
+      key_string = found_message->GetReflection()->GetString(
+          *found_message, found_message->GetDescriptor()->field(0));
+    } else {
+      TextFormat::PrintFieldValueToString(*found_message, fd, -1, &key_string);
+    }
+    if (key_string.empty()) {
+      key_string = "''";
+    }
+    printer_->PrintRaw(StrCat("[", key_string, "]"));
+  }
+}
+
+void MessageDifferencer::StreamReporter::ReportAdded(
+    const Message& /*message1*/, const Message& message2,
+    const std::vector<SpecificField>& field_path) {
+  printer_->Print("added: ");
+  PrintPath(field_path, false);
+  printer_->Print(": ");
+  PrintValue(message2, field_path, false);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportDeleted(
+    const Message& message1, const Message& /*message2*/,
+    const std::vector<SpecificField>& field_path) {
+  printer_->Print("deleted: ");
+  PrintPath(field_path, true);
+  printer_->Print(": ");
+  PrintValue(message1, field_path, true);
+  printer_->Print("\n");  // Print for newlines
+}
+
+void MessageDifferencer::StreamReporter::ReportModified(
+    const Message& message1, const Message& message2,
+    const std::vector<SpecificField>& field_path) {
+  if (!report_modified_aggregates_ && field_path.back().field == NULL) {
+    if (field_path.back().unknown_field_type == UnknownField::TYPE_GROUP) {
+      // Any changes to the subfields have already been printed.
+      return;
+    }
+  } else if (!report_modified_aggregates_) {
+    if (field_path.back().field->cpp_type() ==
+        FieldDescriptor::CPPTYPE_MESSAGE) {
+      // Any changes to the subfields have already been printed.
+      return;
+    }
+  }
+
+  printer_->Print("modified: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print(": ");
+  PrintValue(message1, field_path, true);
+  printer_->Print(" -> ");
+  PrintValue(message2, field_path, false);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportMoved(
+    const Message& message1, const Message& /*message2*/,
+    const std::vector<SpecificField>& field_path) {
+  printer_->Print("moved: ");
+  PrintPath(field_path, true);
+  printer_->Print(" -> ");
+  PrintPath(field_path, false);
+  printer_->Print(" : ");
+  PrintValue(message1, field_path, true);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportMatched(
+    const Message& message1, const Message& /*message2*/,
+    const std::vector<SpecificField>& field_path) {
+  printer_->Print("matched: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print(" : ");
+  PrintValue(message1, field_path, true);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportIgnored(
+    const Message& /*message1*/, const Message& /*message2*/,
+    const std::vector<SpecificField>& field_path) {
+  printer_->Print("ignored: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::SetMessages(const Message& message1,
+                                                     const Message& message2) {
+  message1_ = &message1;
+  message2_ = &message2;
+}
+
+void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
+    const Message& /*message1*/, const Message& /*message2*/,
+    const std::vector<SpecificField>& field_path) {
+  printer_->Print("ignored: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print("\n");  // Print for newlines.
+}
+
+MessageDifferencer::MapKeyComparator*
+MessageDifferencer::CreateMultipleFieldsMapKeyComparator(
+    const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
+  return new MultipleFieldsMapKeyComparator(this, key_field_paths);
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/time_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/time_util.cpp
new file mode 100644
index 0000000..9893aa3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/time_util.cpp
@@ -0,0 +1,514 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/time_util.h>
+
+#include <cstdint>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+#include <google/protobuf/stubs/int128.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/time.h>
+
+// Must go after other includes.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::Duration;
+using google::protobuf::Timestamp;
+
+namespace {
+static const int kNanosPerSecond = 1000000000;
+static const int kMicrosPerSecond = 1000000;
+static const int kMillisPerSecond = 1000;
+static const int kNanosPerMillisecond = 1000000;
+static const int kNanosPerMicrosecond = 1000;
+static const int kSecondsPerMinute = 60;  // Note that we ignore leap seconds.
+static const int kSecondsPerHour = 3600;
+
+template <typename T>
+T CreateNormalized(int64_t seconds, int64_t nanos);
+
+template <>
+Timestamp CreateNormalized(int64_t seconds, int64_t nanos) {
+  // Make sure nanos is in the range.
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    seconds += nanos / kNanosPerSecond;
+    nanos = nanos % kNanosPerSecond;
+  }
+  // For Timestamp nanos should be in the range [0, 999999999]
+  if (nanos < 0) {
+    seconds -= 1;
+    nanos += kNanosPerSecond;
+  }
+  GOOGLE_DCHECK(seconds >= TimeUtil::kTimestampMinSeconds &&
+         seconds <= TimeUtil::kTimestampMaxSeconds);
+  Timestamp result;
+  result.set_seconds(seconds);
+  result.set_nanos(static_cast<int32_t>(nanos));
+  return result;
+}
+
+template <>
+Duration CreateNormalized(int64_t seconds, int64_t nanos) {
+  // Make sure nanos is in the range.
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    seconds += nanos / kNanosPerSecond;
+    nanos = nanos % kNanosPerSecond;
+  }
+  // nanos should have the same sign as seconds.
+  if (seconds < 0 && nanos > 0) {
+    seconds += 1;
+    nanos -= kNanosPerSecond;
+  } else if (seconds > 0 && nanos < 0) {
+    seconds -= 1;
+    nanos += kNanosPerSecond;
+  }
+  GOOGLE_DCHECK(seconds >= TimeUtil::kDurationMinSeconds &&
+         seconds <= TimeUtil::kDurationMaxSeconds);
+  Duration result;
+  result.set_seconds(seconds);
+  result.set_nanos(static_cast<int32_t>(nanos));
+  return result;
+}
+
+// Format nanoseconds with either 3, 6, or 9 digits depending on the required
+// precision to represent the exact value.
+std::string FormatNanos(int32_t nanos) {
+  if (nanos % kNanosPerMillisecond == 0) {
+    return StringPrintf("%03d", nanos / kNanosPerMillisecond);
+  } else if (nanos % kNanosPerMicrosecond == 0) {
+    return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
+  } else {
+    return StringPrintf("%09d", nanos);
+  }
+}
+
+std::string FormatTime(int64_t seconds, int32_t nanos) {
+  return ::google::protobuf::internal::FormatTime(seconds, nanos);
+}
+
+bool ParseTime(const std::string& value, int64_t* seconds, int32_t* nanos) {
+  return ::google::protobuf::internal::ParseTime(value, seconds, nanos);
+}
+
+void CurrentTime(int64_t* seconds, int32_t* nanos) {
+  return ::google::protobuf::internal::GetCurrentTime(seconds, nanos);
+}
+
+// Truncates the remainder part after division.
+int64_t RoundTowardZero(int64_t value, int64_t divider) {
+  int64_t result = value / divider;
+  int64_t remainder = value % divider;
+  // Before C++11, the sign of the remainder is implementation dependent if
+  // any of the operands is negative. Here we try to enforce C++11's "rounded
+  // toward zero" semantics. For example, for (-5) / 2 an implementation may
+  // give -3 as the result with the remainder being 1. This function ensures
+  // we always return -2 (closer to zero) regardless of the implementation.
+  if (result < 0 && remainder > 0) {
+    return result + 1;
+  } else {
+    return result;
+  }
+}
+}  // namespace
+
+// Actually define these static const integers. Required by C++ standard (but
+// some compilers don't like it).
+#ifndef _MSC_VER
+const int64_t TimeUtil::kTimestampMinSeconds;
+const int64_t TimeUtil::kTimestampMaxSeconds;
+const int64_t TimeUtil::kDurationMaxSeconds;
+const int64_t TimeUtil::kDurationMinSeconds;
+#endif  // !_MSC_VER
+
+std::string TimeUtil::ToString(const Timestamp& timestamp) {
+  return FormatTime(timestamp.seconds(), timestamp.nanos());
+}
+
+bool TimeUtil::FromString(const std::string& value, Timestamp* timestamp) {
+  int64_t seconds;
+  int32_t nanos;
+  if (!ParseTime(value, &seconds, &nanos)) {
+    return false;
+  }
+  *timestamp = CreateNormalized<Timestamp>(seconds, nanos);
+  return true;
+}
+
+Timestamp TimeUtil::GetCurrentTime() {
+  int64_t seconds;
+  int32_t nanos;
+  CurrentTime(&seconds, &nanos);
+  return CreateNormalized<Timestamp>(seconds, nanos);
+}
+
+Timestamp TimeUtil::GetEpoch() { return Timestamp(); }
+
+std::string TimeUtil::ToString(const Duration& duration) {
+  std::string result;
+  int64_t seconds = duration.seconds();
+  int32_t nanos = duration.nanos();
+  if (seconds < 0 || nanos < 0) {
+    result += "-";
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  result += StrCat(seconds);
+  if (nanos != 0) {
+    result += "." + FormatNanos(nanos);
+  }
+  result += "s";
+  return result;
+}
+
+static int64_t Pow(int64_t x, int y) {
+  int64_t result = 1;
+  for (int i = 0; i < y; ++i) {
+    result *= x;
+  }
+  return result;
+}
+
+bool TimeUtil::FromString(const std::string& value, Duration* duration) {
+  if (value.length() <= 1 || value[value.length() - 1] != 's') {
+    return false;
+  }
+  bool negative = (value[0] == '-');
+  size_t sign_length = (negative ? 1 : 0);
+  // Parse the duration value as two integers rather than a float value
+  // to avoid precision loss.
+  std::string seconds_part, nanos_part;
+  size_t pos = value.find_last_of('.');
+  if (pos == std::string::npos) {
+    seconds_part = value.substr(sign_length, value.length() - 1 - sign_length);
+    nanos_part = "0";
+  } else {
+    seconds_part = value.substr(sign_length, pos - sign_length);
+    nanos_part = value.substr(pos + 1, value.length() - pos - 2);
+  }
+  char* end;
+  int64_t seconds = strto64(seconds_part.c_str(), &end, 10);
+  if (end != seconds_part.c_str() + seconds_part.length()) {
+    return false;
+  }
+  int64_t nanos = strto64(nanos_part.c_str(), &end, 10);
+  if (end != nanos_part.c_str() + nanos_part.length()) {
+    return false;
+  }
+  nanos = nanos * Pow(10, static_cast<int>(9 - nanos_part.length()));
+  if (negative) {
+    // If a Duration is negative, both seconds and nanos should be negative.
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  duration->set_seconds(seconds);
+  duration->set_nanos(static_cast<int32_t>(nanos));
+  return true;
+}
+
+Duration TimeUtil::NanosecondsToDuration(int64_t nanos) {
+  return CreateNormalized<Duration>(nanos / kNanosPerSecond,
+                                    nanos % kNanosPerSecond);
+}
+
+Duration TimeUtil::MicrosecondsToDuration(int64_t micros) {
+  return CreateNormalized<Duration>(
+      micros / kMicrosPerSecond,
+      (micros % kMicrosPerSecond) * kNanosPerMicrosecond);
+}
+
+Duration TimeUtil::MillisecondsToDuration(int64_t millis) {
+  return CreateNormalized<Duration>(
+      millis / kMillisPerSecond,
+      (millis % kMillisPerSecond) * kNanosPerMillisecond);
+}
+
+Duration TimeUtil::SecondsToDuration(int64_t seconds) {
+  return CreateNormalized<Duration>(seconds, 0);
+}
+
+Duration TimeUtil::MinutesToDuration(int64_t minutes) {
+  return CreateNormalized<Duration>(minutes * kSecondsPerMinute, 0);
+}
+
+Duration TimeUtil::HoursToDuration(int64_t hours) {
+  return CreateNormalized<Duration>(hours * kSecondsPerHour, 0);
+}
+
+int64_t TimeUtil::DurationToNanoseconds(const Duration& duration) {
+  return duration.seconds() * kNanosPerSecond + duration.nanos();
+}
+
+int64_t TimeUtil::DurationToMicroseconds(const Duration& duration) {
+  return duration.seconds() * kMicrosPerSecond +
+         RoundTowardZero(duration.nanos(), kNanosPerMicrosecond);
+}
+
+int64_t TimeUtil::DurationToMilliseconds(const Duration& duration) {
+  return duration.seconds() * kMillisPerSecond +
+         RoundTowardZero(duration.nanos(), kNanosPerMillisecond);
+}
+
+int64_t TimeUtil::DurationToSeconds(const Duration& duration) {
+  return duration.seconds();
+}
+
+int64_t TimeUtil::DurationToMinutes(const Duration& duration) {
+  return RoundTowardZero(duration.seconds(), kSecondsPerMinute);
+}
+
+int64_t TimeUtil::DurationToHours(const Duration& duration) {
+  return RoundTowardZero(duration.seconds(), kSecondsPerHour);
+}
+
+Timestamp TimeUtil::NanosecondsToTimestamp(int64_t nanos) {
+  return CreateNormalized<Timestamp>(nanos / kNanosPerSecond,
+                                     nanos % kNanosPerSecond);
+}
+
+Timestamp TimeUtil::MicrosecondsToTimestamp(int64_t micros) {
+  return CreateNormalized<Timestamp>(
+      micros / kMicrosPerSecond,
+      micros % kMicrosPerSecond * kNanosPerMicrosecond);
+}
+
+Timestamp TimeUtil::MillisecondsToTimestamp(int64_t millis) {
+  return CreateNormalized<Timestamp>(
+      millis / kMillisPerSecond,
+      millis % kMillisPerSecond * kNanosPerMillisecond);
+}
+
+Timestamp TimeUtil::SecondsToTimestamp(int64_t seconds) {
+  return CreateNormalized<Timestamp>(seconds, 0);
+}
+
+int64_t TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kNanosPerSecond + timestamp.nanos();
+}
+
+int64_t TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kMicrosPerSecond +
+         RoundTowardZero(timestamp.nanos(), kNanosPerMicrosecond);
+}
+
+int64_t TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kMillisPerSecond +
+         RoundTowardZero(timestamp.nanos(), kNanosPerMillisecond);
+}
+
+int64_t TimeUtil::TimestampToSeconds(const Timestamp& timestamp) {
+  return timestamp.seconds();
+}
+
+Timestamp TimeUtil::TimeTToTimestamp(time_t value) {
+  return CreateNormalized<Timestamp>(static_cast<int64_t>(value), 0);
+}
+
+time_t TimeUtil::TimestampToTimeT(const Timestamp& value) {
+  return static_cast<time_t>(value.seconds());
+}
+
+Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) {
+  return CreateNormalized<Timestamp>(value.tv_sec,
+                                     value.tv_usec * kNanosPerMicrosecond);
+}
+
+timeval TimeUtil::TimestampToTimeval(const Timestamp& value) {
+  timeval result;
+  result.tv_sec = value.seconds();
+  result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
+  return result;
+}
+
+Duration TimeUtil::TimevalToDuration(const timeval& value) {
+  return CreateNormalized<Duration>(value.tv_sec,
+                                    value.tv_usec * kNanosPerMicrosecond);
+}
+
+timeval TimeUtil::DurationToTimeval(const Duration& value) {
+  timeval result;
+  result.tv_sec = value.seconds();
+  result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
+  // timeval.tv_usec's range is [0, 1000000)
+  if (result.tv_usec < 0) {
+    result.tv_sec -= 1;
+    result.tv_usec += kMicrosPerSecond;
+  }
+  return result;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+namespace google {
+namespace protobuf {
+namespace {
+using ::PROTOBUF_NAMESPACE_ID::util::CreateNormalized;
+using ::PROTOBUF_NAMESPACE_ID::util::kNanosPerSecond;
+
+// Convert a Duration to uint128.
+void ToUint128(const Duration& value, uint128* result, bool* negative) {
+  if (value.seconds() < 0 || value.nanos() < 0) {
+    *negative = true;
+    *result = static_cast<uint64_t>(-value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32_t>(-value.nanos());
+  } else {
+    *negative = false;
+    *result = static_cast<uint64_t>(value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32_t>(value.nanos());
+  }
+}
+
+void ToDuration(const uint128& value, bool negative, Duration* duration) {
+  int64_t seconds =
+      static_cast<int64_t>(Uint128Low64(value / kNanosPerSecond));
+  int32_t nanos =
+      static_cast<int32_t>(Uint128Low64(value % kNanosPerSecond));
+  if (negative) {
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  duration->set_seconds(seconds);
+  duration->set_nanos(nanos);
+}
+}  // namespace
+
+Duration& operator+=(Duration& d1, const Duration& d2) {
+  d1 = CreateNormalized<Duration>(d1.seconds() + d2.seconds(),
+                                  d1.nanos() + d2.nanos());
+  return d1;
+}
+
+Duration& operator-=(Duration& d1, const Duration& d2) {  // NOLINT
+  d1 = CreateNormalized<Duration>(d1.seconds() - d2.seconds(),
+                                  d1.nanos() - d2.nanos());
+  return d1;
+}
+
+Duration& operator*=(Duration& d, int64_t r) {  // NOLINT
+  bool negative;
+  uint128 value;
+  ToUint128(d, &value, &negative);
+  if (r > 0) {
+    value *= static_cast<uint64_t>(r);
+  } else {
+    negative = !negative;
+    value *= static_cast<uint64_t>(-r);
+  }
+  ToDuration(value, negative, &d);
+  return d;
+}
+
+Duration& operator*=(Duration& d, double r) {  // NOLINT
+  double result =
+      (static_cast<double>(d.seconds()) + d.nanos() * (1.0 / kNanosPerSecond)) *
+      r;
+  int64_t seconds = static_cast<int64_t>(result);
+  int32_t nanos = static_cast<int32_t>((result - static_cast<double>(seconds)) *
+                                       kNanosPerSecond);
+  // Note that we normalize here not just because nanos can have a different
+  // sign from seconds but also that nanos can be any arbitrary value when
+  // overflow happens (i.e., the result is a much larger value than what
+  // int64 can represent).
+  d = CreateNormalized<Duration>(seconds, nanos);
+  return d;
+}
+
+Duration& operator/=(Duration& d, int64_t r) {  // NOLINT
+  bool negative;
+  uint128 value;
+  ToUint128(d, &value, &negative);
+  if (r > 0) {
+    value /= static_cast<uint64_t>(r);
+  } else {
+    negative = !negative;
+    value /= static_cast<uint64_t>(-r);
+  }
+  ToDuration(value, negative, &d);
+  return d;
+}
+
+Duration& operator/=(Duration& d, double r) {  // NOLINT
+  return d *= 1.0 / r;
+}
+
+Duration& operator%=(Duration& d1, const Duration& d2) {  // NOLINT
+  bool negative1, negative2;
+  uint128 value1, value2;
+  ToUint128(d1, &value1, &negative1);
+  ToUint128(d2, &value2, &negative2);
+  uint128 result = value1 % value2;
+  // When negative values are involved in division, we round the division
+  // result towards zero. With this semantics, sign of the remainder is the
+  // same as the dividend. For example:
+  //     -5 / 10    = 0, -5 % 10    = -5
+  //     -5 / (-10) = 0, -5 % (-10) = -5
+  //      5 / (-10) = 0,  5 % (-10) = 5
+  ToDuration(result, negative1, &d1);
+  return d1;
+}
+
+int64_t operator/(const Duration& d1, const Duration& d2) {
+  bool negative1, negative2;
+  uint128 value1, value2;
+  ToUint128(d1, &value1, &negative1);
+  ToUint128(d2, &value2, &negative2);
+  int64_t result = Uint128Low64(value1 / value2);
+  if (negative1 != negative2) {
+    result = -result;
+  }
+  return result;
+}
+
+Timestamp& operator+=(Timestamp& t, const Duration& d) {  // NOLINT
+  t = CreateNormalized<Timestamp>(t.seconds() + d.seconds(),
+                                  t.nanos() + d.nanos());
+  return t;
+}
+
+Timestamp& operator-=(Timestamp& t, const Duration& d) {  // NOLINT
+  t = CreateNormalized<Timestamp>(t.seconds() - d.seconds(),
+                                  t.nanos() - d.nanos());
+  return t;
+}
+
+Duration operator-(const Timestamp& t1, const Timestamp& t2) {
+  return CreateNormalized<Duration>(t1.seconds() - t2.seconds(),
+                                    t1.nanos() - t2.nanos());
+}
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/util/type_resolver_util.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/util/type_resolver_util.cpp
new file mode 100644
index 0000000..8be0efb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/util/type_resolver_util.cpp
@@ -0,0 +1,370 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/util/type_resolver_util.h>
+
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/status.h>
+
+// clang-format off
+#include <google/protobuf/port_def.inc>
+// clang-format on
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+using google::protobuf::Any;
+using google::protobuf::BoolValue;
+using google::protobuf::BytesValue;
+using google::protobuf::DoubleValue;
+using google::protobuf::Enum;
+using google::protobuf::EnumValue;
+using google::protobuf::Field;
+using google::protobuf::FloatValue;
+using google::protobuf::Int32Value;
+using google::protobuf::Int64Value;
+using google::protobuf::Option;
+using google::protobuf::StringValue;
+using google::protobuf::Type;
+using google::protobuf::UInt32Value;
+using google::protobuf::UInt64Value;
+
+class DescriptorPoolTypeResolver : public TypeResolver {
+ public:
+  DescriptorPoolTypeResolver(const std::string& url_prefix,
+                             const DescriptorPool* pool)
+      : url_prefix_(url_prefix), pool_(pool) {}
+
+  util::Status ResolveMessageType(const std::string& type_url,
+                                  Type* type) override {
+    std::string type_name;
+    util::Status status = ParseTypeUrl(type_url, &type_name);
+    if (!status.ok()) {
+      return status;
+    }
+
+    const Descriptor* descriptor = pool_->FindMessageTypeByName(type_name);
+    if (descriptor == NULL) {
+      return util::NotFoundError("Invalid type URL, unknown type: " +
+                                 type_name);
+    }
+    ConvertDescriptor(descriptor, type);
+    return util::Status();
+  }
+
+  util::Status ResolveEnumType(const std::string& type_url,
+                               Enum* enum_type) override {
+    std::string type_name;
+    util::Status status = ParseTypeUrl(type_url, &type_name);
+    if (!status.ok()) {
+      return status;
+    }
+
+    const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
+    if (descriptor == NULL) {
+      return util::InvalidArgumentError("Invalid type URL, unknown type: " +
+                                        type_name);
+    }
+    ConvertEnumDescriptor(descriptor, enum_type);
+    return util::Status();
+  }
+
+ private:
+  void ConvertDescriptor(const Descriptor* descriptor, Type* type) {
+    type->Clear();
+    type->set_name(descriptor->full_name());
+    for (int i = 0; i < descriptor->field_count(); ++i) {
+      ConvertFieldDescriptor(descriptor->field(i), type->add_fields());
+    }
+    for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
+      type->add_oneofs(descriptor->oneof_decl(i)->name());
+    }
+    type->mutable_source_context()->set_file_name(descriptor->file()->name());
+    ConvertMessageOptions(descriptor->options(), type->mutable_options());
+  }
+
+  void ConvertMessageOptions(const MessageOptions& options,
+                             RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  void ConvertFieldOptions(const FieldOptions& options,
+                           RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  void ConvertEnumOptions(const EnumOptions& options,
+                          RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  void ConvertEnumValueOptions(const EnumValueOptions& options,
+                               RepeatedPtrField<Option>* output) {
+    return ConvertOptionsInternal(options, output);
+  }
+
+  // Implementation details for Convert*Options.
+  void ConvertOptionsInternal(const Message& options,
+                              RepeatedPtrField<Option>* output) {
+    const Reflection* reflection = options.GetReflection();
+    std::vector<const FieldDescriptor*> fields;
+    reflection->ListFields(options, &fields);
+    for (const FieldDescriptor* field : fields) {
+      if (field->is_repeated()) {
+        const int size = reflection->FieldSize(options, field);
+        for (int i = 0; i < size; i++) {
+          ConvertOptionField(reflection, options, field, i, output->Add());
+        }
+      } else {
+        ConvertOptionField(reflection, options, field, -1, output->Add());
+      }
+    }
+  }
+
+  static void ConvertOptionField(const Reflection* reflection,
+                                 const Message& options,
+                                 const FieldDescriptor* field, int index,
+                                 Option* out) {
+    out->set_name(field->is_extension() ? field->full_name() : field->name());
+    Any* value = out->mutable_value();
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        value->PackFrom(
+            field->is_repeated()
+                ? reflection->GetRepeatedMessage(options, field, index)
+                : reflection->GetMessage(options, field));
+        return;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        value->PackFrom(WrapValue<DoubleValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedDouble(options, field, index)
+                : reflection->GetDouble(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        value->PackFrom(WrapValue<FloatValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedFloat(options, field, index)
+                : reflection->GetFloat(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_INT64:
+        value->PackFrom(WrapValue<Int64Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedInt64(options, field, index)
+                : reflection->GetInt64(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        value->PackFrom(WrapValue<UInt64Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedUInt64(options, field, index)
+                : reflection->GetUInt64(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_INT32:
+        value->PackFrom(WrapValue<Int32Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedInt32(options, field, index)
+                : reflection->GetInt32(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        value->PackFrom(WrapValue<UInt32Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedUInt32(options, field, index)
+                : reflection->GetUInt32(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        value->PackFrom(WrapValue<BoolValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedBool(options, field, index)
+                : reflection->GetBool(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_STRING: {
+        const std::string& val =
+            field->is_repeated()
+                ? reflection->GetRepeatedString(options, field, index)
+                : reflection->GetString(options, field);
+        if (field->type() == FieldDescriptor::TYPE_STRING) {
+          value->PackFrom(WrapValue<StringValue>(val));
+        } else {
+          value->PackFrom(WrapValue<BytesValue>(val));
+        }
+        return;
+      }
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        const EnumValueDescriptor* val =
+            field->is_repeated()
+                ? reflection->GetRepeatedEnum(options, field, index)
+                : reflection->GetEnum(options, field);
+        value->PackFrom(WrapValue<Int32Value>(val->number()));
+        return;
+      }
+    }
+  }
+
+  template <typename WrapperT, typename T>
+  static WrapperT WrapValue(T value) {
+    WrapperT wrapper;
+    wrapper.set_value(value);
+    return wrapper;
+  }
+
+  void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) {
+    field->set_kind(static_cast<Field::Kind>(descriptor->type()));
+    switch (descriptor->label()) {
+      case FieldDescriptor::LABEL_OPTIONAL:
+        field->set_cardinality(Field::CARDINALITY_OPTIONAL);
+        break;
+      case FieldDescriptor::LABEL_REPEATED:
+        field->set_cardinality(Field::CARDINALITY_REPEATED);
+        break;
+      case FieldDescriptor::LABEL_REQUIRED:
+        field->set_cardinality(Field::CARDINALITY_REQUIRED);
+        break;
+    }
+    field->set_number(descriptor->number());
+    field->set_name(descriptor->name());
+    field->set_json_name(descriptor->json_name());
+    if (descriptor->has_default_value()) {
+      field->set_default_value(DefaultValueAsString(descriptor));
+    }
+    if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE ||
+        descriptor->type() == FieldDescriptor::TYPE_GROUP) {
+      field->set_type_url(GetTypeUrl(descriptor->message_type()));
+    } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
+      field->set_type_url(GetTypeUrl(descriptor->enum_type()));
+    }
+    if (descriptor->containing_oneof() != NULL) {
+      field->set_oneof_index(descriptor->containing_oneof()->index() + 1);
+    }
+    if (descriptor->is_packed()) {
+      field->set_packed(true);
+    }
+
+    ConvertFieldOptions(descriptor->options(), field->mutable_options());
+  }
+
+  void ConvertEnumDescriptor(const EnumDescriptor* descriptor,
+                             Enum* enum_type) {
+    enum_type->Clear();
+    enum_type->set_name(descriptor->full_name());
+    enum_type->mutable_source_context()->set_file_name(
+        descriptor->file()->name());
+    for (int i = 0; i < descriptor->value_count(); ++i) {
+      const EnumValueDescriptor* value_descriptor = descriptor->value(i);
+      EnumValue* value = enum_type->mutable_enumvalue()->Add();
+      value->set_name(value_descriptor->name());
+      value->set_number(value_descriptor->number());
+
+      ConvertEnumValueOptions(value_descriptor->options(),
+                              value->mutable_options());
+    }
+
+    ConvertEnumOptions(descriptor->options(), enum_type->mutable_options());
+  }
+
+  std::string GetTypeUrl(const Descriptor* descriptor) {
+    return url_prefix_ + "/" + descriptor->full_name();
+  }
+
+  std::string GetTypeUrl(const EnumDescriptor* descriptor) {
+    return url_prefix_ + "/" + descriptor->full_name();
+  }
+
+  util::Status ParseTypeUrl(const std::string& type_url,
+                            std::string* type_name) {
+    if (type_url.substr(0, url_prefix_.size() + 1) != url_prefix_ + "/") {
+      return util::InvalidArgumentError(
+          StrCat("Invalid type URL, type URLs must be of the form '",
+                       url_prefix_, "/<typename>', got: ", type_url));
+    }
+    *type_name = type_url.substr(url_prefix_.size() + 1);
+    return util::Status();
+  }
+
+  std::string DefaultValueAsString(const FieldDescriptor* descriptor) {
+    switch (descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        return StrCat(descriptor->default_value_int32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return StrCat(descriptor->default_value_int64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return StrCat(descriptor->default_value_uint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return StrCat(descriptor->default_value_uint64());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        return SimpleFtoa(descriptor->default_value_float());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        return SimpleDtoa(descriptor->default_value_double());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return descriptor->default_value_bool() ? "true" : "false";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+          return CEscape(descriptor->default_value_string());
+        } else {
+          return descriptor->default_value_string();
+        }
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return descriptor->default_value_enum()->name();
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
+        break;
+    }
+    return "";
+  }
+
+  std::string url_prefix_;
+  const DescriptorPool* pool_;
+};
+
+}  // namespace
+
+TypeResolver* NewTypeResolverForDescriptorPool(const std::string& url_prefix,
+                                               const DescriptorPool* pool) {
+  return new DescriptorPoolTypeResolver(url_prefix, pool);
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/wire_format.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/wire_format.cpp
new file mode 100644
index 0000000..6fe63c8
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/wire_format.cpp
@@ -0,0 +1,1768 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/wire_format.h>
+
+#include <stack>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+const size_t kMapEntryTagByteSize = 2;
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Forward declare static functions
+static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field,
+                                          const MapValueConstRef& value);
+
+// ===================================================================
+
+bool UnknownFieldSetFieldSkipper::SkipField(io::CodedInputStream* input,
+                                            uint32_t tag) {
+  return WireFormat::SkipField(input, tag, unknown_fields_);
+}
+
+bool UnknownFieldSetFieldSkipper::SkipMessage(io::CodedInputStream* input) {
+  return WireFormat::SkipMessage(input, unknown_fields_);
+}
+
+void UnknownFieldSetFieldSkipper::SkipUnknownEnum(int field_number, int value) {
+  unknown_fields_->AddVarint(field_number, value);
+}
+
+bool WireFormat::SkipField(io::CodedInputStream* input, uint32_t tag,
+                           UnknownFieldSet* unknown_fields) {
+  int number = WireFormatLite::GetTagFieldNumber(tag);
+  // Field number 0 is illegal.
+  if (number == 0) return false;
+
+  switch (WireFormatLite::GetTagWireType(tag)) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      uint64_t value;
+      if (!input->ReadVarint64(&value)) return false;
+      if (unknown_fields != nullptr) unknown_fields->AddVarint(number, value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      uint64_t value;
+      if (!input->ReadLittleEndian64(&value)) return false;
+      if (unknown_fields != nullptr) unknown_fields->AddFixed64(number, value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      uint32_t length;
+      if (!input->ReadVarint32(&length)) return false;
+      if (unknown_fields == nullptr) {
+        if (!input->Skip(length)) return false;
+      } else {
+        if (!input->ReadString(unknown_fields->AddLengthDelimited(number),
+                               length)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      if (!input->IncrementRecursionDepth()) return false;
+      if (!SkipMessage(input, (unknown_fields == nullptr)
+                                  ? nullptr
+                                  : unknown_fields->AddGroup(number))) {
+        return false;
+      }
+      input->DecrementRecursionDepth();
+      // Check that the ending tag matched the starting tag.
+      if (!input->LastTagWas(
+              WireFormatLite::MakeTag(WireFormatLite::GetTagFieldNumber(tag),
+                                      WireFormatLite::WIRETYPE_END_GROUP))) {
+        return false;
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      return false;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32: {
+      uint32_t value;
+      if (!input->ReadLittleEndian32(&value)) return false;
+      if (unknown_fields != nullptr) unknown_fields->AddFixed32(number, value);
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
+bool WireFormat::SkipMessage(io::CodedInputStream* input,
+                             UnknownFieldSet* unknown_fields) {
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+    if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+      // Must be the end of the message.
+      return true;
+    }
+
+    if (!SkipField(input, tag, unknown_fields)) return false;
+  }
+}
+
+bool WireFormat::ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+                                                uint32_t field_number,
+                                                bool (*is_valid)(int),
+                                                UnknownFieldSet* unknown_fields,
+                                                RepeatedField<int>* values) {
+  uint32_t length;
+  if (!input->ReadVarint32(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    int value;
+    if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+            input, &value)) {
+      return false;
+    }
+    if (is_valid == nullptr || is_valid(value)) {
+      values->Add(value);
+    } else {
+      unknown_fields->AddVarint(field_number, value);
+    }
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+uint8_t* WireFormat::InternalSerializeUnknownFieldsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    target = stream->EnsureSpace(target);
+    switch (field.type()) {
+      case UnknownField::TYPE_VARINT:
+        target = WireFormatLite::WriteUInt64ToArray(field.number(),
+                                                    field.varint(), target);
+        break;
+      case UnknownField::TYPE_FIXED32:
+        target = WireFormatLite::WriteFixed32ToArray(field.number(),
+                                                     field.fixed32(), target);
+        break;
+      case UnknownField::TYPE_FIXED64:
+        target = WireFormatLite::WriteFixed64ToArray(field.number(),
+                                                     field.fixed64(), target);
+        break;
+      case UnknownField::TYPE_LENGTH_DELIMITED:
+        target = stream->WriteString(field.number(), field.length_delimited(),
+                                     target);
+        break;
+      case UnknownField::TYPE_GROUP:
+        target = WireFormatLite::WriteTagToArray(
+            field.number(), WireFormatLite::WIRETYPE_START_GROUP, target);
+        target = InternalSerializeUnknownFieldsToArray(field.group(), target,
+                                                       stream);
+        target = stream->EnsureSpace(target);
+        target = WireFormatLite::WriteTagToArray(
+            field.number(), WireFormatLite::WIRETYPE_END_GROUP, target);
+        break;
+    }
+  }
+  return target;
+}
+
+uint8_t* WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    // The only unknown fields that are allowed to exist in a MessageSet are
+    // messages, which are length-delimited.
+    if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+      target = stream->EnsureSpace(target);
+      // Start group.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetItemStartTag, target);
+
+      // Write type ID.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetTypeIdTag, target);
+      target =
+          io::CodedOutputStream::WriteVarint32ToArray(field.number(), target);
+
+      // Write message.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetMessageTag, target);
+
+      target = field.InternalSerializeLengthDelimitedNoTag(target, stream);
+
+      target = stream->EnsureSpace(target);
+      // End group.
+      target = io::CodedOutputStream::WriteTagToArray(
+          WireFormatLite::kMessageSetItemEndTag, target);
+    }
+  }
+
+  return target;
+}
+
+size_t WireFormat::ComputeUnknownFieldsSize(
+    const UnknownFieldSet& unknown_fields) {
+  size_t size = 0;
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    switch (field.type()) {
+      case UnknownField::TYPE_VARINT:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_VARINT));
+        size += io::CodedOutputStream::VarintSize64(field.varint());
+        break;
+      case UnknownField::TYPE_FIXED32:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_FIXED32));
+        size += sizeof(int32_t);
+        break;
+      case UnknownField::TYPE_FIXED64:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_FIXED64));
+        size += sizeof(int64_t);
+        break;
+      case UnknownField::TYPE_LENGTH_DELIMITED:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+        size += io::CodedOutputStream::VarintSize32(
+            field.length_delimited().size());
+        size += field.length_delimited().size();
+        break;
+      case UnknownField::TYPE_GROUP:
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_START_GROUP));
+        size += ComputeUnknownFieldsSize(field.group());
+        size += io::CodedOutputStream::VarintSize32(WireFormatLite::MakeTag(
+            field.number(), WireFormatLite::WIRETYPE_END_GROUP));
+        break;
+    }
+  }
+
+  return size;
+}
+
+size_t WireFormat::ComputeUnknownMessageSetItemsSize(
+    const UnknownFieldSet& unknown_fields) {
+  size_t size = 0;
+  for (int i = 0; i < unknown_fields.field_count(); i++) {
+    const UnknownField& field = unknown_fields.field(i);
+
+    // The only unknown fields that are allowed to exist in a MessageSet are
+    // messages, which are length-delimited.
+    if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+      size += WireFormatLite::kMessageSetItemTagsSize;
+      size += io::CodedOutputStream::VarintSize32(field.number());
+
+      int field_size = field.GetLengthDelimitedSize();
+      size += io::CodedOutputStream::VarintSize32(field_size);
+      size += field_size;
+    }
+  }
+
+  return size;
+}
+
+// ===================================================================
+
+bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input,
+                                      Message* message) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  const Reflection* message_reflection = message->GetReflection();
+
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    if (WireFormatLite::GetTagWireType(tag) ==
+        WireFormatLite::WIRETYPE_END_GROUP) {
+      // Must be the end of the message.
+      return true;
+    }
+
+    const FieldDescriptor* field = nullptr;
+
+    if (descriptor != nullptr) {
+      int field_number = WireFormatLite::GetTagFieldNumber(tag);
+      field = descriptor->FindFieldByNumber(field_number);
+
+      // If that failed, check if the field is an extension.
+      if (field == nullptr && descriptor->IsExtensionNumber(field_number)) {
+        if (input->GetExtensionPool() == nullptr) {
+          field = message_reflection->FindKnownExtensionByNumber(field_number);
+        } else {
+          field = input->GetExtensionPool()->FindExtensionByNumber(
+              descriptor, field_number);
+        }
+      }
+
+      // If that failed, but we're a MessageSet, and this is the tag for a
+      // MessageSet item, then parse that.
+      if (field == nullptr && descriptor->options().message_set_wire_format() &&
+          tag == WireFormatLite::kMessageSetItemStartTag) {
+        if (!ParseAndMergeMessageSetItem(input, message)) {
+          return false;
+        }
+        continue;  // Skip ParseAndMergeField(); already taken care of.
+      }
+    }
+
+    if (!ParseAndMergeField(tag, field, message, input)) {
+      return false;
+    }
+  }
+}
+
+bool WireFormat::SkipMessageSetField(io::CodedInputStream* input,
+                                     uint32_t field_number,
+                                     UnknownFieldSet* unknown_fields) {
+  uint32_t length;
+  if (!input->ReadVarint32(&length)) return false;
+  return input->ReadString(unknown_fields->AddLengthDelimited(field_number),
+                           length);
+}
+
+bool WireFormat::ParseAndMergeMessageSetField(uint32_t field_number,
+                                              const FieldDescriptor* field,
+                                              Message* message,
+                                              io::CodedInputStream* input) {
+  const Reflection* message_reflection = message->GetReflection();
+  if (field == nullptr) {
+    // We store unknown MessageSet extensions as groups.
+    return SkipMessageSetField(
+        input, field_number, message_reflection->MutableUnknownFields(message));
+  } else if (field->is_repeated() ||
+             field->type() != FieldDescriptor::TYPE_MESSAGE) {
+    // This shouldn't happen as we only allow optional message extensions to
+    // MessageSet.
+    GOOGLE_LOG(ERROR) << "Extensions of MessageSets must be optional messages.";
+    return false;
+  } else {
+    Message* sub_message = message_reflection->MutableMessage(
+        message, field, input->GetExtensionFactory());
+    return WireFormatLite::ReadMessage(input, sub_message);
+  }
+}
+
+static bool StrictUtf8Check(const FieldDescriptor* field) {
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+bool WireFormat::ParseAndMergeField(
+    uint32_t tag,
+    const FieldDescriptor* field,  // May be nullptr for unknown
+    Message* message, io::CodedInputStream* input) {
+  const Reflection* message_reflection = message->GetReflection();
+
+  enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format;
+
+  if (field == nullptr) {
+    value_format = UNKNOWN;
+  } else if (WireFormatLite::GetTagWireType(tag) ==
+             WireTypeForFieldType(field->type())) {
+    value_format = NORMAL_FORMAT;
+  } else if (field->is_packable() &&
+             WireFormatLite::GetTagWireType(tag) ==
+                 WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    value_format = PACKED_FORMAT;
+  } else {
+    // We don't recognize this field. Either the field number is unknown
+    // or the wire type doesn't match. Put it in our unknown field set.
+    value_format = UNKNOWN;
+  }
+
+  if (value_format == UNKNOWN) {
+    return SkipField(input, tag,
+                     message_reflection->MutableUnknownFields(message));
+  } else if (value_format == PACKED_FORMAT) {
+    uint32_t length;
+    if (!input->ReadVarint32(&length)) return false;
+    io::CodedInputStream::Limit limit = input->PushLimit(length);
+
+    switch (field->type()) {
+#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                      \
+  case FieldDescriptor::TYPE_##TYPE: {                                         \
+    while (input->BytesUntilLimit() > 0) {                                     \
+      CPPTYPE value;                                                           \
+      if (!WireFormatLite::ReadPrimitive<CPPTYPE,                              \
+                                         WireFormatLite::TYPE_##TYPE>(input,   \
+                                                                      &value)) \
+        return false;                                                          \
+      message_reflection->Add##CPPTYPE_METHOD(message, field, value);          \
+    }                                                                          \
+    break;                                                                     \
+  }
+
+      HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+      HANDLE_PACKED_TYPE(SINT32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(SINT64, int64_t, Int64)
+      HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+      HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
+
+      HANDLE_PACKED_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_PACKED_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_PACKED_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_PACKED_TYPE(SFIXED64, int64_t, Int64)
+
+      HANDLE_PACKED_TYPE(FLOAT, float, Float)
+      HANDLE_PACKED_TYPE(DOUBLE, double, Double)
+
+      HANDLE_PACKED_TYPE(BOOL, bool, Bool)
+#undef HANDLE_PACKED_TYPE
+
+      case FieldDescriptor::TYPE_ENUM: {
+        while (input->BytesUntilLimit() > 0) {
+          int value;
+          if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+                  input, &value))
+            return false;
+          if (message->GetDescriptor()->file()->syntax() ==
+              FileDescriptor::SYNTAX_PROTO3) {
+            message_reflection->AddEnumValue(message, field, value);
+          } else {
+            const EnumValueDescriptor* enum_value =
+                field->enum_type()->FindValueByNumber(value);
+            if (enum_value != nullptr) {
+              message_reflection->AddEnum(message, field, enum_value);
+            } else {
+              // The enum value is not one of the known values.  Add it to the
+              // UnknownFieldSet.
+              int64_t sign_extended_value = static_cast<int64_t>(value);
+              message_reflection->MutableUnknownFields(message)->AddVarint(
+                  WireFormatLite::GetTagFieldNumber(tag), sign_extended_value);
+            }
+          }
+        }
+
+        break;
+      }
+
+      case FieldDescriptor::TYPE_STRING:
+      case FieldDescriptor::TYPE_GROUP:
+      case FieldDescriptor::TYPE_MESSAGE:
+      case FieldDescriptor::TYPE_BYTES:
+        // Can't have packed fields of these types: these should be caught by
+        // the protocol compiler.
+        return false;
+        break;
+    }
+
+    input->PopLimit(limit);
+  } else {
+    // Non-packed value (value_format == NORMAL_FORMAT)
+    switch (field->type()) {
+#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                            \
+  case FieldDescriptor::TYPE_##TYPE: {                                        \
+    CPPTYPE value;                                                            \
+    if (!WireFormatLite::ReadPrimitive<CPPTYPE, WireFormatLite::TYPE_##TYPE>( \
+            input, &value))                                                   \
+      return false;                                                           \
+    if (field->is_repeated()) {                                               \
+      message_reflection->Add##CPPTYPE_METHOD(message, field, value);         \
+    } else {                                                                  \
+      message_reflection->Set##CPPTYPE_METHOD(message, field, value);         \
+    }                                                                         \
+    break;                                                                    \
+  }
+
+      HANDLE_TYPE(INT32, int32_t, Int32)
+      HANDLE_TYPE(INT64, int64_t, Int64)
+      HANDLE_TYPE(SINT32, int32_t, Int32)
+      HANDLE_TYPE(SINT64, int64_t, Int64)
+      HANDLE_TYPE(UINT32, uint32_t, UInt32)
+      HANDLE_TYPE(UINT64, uint64_t, UInt64)
+
+      HANDLE_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_TYPE(SFIXED64, int64_t, Int64)
+
+      HANDLE_TYPE(FLOAT, float, Float)
+      HANDLE_TYPE(DOUBLE, double, Double)
+
+      HANDLE_TYPE(BOOL, bool, Bool)
+#undef HANDLE_TYPE
+
+      case FieldDescriptor::TYPE_ENUM: {
+        int value;
+        if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
+                input, &value))
+          return false;
+        if (field->is_repeated()) {
+          message_reflection->AddEnumValue(message, field, value);
+        } else {
+          message_reflection->SetEnumValue(message, field, value);
+        }
+        break;
+      }
+
+      // Handle strings separately so that we can optimize the ctype=CORD case.
+      case FieldDescriptor::TYPE_STRING: {
+        bool strict_utf8_check = StrictUtf8Check(field);
+        std::string value;
+        if (!WireFormatLite::ReadString(input, &value)) return false;
+        if (strict_utf8_check) {
+          if (!WireFormatLite::VerifyUtf8String(value.data(), value.length(),
+                                                WireFormatLite::PARSE,
+                                                field->full_name().c_str())) {
+            return false;
+          }
+        } else {
+          VerifyUTF8StringNamedField(value.data(), value.length(), PARSE,
+                                     field->full_name().c_str());
+        }
+        if (field->is_repeated()) {
+          message_reflection->AddString(message, field, value);
+        } else {
+          message_reflection->SetString(message, field, value);
+        }
+        break;
+      }
+
+      case FieldDescriptor::TYPE_BYTES: {
+        std::string value;
+        if (!WireFormatLite::ReadBytes(input, &value)) return false;
+        if (field->is_repeated()) {
+          message_reflection->AddString(message, field, value);
+        } else {
+          message_reflection->SetString(message, field, value);
+        }
+        break;
+      }
+
+      case FieldDescriptor::TYPE_GROUP: {
+        Message* sub_message;
+        if (field->is_repeated()) {
+          sub_message = message_reflection->AddMessage(
+              message, field, input->GetExtensionFactory());
+        } else {
+          sub_message = message_reflection->MutableMessage(
+              message, field, input->GetExtensionFactory());
+        }
+
+        if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag),
+                                       input, sub_message))
+          return false;
+        break;
+      }
+
+      case FieldDescriptor::TYPE_MESSAGE: {
+        Message* sub_message;
+        if (field->is_repeated()) {
+          sub_message = message_reflection->AddMessage(
+              message, field, input->GetExtensionFactory());
+        } else {
+          sub_message = message_reflection->MutableMessage(
+              message, field, input->GetExtensionFactory());
+        }
+
+        if (!WireFormatLite::ReadMessage(input, sub_message)) return false;
+        break;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool WireFormat::ParseAndMergeMessageSetItem(io::CodedInputStream* input,
+                                             Message* message) {
+  struct MSReflective {
+    bool ParseField(int type_id, io::CodedInputStream* input) {
+      const FieldDescriptor* field =
+          message_reflection->FindKnownExtensionByNumber(type_id);
+      return ParseAndMergeMessageSetField(type_id, field, message, input);
+    }
+
+    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
+      return WireFormat::SkipField(input, tag, nullptr);
+    }
+
+    const Reflection* message_reflection;
+    Message* message;
+  };
+
+  return ParseMessageSetItemImpl(
+      input, MSReflective{message->GetReflection(), message});
+}
+
+struct WireFormat::MessageSetParser {
+  const char* _InternalParse(const char* ptr, internal::ParseContext* ctx) {
+    // Parse a MessageSetItem
+    auto metadata = reflection->MutableInternalMetadata(msg);
+    enum class State { kNoTag, kHasType, kHasPayload, kDone };
+    State state = State::kNoTag;
+
+    std::string payload;
+    uint32_t type_id = 0;
+    while (!ctx->Done(&ptr)) {
+      // We use 64 bit tags in order to allow typeid's that span the whole
+      // range of 32 bit numbers.
+      uint32_t tag = static_cast<uint8_t>(*ptr++);
+      if (tag == WireFormatLite::kMessageSetTypeIdTag) {
+        uint64_t tmp;
+        ptr = ParseBigVarint(ptr, &tmp);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        if (state == State::kNoTag) {
+          type_id = tmp;
+          state = State::kHasType;
+        } else if (state == State::kHasPayload) {
+          type_id = tmp;
+          const FieldDescriptor* field;
+          if (ctx->data().pool == nullptr) {
+            field = reflection->FindKnownExtensionByNumber(type_id);
+          } else {
+            field =
+                ctx->data().pool->FindExtensionByNumber(descriptor, type_id);
+          }
+          if (field == nullptr || field->message_type() == nullptr) {
+            WriteLengthDelimited(
+                type_id, payload,
+                metadata->mutable_unknown_fields<UnknownFieldSet>());
+          } else {
+            Message* value =
+                field->is_repeated()
+                    ? reflection->AddMessage(msg, field, ctx->data().factory)
+                    : reflection->MutableMessage(msg, field,
+                                                 ctx->data().factory);
+            const char* p;
+            // We can't use regular parse from string as we have to track
+            // proper recursion depth and descriptor pools.
+            ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
+            tmp_ctx.data().pool = ctx->data().pool;
+            tmp_ctx.data().factory = ctx->data().factory;
+            GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
+                                           tmp_ctx.EndedAtLimit());
+          }
+          state = State::kDone;
+        }
+        continue;
+      } else if (tag == WireFormatLite::kMessageSetMessageTag) {
+        if (state == State::kNoTag) {
+          int32_t size = ReadSize(&ptr);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+          ptr = ctx->ReadString(ptr, size, &payload);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+          state = State::kHasPayload;
+        } else if (state == State::kHasType) {
+          // We're now parsing the payload
+          const FieldDescriptor* field = nullptr;
+          if (descriptor->IsExtensionNumber(type_id)) {
+            if (ctx->data().pool == nullptr) {
+              field = reflection->FindKnownExtensionByNumber(type_id);
+            } else {
+              field =
+                  ctx->data().pool->FindExtensionByNumber(descriptor, type_id);
+            }
+          }
+          ptr = WireFormat::_InternalParseAndMergeField(
+              msg, ptr, ctx, static_cast<uint64_t>(type_id) * 8 + 2, reflection,
+              field);
+          state = State::kDone;
+        } else {
+          int32_t size = ReadSize(&ptr);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+          ptr = ctx->Skip(ptr, size);
+          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        }
+      } else {
+        // An unknown field in MessageSetItem.
+        ptr = ReadTag(ptr - 1, &tag);
+        if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        // Skip field.
+        ptr = internal::UnknownFieldParse(
+            tag, static_cast<std::string*>(nullptr), ptr, ctx);
+      }
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+    return ptr;
+  }
+
+  const char* ParseMessageSet(const char* ptr, internal::ParseContext* ctx) {
+    while (!ctx->Done(&ptr)) {
+      uint32_t tag;
+      ptr = ReadTag(ptr, &tag);
+      if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+      if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
+        ctx->SetLastTag(tag);
+        break;
+      }
+      if (tag == WireFormatLite::kMessageSetItemStartTag) {
+        // A message set item starts
+        ptr = ctx->ParseGroup(this, ptr, tag);
+      } else {
+        // Parse other fields as normal extensions.
+        int field_number = WireFormatLite::GetTagFieldNumber(tag);
+        const FieldDescriptor* field = nullptr;
+        if (descriptor->IsExtensionNumber(field_number)) {
+          if (ctx->data().pool == nullptr) {
+            field = reflection->FindKnownExtensionByNumber(field_number);
+          } else {
+            field = ctx->data().pool->FindExtensionByNumber(descriptor,
+                                                            field_number);
+          }
+        }
+        ptr = WireFormat::_InternalParseAndMergeField(msg, ptr, ctx, tag,
+                                                      reflection, field);
+      }
+      if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+    }
+    return ptr;
+  }
+
+  Message* msg;
+  const Descriptor* descriptor;
+  const Reflection* reflection;
+};
+
+const char* WireFormat::_InternalParse(Message* msg, const char* ptr,
+                                       internal::ParseContext* ctx) {
+  const Descriptor* descriptor = msg->GetDescriptor();
+  const Reflection* reflection = msg->GetReflection();
+  GOOGLE_DCHECK(descriptor);
+  GOOGLE_DCHECK(reflection);
+  if (descriptor->options().message_set_wire_format()) {
+    MessageSetParser message_set{msg, descriptor, reflection};
+    return message_set.ParseMessageSet(ptr, ctx);
+  }
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ReadTag(ptr, &tag);
+    if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+    if (tag == 0 || (tag & 7) == WireFormatLite::WIRETYPE_END_GROUP) {
+      ctx->SetLastTag(tag);
+      break;
+    }
+    const FieldDescriptor* field = nullptr;
+
+    int field_number = WireFormatLite::GetTagFieldNumber(tag);
+    field = descriptor->FindFieldByNumber(field_number);
+
+    // If that failed, check if the field is an extension.
+    if (field == nullptr && descriptor->IsExtensionNumber(field_number)) {
+      if (ctx->data().pool == nullptr) {
+        field = reflection->FindKnownExtensionByNumber(field_number);
+      } else {
+        field =
+            ctx->data().pool->FindExtensionByNumber(descriptor, field_number);
+      }
+    }
+
+    ptr = _InternalParseAndMergeField(msg, ptr, ctx, tag, reflection, field);
+    if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+  }
+  return ptr;
+}
+
+const char* WireFormat::_InternalParseAndMergeField(
+    Message* msg, const char* ptr, internal::ParseContext* ctx, uint64_t tag,
+    const Reflection* reflection, const FieldDescriptor* field) {
+  if (field == nullptr) {
+    // unknown field set parser takes 64bit tags, because message set type ids
+    // span the full 32 bit range making the tag span [0, 2^35) range.
+    return internal::UnknownFieldParse(
+        tag, reflection->MutableUnknownFields(msg), ptr, ctx);
+  }
+  if (WireFormatLite::GetTagWireType(tag) !=
+      WireTypeForFieldType(field->type())) {
+    if (field->is_packable() && WireFormatLite::GetTagWireType(tag) ==
+                                    WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+      switch (field->type()) {
+#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                   \
+  case FieldDescriptor::TYPE_##TYPE: {                                      \
+    ptr = internal::Packed##CPPTYPE_METHOD##Parser(                         \
+        reflection->MutableRepeatedFieldInternal<CPPTYPE>(msg, field), ptr, \
+        ctx);                                                               \
+    return ptr;                                                             \
+  }
+
+        HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
+        HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
+        HANDLE_PACKED_TYPE(SINT32, int32_t, SInt32)
+        HANDLE_PACKED_TYPE(SINT64, int64_t, SInt64)
+        HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
+        HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
+
+        HANDLE_PACKED_TYPE(FIXED32, uint32_t, Fixed32)
+        HANDLE_PACKED_TYPE(FIXED64, uint64_t, Fixed64)
+        HANDLE_PACKED_TYPE(SFIXED32, int32_t, SFixed32)
+        HANDLE_PACKED_TYPE(SFIXED64, int64_t, SFixed64)
+
+        HANDLE_PACKED_TYPE(FLOAT, float, Float)
+        HANDLE_PACKED_TYPE(DOUBLE, double, Double)
+
+        HANDLE_PACKED_TYPE(BOOL, bool, Bool)
+#undef HANDLE_PACKED_TYPE
+
+        case FieldDescriptor::TYPE_ENUM: {
+          auto rep_enum =
+              reflection->MutableRepeatedFieldInternal<int>(msg, field);
+          bool open_enum = false;
+          if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ||
+              open_enum) {
+            ptr = internal::PackedEnumParser(rep_enum, ptr, ctx);
+          } else {
+            return ctx->ReadPackedVarint(
+                ptr, [rep_enum, field, reflection, msg](uint64_t val) {
+                  if (field->enum_type()->FindValueByNumber(val) != nullptr) {
+                    rep_enum->Add(val);
+                  } else {
+                    WriteVarint(field->number(), val,
+                                reflection->MutableUnknownFields(msg));
+                  }
+                });
+          }
+          return ptr;
+        }
+
+        case FieldDescriptor::TYPE_STRING:
+        case FieldDescriptor::TYPE_GROUP:
+        case FieldDescriptor::TYPE_MESSAGE:
+        case FieldDescriptor::TYPE_BYTES:
+          GOOGLE_LOG(FATAL) << "Can't reach";
+          return nullptr;
+      }
+    } else {
+      // mismatched wiretype;
+      return internal::UnknownFieldParse(
+          tag, reflection->MutableUnknownFields(msg), ptr, ctx);
+    }
+  }
+
+  // Non-packed value
+  bool utf8_check = false;
+  bool strict_utf8_check = false;
+  switch (field->type()) {
+#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)        \
+  case FieldDescriptor::TYPE_##TYPE: {                    \
+    CPPTYPE value;                                        \
+    ptr = VarintParse(ptr, &value);                       \
+    if (ptr == nullptr) return nullptr;                   \
+    if (field->is_repeated()) {                           \
+      reflection->Add##CPPTYPE_METHOD(msg, field, value); \
+    } else {                                              \
+      reflection->Set##CPPTYPE_METHOD(msg, field, value); \
+    }                                                     \
+    return ptr;                                           \
+  }
+
+    HANDLE_TYPE(BOOL, uint64_t, Bool)
+    HANDLE_TYPE(INT32, uint32_t, Int32)
+    HANDLE_TYPE(INT64, uint64_t, Int64)
+    HANDLE_TYPE(UINT32, uint32_t, UInt32)
+    HANDLE_TYPE(UINT64, uint64_t, UInt64)
+
+    case FieldDescriptor::TYPE_SINT32: {
+      int32_t value = ReadVarintZigZag32(&ptr);
+      if (ptr == nullptr) return nullptr;
+      if (field->is_repeated()) {
+        reflection->AddInt32(msg, field, value);
+      } else {
+        reflection->SetInt32(msg, field, value);
+      }
+      return ptr;
+    }
+    case FieldDescriptor::TYPE_SINT64: {
+      int64_t value = ReadVarintZigZag64(&ptr);
+      if (ptr == nullptr) return nullptr;
+      if (field->is_repeated()) {
+        reflection->AddInt64(msg, field, value);
+      } else {
+        reflection->SetInt64(msg, field, value);
+      }
+      return ptr;
+    }
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)        \
+  case FieldDescriptor::TYPE_##TYPE: {                    \
+    CPPTYPE value;                                        \
+    value = UnalignedLoad<CPPTYPE>(ptr);                  \
+    ptr += sizeof(CPPTYPE);                               \
+    if (field->is_repeated()) {                           \
+      reflection->Add##CPPTYPE_METHOD(msg, field, value); \
+    } else {                                              \
+      reflection->Set##CPPTYPE_METHOD(msg, field, value); \
+    }                                                     \
+    return ptr;                                           \
+  }
+
+      HANDLE_TYPE(FIXED32, uint32_t, UInt32)
+      HANDLE_TYPE(FIXED64, uint64_t, UInt64)
+      HANDLE_TYPE(SFIXED32, int32_t, Int32)
+      HANDLE_TYPE(SFIXED64, int64_t, Int64)
+
+      HANDLE_TYPE(FLOAT, float, Float)
+      HANDLE_TYPE(DOUBLE, double, Double)
+
+#undef HANDLE_TYPE
+
+    case FieldDescriptor::TYPE_ENUM: {
+      uint32_t value;
+      ptr = VarintParse(ptr, &value);
+      if (ptr == nullptr) return nullptr;
+      if (field->is_repeated()) {
+        reflection->AddEnumValue(msg, field, value);
+      } else {
+        reflection->SetEnumValue(msg, field, value);
+      }
+      return ptr;
+    }
+
+    // Handle strings separately so that we can optimize the ctype=CORD case.
+    case FieldDescriptor::TYPE_STRING:
+      utf8_check = true;
+      strict_utf8_check = StrictUtf8Check(field);
+      PROTOBUF_FALLTHROUGH_INTENDED;
+    case FieldDescriptor::TYPE_BYTES: {
+      int size = ReadSize(&ptr);
+      if (ptr == nullptr) return nullptr;
+      std::string value;
+      ptr = ctx->ReadString(ptr, size, &value);
+      if (ptr == nullptr) return nullptr;
+      if (utf8_check) {
+        if (strict_utf8_check) {
+          if (!WireFormatLite::VerifyUtf8String(value.data(), value.length(),
+                                                WireFormatLite::PARSE,
+                                                field->full_name().c_str())) {
+            return nullptr;
+          }
+        } else {
+          VerifyUTF8StringNamedField(value.data(), value.length(), PARSE,
+                                     field->full_name().c_str());
+        }
+      }
+      if (field->is_repeated()) {
+        reflection->AddString(msg, field, std::move(value));
+      } else {
+        reflection->SetString(msg, field, std::move(value));
+      }
+      return ptr;
+    }
+
+    case FieldDescriptor::TYPE_GROUP: {
+      Message* sub_message;
+      if (field->is_repeated()) {
+        sub_message = reflection->AddMessage(msg, field, ctx->data().factory);
+      } else {
+        sub_message =
+            reflection->MutableMessage(msg, field, ctx->data().factory);
+      }
+
+      return ctx->ParseGroup(sub_message, ptr, tag);
+    }
+
+    case FieldDescriptor::TYPE_MESSAGE: {
+      Message* sub_message;
+      if (field->is_repeated()) {
+        sub_message = reflection->AddMessage(msg, field, ctx->data().factory);
+      } else {
+        sub_message =
+            reflection->MutableMessage(msg, field, ctx->data().factory);
+      }
+      return ctx->ParseMessage(sub_message, ptr);
+    }
+  }
+
+  // GCC 8 complains about control reaching end of non-void function here.
+  // Let's keep it happy by returning a nullptr.
+  return nullptr;
+}
+
+// ===================================================================
+
+uint8_t* WireFormat::_InternalSerialize(const Message& message, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* message_reflection = message.GetReflection();
+
+  std::vector<const FieldDescriptor*> fields;
+
+  // Fields of map entry should always be serialized.
+  if (descriptor->options().map_entry()) {
+    for (int i = 0; i < descriptor->field_count(); i++) {
+      fields.push_back(descriptor->field(i));
+    }
+  } else {
+    message_reflection->ListFields(message, &fields);
+  }
+
+  for (auto field : fields) {
+    target = InternalSerializeField(field, message, target, stream);
+  }
+
+  if (descriptor->options().message_set_wire_format()) {
+    return InternalSerializeUnknownMessageSetItemsToArray(
+        message_reflection->GetUnknownFields(message), target, stream);
+  } else {
+    return InternalSerializeUnknownFieldsToArray(
+        message_reflection->GetUnknownFields(message), target, stream);
+  }
+}
+
+uint8_t* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                        const MapKey& value, uint8_t* target,
+                                        io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_BYTES:
+    case FieldDescriptor::TYPE_ENUM:
+      GOOGLE_LOG(FATAL) << "Unsupported";
+      break;
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
+  case FieldDescriptor::TYPE_##FieldType:                    \
+    target = WireFormatLite::Write##CamelFieldType##ToArray( \
+        1, value.Get##CamelCppType##Value(), target);        \
+    break;
+      CASE_TYPE(INT64, Int64, Int64)
+      CASE_TYPE(UINT64, UInt64, UInt64)
+      CASE_TYPE(INT32, Int32, Int32)
+      CASE_TYPE(FIXED64, Fixed64, UInt64)
+      CASE_TYPE(FIXED32, Fixed32, UInt32)
+      CASE_TYPE(BOOL, Bool, Bool)
+      CASE_TYPE(UINT32, UInt32, UInt32)
+      CASE_TYPE(SFIXED32, SFixed32, Int32)
+      CASE_TYPE(SFIXED64, SFixed64, Int64)
+      CASE_TYPE(SINT32, SInt32, Int32)
+      CASE_TYPE(SINT64, SInt64, Int64)
+#undef CASE_TYPE
+    case FieldDescriptor::TYPE_STRING:
+      target = stream->WriteString(1, value.GetStringValue(), target);
+      break;
+  }
+  return target;
+}
+
+static uint8_t* SerializeMapValueRefWithCachedSizes(
+    const FieldDescriptor* field, const MapValueConstRef& value,
+    uint8_t* target, io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  switch (field->type()) {
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
+  case FieldDescriptor::TYPE_##FieldType:                    \
+    target = WireFormatLite::Write##CamelFieldType##ToArray( \
+        2, value.Get##CamelCppType##Value(), target);        \
+    break;
+    CASE_TYPE(INT64, Int64, Int64)
+    CASE_TYPE(UINT64, UInt64, UInt64)
+    CASE_TYPE(INT32, Int32, Int32)
+    CASE_TYPE(FIXED64, Fixed64, UInt64)
+    CASE_TYPE(FIXED32, Fixed32, UInt32)
+    CASE_TYPE(BOOL, Bool, Bool)
+    CASE_TYPE(UINT32, UInt32, UInt32)
+    CASE_TYPE(SFIXED32, SFixed32, Int32)
+    CASE_TYPE(SFIXED64, SFixed64, Int64)
+    CASE_TYPE(SINT32, SInt32, Int32)
+    CASE_TYPE(SINT64, SInt64, Int64)
+    CASE_TYPE(ENUM, Enum, Enum)
+    CASE_TYPE(DOUBLE, Double, Double)
+    CASE_TYPE(FLOAT, Float, Float)
+#undef CASE_TYPE
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      target = stream->WriteString(2, value.GetStringValue(), target);
+      break;
+    case FieldDescriptor::TYPE_MESSAGE: {
+      auto& msg = value.GetMessageValue();
+      target = WireFormatLite::InternalWriteMessage(2, msg, msg.GetCachedSize(),
+                                                    target, stream);
+    } break;
+    case FieldDescriptor::TYPE_GROUP:
+      target = WireFormatLite::InternalWriteGroup(2, value.GetMessageValue(),
+                                                  target, stream);
+      break;
+  }
+  return target;
+}
+
+class MapKeySorter {
+ public:
+  static std::vector<MapKey> SortKey(const Message& message,
+                                     const Reflection* reflection,
+                                     const FieldDescriptor* field) {
+    std::vector<MapKey> sorted_key_list;
+    for (MapIterator it =
+             reflection->MapBegin(const_cast<Message*>(&message), field);
+         it != reflection->MapEnd(const_cast<Message*>(&message), field);
+         ++it) {
+      sorted_key_list.push_back(it.GetKey());
+    }
+    MapKeyComparator comparator;
+    std::sort(sorted_key_list.begin(), sorted_key_list.end(), comparator);
+    return sorted_key_list;
+  }
+
+ private:
+  class MapKeyComparator {
+   public:
+    bool operator()(const MapKey& a, const MapKey& b) const {
+      GOOGLE_DCHECK(a.type() == b.type());
+      switch (a.type()) {
+#define CASE_TYPE(CppType, CamelCppType)                                \
+  case FieldDescriptor::CPPTYPE_##CppType: {                            \
+    return a.Get##CamelCppType##Value() < b.Get##CamelCppType##Value(); \
+  }
+        CASE_TYPE(STRING, String)
+        CASE_TYPE(INT64, Int64)
+        CASE_TYPE(INT32, Int32)
+        CASE_TYPE(UINT64, UInt64)
+        CASE_TYPE(UINT32, UInt32)
+        CASE_TYPE(BOOL, Bool)
+#undef CASE_TYPE
+
+        default:
+          GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+          return true;
+      }
+    }
+  };
+};
+
+static uint8_t* InternalSerializeMapEntry(const FieldDescriptor* field,
+                                          const MapKey& key,
+                                          const MapValueConstRef& value,
+                                          uint8_t* target,
+                                          io::EpsCopyOutputStream* stream) {
+  const FieldDescriptor* key_field = field->message_type()->field(0);
+  const FieldDescriptor* value_field = field->message_type()->field(1);
+
+  size_t size = kMapEntryTagByteSize;
+  size += MapKeyDataOnlyByteSize(key_field, key);
+  size += MapValueRefDataOnlyByteSize(value_field, value);
+  target = stream->EnsureSpace(target);
+  target = WireFormatLite::WriteTagToArray(
+      field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(size, target);
+  target = SerializeMapKeyWithCachedSizes(key_field, key, target, stream);
+  target =
+      SerializeMapValueRefWithCachedSizes(value_field, value, target, stream);
+  return target;
+}
+
+uint8_t* WireFormat::InternalSerializeField(const FieldDescriptor* field,
+                                            const Message& message,
+                                            uint8_t* target,
+                                            io::EpsCopyOutputStream* stream) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  if (field->is_extension() &&
+      field->containing_type()->options().message_set_wire_format() &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      !field->is_repeated()) {
+    return InternalSerializeMessageSetItem(field, message, target, stream);
+  }
+
+  // For map fields, we can use either repeated field reflection or map
+  // reflection.  Our choice has some subtle effects.  If we use repeated field
+  // reflection here, then the repeated field representation becomes
+  // authoritative for this field: any existing references that came from map
+  // reflection remain valid for reading, but mutations to them are lost and
+  // will be overwritten next time we call map reflection!
+  //
+  // So far this mainly affects Python, which keeps long-term references to map
+  // values around, and always uses map reflection.  See: b/35918691
+  //
+  // Here we choose to use map reflection API as long as the internal
+  // map is valid. In this way, the serialization doesn't change map field's
+  // internal state and existing references that came from map reflection remain
+  // valid for both reading and writing.
+  if (field->is_map()) {
+    const MapFieldBase* map_field =
+        message_reflection->GetMapData(message, field);
+    if (map_field->IsMapValid()) {
+      if (stream->IsSerializationDeterministic()) {
+        std::vector<MapKey> sorted_key_list =
+            MapKeySorter::SortKey(message, message_reflection, field);
+        for (std::vector<MapKey>::iterator it = sorted_key_list.begin();
+             it != sorted_key_list.end(); ++it) {
+          MapValueConstRef map_value;
+          message_reflection->LookupMapValue(message, field, *it, &map_value);
+          target =
+              InternalSerializeMapEntry(field, *it, map_value, target, stream);
+        }
+      } else {
+        for (MapIterator it = message_reflection->MapBegin(
+                 const_cast<Message*>(&message), field);
+             it !=
+             message_reflection->MapEnd(const_cast<Message*>(&message), field);
+             ++it) {
+          target = InternalSerializeMapEntry(field, it.GetKey(),
+                                             it.GetValueRef(), target, stream);
+        }
+      }
+
+      return target;
+    }
+  }
+  int count = 0;
+
+  if (field->is_repeated()) {
+    count = message_reflection->FieldSize(message, field);
+  } else if (field->containing_type()->options().map_entry()) {
+    // Map entry fields always need to be serialized.
+    count = 1;
+  } else if (message_reflection->HasField(message, field)) {
+    count = 1;
+  }
+
+  // map_entries is for maps that'll be deterministically serialized.
+  std::vector<const Message*> map_entries;
+  if (count > 1 && field->is_map() && stream->IsSerializationDeterministic()) {
+    map_entries =
+        DynamicMapSorter::Sort(message, count, message_reflection, field);
+  }
+
+  if (field->is_packed()) {
+    if (count == 0) return target;
+    target = stream->EnsureSpace(target);
+    switch (field->type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)      \
+  case FieldDescriptor::TYPE_##TYPE: {                                         \
+    auto r =                                                                   \
+        message_reflection->GetRepeatedFieldInternal<CPPTYPE>(message, field); \
+    target = stream->Write##TYPE_METHOD##Packed(                               \
+        field->number(), r, FieldDataOnlyByteSize(field, message), target);    \
+    break;                                                                     \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(ENUM, int, Enum, Enum)
+
+#undef HANDLE_PRIMITIVE_TYPE
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)      \
+  case FieldDescriptor::TYPE_##TYPE: {                                         \
+    auto r =                                                                   \
+        message_reflection->GetRepeatedFieldInternal<CPPTYPE>(message, field); \
+    target = stream->WriteFixedPacked(field->number(), r, target);             \
+    break;                                                                     \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)
+
+      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
+      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
+
+      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
+#undef HANDLE_PRIMITIVE_TYPE
+      default:
+        GOOGLE_LOG(FATAL) << "Invalid descriptor";
+    }
+    return target;
+  }
+
+  auto get_message_from_field = [&message, &map_entries, message_reflection](
+                                    const FieldDescriptor* field, int j) {
+    if (!field->is_repeated()) {
+      return &message_reflection->GetMessage(message, field);
+    }
+    if (!map_entries.empty()) {
+      return map_entries[j];
+    }
+    return &message_reflection->GetRepeatedMessage(message, field, j);
+  };
+  for (int j = 0; j < count; j++) {
+    target = stream->EnsureSpace(target);
+    switch (field->type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)     \
+  case FieldDescriptor::TYPE_##TYPE: {                                        \
+    const CPPTYPE value =                                                     \
+        field->is_repeated()                                                  \
+            ? message_reflection->GetRepeated##CPPTYPE_METHOD(message, field, \
+                                                              j)              \
+            : message_reflection->Get##CPPTYPE_METHOD(message, field);        \
+    target = WireFormatLite::Write##TYPE_METHOD##ToArray(field->number(),     \
+                                                         value, target);      \
+    break;                                                                    \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
+
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)
+
+      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
+      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
+
+      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
+#undef HANDLE_PRIMITIVE_TYPE
+
+      case FieldDescriptor::TYPE_GROUP: {
+        auto* msg = get_message_from_field(field, j);
+        target = WireFormatLite::InternalWriteGroup(field->number(), *msg,
+                                                    target, stream);
+      } break;
+
+      case FieldDescriptor::TYPE_MESSAGE: {
+        auto* msg = get_message_from_field(field, j);
+        target = WireFormatLite::InternalWriteMessage(
+            field->number(), *msg, msg->GetCachedSize(), target, stream);
+      } break;
+
+      case FieldDescriptor::TYPE_ENUM: {
+        const EnumValueDescriptor* value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedEnum(message, field, j)
+                : message_reflection->GetEnum(message, field);
+        target = WireFormatLite::WriteEnumToArray(field->number(),
+                                                  value->number(), target);
+        break;
+      }
+
+      // Handle strings separately so that we can get string references
+      // instead of copying.
+      case FieldDescriptor::TYPE_STRING: {
+        bool strict_utf8_check = StrictUtf8Check(field);
+        std::string scratch;
+        const std::string& value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedStringReference(message, field,
+                                                                 j, &scratch)
+                : message_reflection->GetStringReference(message, field,
+                                                         &scratch);
+        if (strict_utf8_check) {
+          WireFormatLite::VerifyUtf8String(value.data(), value.length(),
+                                           WireFormatLite::SERIALIZE,
+                                           field->full_name().c_str());
+        } else {
+          VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
+                                     field->full_name().c_str());
+        }
+        target = stream->WriteString(field->number(), value, target);
+        break;
+      }
+
+      case FieldDescriptor::TYPE_BYTES: {
+        std::string scratch;
+        const std::string& value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedStringReference(message, field,
+                                                                 j, &scratch)
+                : message_reflection->GetStringReference(message, field,
+                                                         &scratch);
+        target = stream->WriteString(field->number(), value, target);
+        break;
+      }
+    }
+  }
+  return target;
+}
+
+uint8_t* WireFormat::InternalSerializeMessageSetItem(
+    const FieldDescriptor* field, const Message& message, uint8_t* target,
+    io::EpsCopyOutputStream* stream) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  target = stream->EnsureSpace(target);
+  // Start group.
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemStartTag, target);
+  // Write type ID.
+  target = WireFormatLite::WriteUInt32ToArray(
+      WireFormatLite::kMessageSetTypeIdNumber, field->number(), target);
+  // Write message.
+  auto& msg = message_reflection->GetMessage(message, field);
+  target = WireFormatLite::InternalWriteMessage(
+      WireFormatLite::kMessageSetMessageNumber, msg, msg.GetCachedSize(),
+      target, stream);
+  // End group.
+  target = stream->EnsureSpace(target);
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemEndTag, target);
+  return target;
+}
+
+// ===================================================================
+
+size_t WireFormat::ByteSize(const Message& message) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  const Reflection* message_reflection = message.GetReflection();
+
+  size_t our_size = 0;
+
+  std::vector<const FieldDescriptor*> fields;
+
+  // Fields of map entry should always be serialized.
+  if (descriptor->options().map_entry()) {
+    for (int i = 0; i < descriptor->field_count(); i++) {
+      fields.push_back(descriptor->field(i));
+    }
+  } else {
+    message_reflection->ListFields(message, &fields);
+  }
+
+  for (const FieldDescriptor* field : fields) {
+    our_size += FieldByteSize(field, message);
+  }
+
+  if (descriptor->options().message_set_wire_format()) {
+    our_size += ComputeUnknownMessageSetItemsSize(
+        message_reflection->GetUnknownFields(message));
+  } else {
+    our_size +=
+        ComputeUnknownFieldsSize(message_reflection->GetUnknownFields(message));
+  }
+
+  return our_size;
+}
+
+size_t WireFormat::FieldByteSize(const FieldDescriptor* field,
+                                 const Message& message) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  if (field->is_extension() &&
+      field->containing_type()->options().message_set_wire_format() &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      !field->is_repeated()) {
+    return MessageSetItemByteSize(field, message);
+  }
+
+  size_t count = 0;
+  if (field->is_repeated()) {
+    if (field->is_map()) {
+      const MapFieldBase* map_field =
+          message_reflection->GetMapData(message, field);
+      if (map_field->IsMapValid()) {
+        count = FromIntSize(map_field->size());
+      } else {
+        count = FromIntSize(message_reflection->FieldSize(message, field));
+      }
+    } else {
+      count = FromIntSize(message_reflection->FieldSize(message, field));
+    }
+  } else if (field->containing_type()->options().map_entry()) {
+    // Map entry fields always need to be serialized.
+    count = 1;
+  } else if (message_reflection->HasField(message, field)) {
+    count = 1;
+  }
+
+  const size_t data_size = FieldDataOnlyByteSize(field, message);
+  size_t our_size = data_size;
+  if (field->is_packed()) {
+    if (data_size > 0) {
+      // Packed fields get serialized like a string, not their native type.
+      // Technically this doesn't really matter; the size only changes if it's
+      // a GROUP
+      our_size += TagSize(field->number(), FieldDescriptor::TYPE_STRING);
+      our_size += io::CodedOutputStream::VarintSize32(data_size);
+    }
+  } else {
+    our_size += count * TagSize(field->number(), field->type());
+  }
+  return our_size;
+}
+
+size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
+                              const MapKey& value) {
+  GOOGLE_DCHECK_EQ(FieldDescriptor::TypeToCppType(field->type()), value.type());
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_BYTES:
+    case FieldDescriptor::TYPE_ENUM:
+      GOOGLE_LOG(FATAL) << "Unsupported";
+      return 0;
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
+  case FieldDescriptor::TYPE_##FieldType:                  \
+    return WireFormatLite::CamelFieldType##Size(           \
+        value.Get##CamelCppType##Value());
+
+#define FIXED_CASE_TYPE(FieldType, CamelFieldType) \
+  case FieldDescriptor::TYPE_##FieldType:          \
+    return WireFormatLite::k##CamelFieldType##Size;
+
+      CASE_TYPE(INT32, Int32, Int32);
+      CASE_TYPE(INT64, Int64, Int64);
+      CASE_TYPE(UINT32, UInt32, UInt32);
+      CASE_TYPE(UINT64, UInt64, UInt64);
+      CASE_TYPE(SINT32, SInt32, Int32);
+      CASE_TYPE(SINT64, SInt64, Int64);
+      CASE_TYPE(STRING, String, String);
+      FIXED_CASE_TYPE(FIXED32, Fixed32);
+      FIXED_CASE_TYPE(FIXED64, Fixed64);
+      FIXED_CASE_TYPE(SFIXED32, SFixed32);
+      FIXED_CASE_TYPE(SFIXED64, SFixed64);
+      FIXED_CASE_TYPE(BOOL, Bool);
+
+#undef CASE_TYPE
+#undef FIXED_CASE_TYPE
+  }
+  GOOGLE_LOG(FATAL) << "Cannot get here";
+  return 0;
+}
+
+static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field,
+                                          const MapValueConstRef& value) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_GROUP:
+      GOOGLE_LOG(FATAL) << "Unsupported";
+      return 0;
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
+  case FieldDescriptor::TYPE_##FieldType:                  \
+    return WireFormatLite::CamelFieldType##Size(           \
+        value.Get##CamelCppType##Value());
+
+#define FIXED_CASE_TYPE(FieldType, CamelFieldType) \
+  case FieldDescriptor::TYPE_##FieldType:          \
+    return WireFormatLite::k##CamelFieldType##Size;
+
+      CASE_TYPE(INT32, Int32, Int32);
+      CASE_TYPE(INT64, Int64, Int64);
+      CASE_TYPE(UINT32, UInt32, UInt32);
+      CASE_TYPE(UINT64, UInt64, UInt64);
+      CASE_TYPE(SINT32, SInt32, Int32);
+      CASE_TYPE(SINT64, SInt64, Int64);
+      CASE_TYPE(STRING, String, String);
+      CASE_TYPE(BYTES, Bytes, String);
+      CASE_TYPE(ENUM, Enum, Enum);
+      CASE_TYPE(MESSAGE, Message, Message);
+      FIXED_CASE_TYPE(FIXED32, Fixed32);
+      FIXED_CASE_TYPE(FIXED64, Fixed64);
+      FIXED_CASE_TYPE(SFIXED32, SFixed32);
+      FIXED_CASE_TYPE(SFIXED64, SFixed64);
+      FIXED_CASE_TYPE(DOUBLE, Double);
+      FIXED_CASE_TYPE(FLOAT, Float);
+      FIXED_CASE_TYPE(BOOL, Bool);
+
+#undef CASE_TYPE
+#undef FIXED_CASE_TYPE
+  }
+  GOOGLE_LOG(FATAL) << "Cannot get here";
+  return 0;
+}
+
+size_t WireFormat::FieldDataOnlyByteSize(const FieldDescriptor* field,
+                                         const Message& message) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  size_t data_size = 0;
+
+  if (field->is_map()) {
+    const MapFieldBase* map_field =
+        message_reflection->GetMapData(message, field);
+    if (map_field->IsMapValid()) {
+      MapIterator iter(const_cast<Message*>(&message), field);
+      MapIterator end(const_cast<Message*>(&message), field);
+      const FieldDescriptor* key_field = field->message_type()->field(0);
+      const FieldDescriptor* value_field = field->message_type()->field(1);
+      for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end;
+           ++iter) {
+        size_t size = kMapEntryTagByteSize;
+        size += MapKeyDataOnlyByteSize(key_field, iter.GetKey());
+        size += MapValueRefDataOnlyByteSize(value_field, iter.GetValueRef());
+        data_size += WireFormatLite::LengthDelimitedSize(size);
+      }
+      return data_size;
+    }
+  }
+
+  size_t count = 0;
+  if (field->is_repeated()) {
+    count =
+        internal::FromIntSize(message_reflection->FieldSize(message, field));
+  } else if (field->containing_type()->options().map_entry()) {
+    // Map entry fields always need to be serialized.
+    count = 1;
+  } else if (message_reflection->HasField(message, field)) {
+    count = 1;
+  }
+
+  switch (field->type()) {
+#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD)                      \
+  case FieldDescriptor::TYPE_##TYPE:                                        \
+    if (field->is_repeated()) {                                             \
+      for (size_t j = 0; j < count; j++) {                                  \
+        data_size += WireFormatLite::TYPE_METHOD##Size(                     \
+            message_reflection->GetRepeated##CPPTYPE_METHOD(message, field, \
+                                                            j));            \
+      }                                                                     \
+    } else {                                                                \
+      data_size += WireFormatLite::TYPE_METHOD##Size(                       \
+          message_reflection->Get##CPPTYPE_METHOD(message, field));         \
+    }                                                                       \
+    break;
+
+#define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD)                   \
+  case FieldDescriptor::TYPE_##TYPE:                           \
+    data_size += count * WireFormatLite::k##TYPE_METHOD##Size; \
+    break;
+
+    HANDLE_TYPE(INT32, Int32, Int32)
+    HANDLE_TYPE(INT64, Int64, Int64)
+    HANDLE_TYPE(SINT32, SInt32, Int32)
+    HANDLE_TYPE(SINT64, SInt64, Int64)
+    HANDLE_TYPE(UINT32, UInt32, UInt32)
+    HANDLE_TYPE(UINT64, UInt64, UInt64)
+
+    HANDLE_FIXED_TYPE(FIXED32, Fixed32)
+    HANDLE_FIXED_TYPE(FIXED64, Fixed64)
+    HANDLE_FIXED_TYPE(SFIXED32, SFixed32)
+    HANDLE_FIXED_TYPE(SFIXED64, SFixed64)
+
+    HANDLE_FIXED_TYPE(FLOAT, Float)
+    HANDLE_FIXED_TYPE(DOUBLE, Double)
+
+    HANDLE_FIXED_TYPE(BOOL, Bool)
+
+    HANDLE_TYPE(GROUP, Group, Message)
+    HANDLE_TYPE(MESSAGE, Message, Message)
+#undef HANDLE_TYPE
+#undef HANDLE_FIXED_TYPE
+
+    case FieldDescriptor::TYPE_ENUM: {
+      if (field->is_repeated()) {
+        for (size_t j = 0; j < count; j++) {
+          data_size += WireFormatLite::EnumSize(
+              message_reflection->GetRepeatedEnum(message, field, j)->number());
+        }
+      } else {
+        data_size += WireFormatLite::EnumSize(
+            message_reflection->GetEnum(message, field)->number());
+      }
+      break;
+    }
+
+    // Handle strings separately so that we can get string references
+    // instead of copying.
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES: {
+      for (size_t j = 0; j < count; j++) {
+        std::string scratch;
+        const std::string& value =
+            field->is_repeated()
+                ? message_reflection->GetRepeatedStringReference(message, field,
+                                                                 j, &scratch)
+                : message_reflection->GetStringReference(message, field,
+                                                         &scratch);
+        data_size += WireFormatLite::StringSize(value);
+      }
+      break;
+    }
+  }
+  return data_size;
+}
+
+size_t WireFormat::MessageSetItemByteSize(const FieldDescriptor* field,
+                                          const Message& message) {
+  const Reflection* message_reflection = message.GetReflection();
+
+  size_t our_size = WireFormatLite::kMessageSetItemTagsSize;
+
+  // type_id
+  our_size += io::CodedOutputStream::VarintSize32(field->number());
+
+  // message
+  const Message& sub_message = message_reflection->GetMessage(message, field);
+  size_t message_size = sub_message.ByteSizeLong();
+
+  our_size += io::CodedOutputStream::VarintSize32(message_size);
+  our_size += message_size;
+
+  return our_size;
+}
+
+// Compute the size of the UnknownFieldSet on the wire.
+size_t ComputeUnknownFieldsSize(const InternalMetadata& metadata,
+                                size_t total_size, CachedSize* cached_size) {
+  total_size += WireFormat::ComputeUnknownFieldsSize(
+      metadata.unknown_fields<UnknownFieldSet>(
+          UnknownFieldSet::default_instance));
+  cached_size->Set(ToCachedSize(total_size));
+  return total_size;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/wire_format_lite.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/wire_format_lite.cpp
new file mode 100644
index 0000000..5ab1ca1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/wire_format_lite.cpp
@@ -0,0 +1,818 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/wire_format_lite.h>
+
+#include <limits>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/stringprintf.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
+// Old version of MSVC doesn't like definitions of inline constants, GCC
+// requires them.
+const int WireFormatLite::kMessageSetItemStartTag;
+const int WireFormatLite::kMessageSetItemEndTag;
+const int WireFormatLite::kMessageSetTypeIdTag;
+const int WireFormatLite::kMessageSetMessageTag;
+
+#endif
+
+// IBM xlC requires prefixing constants with WireFormatLite::
+const size_t WireFormatLite::kMessageSetItemTagsSize =
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetItemStartTag>::value +
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetItemEndTag>::value +
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetTypeIdTag>::value +
+    io::CodedOutputStream::StaticVarintSize32<
+        WireFormatLite::kMessageSetMessageTag>::value;
+
+const WireFormatLite::CppType
+    WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = {
+        static_cast<CppType>(0),  // 0 is reserved for errors
+
+        CPPTYPE_DOUBLE,   // TYPE_DOUBLE
+        CPPTYPE_FLOAT,    // TYPE_FLOAT
+        CPPTYPE_INT64,    // TYPE_INT64
+        CPPTYPE_UINT64,   // TYPE_UINT64
+        CPPTYPE_INT32,    // TYPE_INT32
+        CPPTYPE_UINT64,   // TYPE_FIXED64
+        CPPTYPE_UINT32,   // TYPE_FIXED32
+        CPPTYPE_BOOL,     // TYPE_BOOL
+        CPPTYPE_STRING,   // TYPE_STRING
+        CPPTYPE_MESSAGE,  // TYPE_GROUP
+        CPPTYPE_MESSAGE,  // TYPE_MESSAGE
+        CPPTYPE_STRING,   // TYPE_BYTES
+        CPPTYPE_UINT32,   // TYPE_UINT32
+        CPPTYPE_ENUM,     // TYPE_ENUM
+        CPPTYPE_INT32,    // TYPE_SFIXED32
+        CPPTYPE_INT64,    // TYPE_SFIXED64
+        CPPTYPE_INT32,    // TYPE_SINT32
+        CPPTYPE_INT64,    // TYPE_SINT64
+};
+
+const WireFormatLite::WireType
+    WireFormatLite::kWireTypeForFieldType[MAX_FIELD_TYPE + 1] = {
+        static_cast<WireFormatLite::WireType>(-1),  // invalid
+        WireFormatLite::WIRETYPE_FIXED64,           // TYPE_DOUBLE
+        WireFormatLite::WIRETYPE_FIXED32,           // TYPE_FLOAT
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_INT64
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_UINT64
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_INT32
+        WireFormatLite::WIRETYPE_FIXED64,           // TYPE_FIXED64
+        WireFormatLite::WIRETYPE_FIXED32,           // TYPE_FIXED32
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_BOOL
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED,  // TYPE_STRING
+        WireFormatLite::WIRETYPE_START_GROUP,       // TYPE_GROUP
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED,  // TYPE_MESSAGE
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED,  // TYPE_BYTES
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_UINT32
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_ENUM
+        WireFormatLite::WIRETYPE_FIXED32,           // TYPE_SFIXED32
+        WireFormatLite::WIRETYPE_FIXED64,           // TYPE_SFIXED64
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_SINT32
+        WireFormatLite::WIRETYPE_VARINT,            // TYPE_SINT64
+};
+
+bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32_t tag) {
+  // Field number 0 is illegal.
+  if (WireFormatLite::GetTagFieldNumber(tag) == 0) return false;
+  switch (WireFormatLite::GetTagWireType(tag)) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      uint64_t value;
+      if (!input->ReadVarint64(&value)) return false;
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      uint64_t value;
+      if (!input->ReadLittleEndian64(&value)) return false;
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      uint32_t length;
+      if (!input->ReadVarint32(&length)) return false;
+      if (!input->Skip(length)) return false;
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      if (!input->IncrementRecursionDepth()) return false;
+      if (!SkipMessage(input)) return false;
+      input->DecrementRecursionDepth();
+      // Check that the ending tag matched the starting tag.
+      if (!input->LastTagWas(
+              WireFormatLite::MakeTag(WireFormatLite::GetTagFieldNumber(tag),
+                                      WireFormatLite::WIRETYPE_END_GROUP))) {
+        return false;
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      return false;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32: {
+      uint32_t value;
+      if (!input->ReadLittleEndian32(&value)) return false;
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
+bool WireFormatLite::SkipField(io::CodedInputStream* input, uint32_t tag,
+                               io::CodedOutputStream* output) {
+  // Field number 0 is illegal.
+  if (WireFormatLite::GetTagFieldNumber(tag) == 0) return false;
+  switch (WireFormatLite::GetTagWireType(tag)) {
+    case WireFormatLite::WIRETYPE_VARINT: {
+      uint64_t value;
+      if (!input->ReadVarint64(&value)) return false;
+      output->WriteVarint32(tag);
+      output->WriteVarint64(value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_FIXED64: {
+      uint64_t value;
+      if (!input->ReadLittleEndian64(&value)) return false;
+      output->WriteVarint32(tag);
+      output->WriteLittleEndian64(value);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
+      uint32_t length;
+      if (!input->ReadVarint32(&length)) return false;
+      output->WriteVarint32(tag);
+      output->WriteVarint32(length);
+      // TODO(mkilavuz): Provide API to prevent extra string copying.
+      std::string temp;
+      if (!input->ReadString(&temp, length)) return false;
+      output->WriteString(temp);
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_START_GROUP: {
+      output->WriteVarint32(tag);
+      if (!input->IncrementRecursionDepth()) return false;
+      if (!SkipMessage(input, output)) return false;
+      input->DecrementRecursionDepth();
+      // Check that the ending tag matched the starting tag.
+      if (!input->LastTagWas(
+              WireFormatLite::MakeTag(WireFormatLite::GetTagFieldNumber(tag),
+                                      WireFormatLite::WIRETYPE_END_GROUP))) {
+        return false;
+      }
+      return true;
+    }
+    case WireFormatLite::WIRETYPE_END_GROUP: {
+      return false;
+    }
+    case WireFormatLite::WIRETYPE_FIXED32: {
+      uint32_t value;
+      if (!input->ReadLittleEndian32(&value)) return false;
+      output->WriteVarint32(tag);
+      output->WriteLittleEndian32(value);
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
+bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+    if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+      // Must be the end of the message.
+      return true;
+    }
+
+    if (!SkipField(input, tag)) return false;
+  }
+}
+
+bool WireFormatLite::SkipMessage(io::CodedInputStream* input,
+                                 io::CodedOutputStream* output) {
+  while (true) {
+    uint32_t tag = input->ReadTag();
+    if (tag == 0) {
+      // End of input.  This is a valid place to end, so return true.
+      return true;
+    }
+
+    WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
+
+    if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
+      output->WriteVarint32(tag);
+      // Must be the end of the message.
+      return true;
+    }
+
+    if (!SkipField(input, tag, output)) return false;
+  }
+}
+
+bool FieldSkipper::SkipField(io::CodedInputStream* input, uint32_t tag) {
+  return WireFormatLite::SkipField(input, tag);
+}
+
+bool FieldSkipper::SkipMessage(io::CodedInputStream* input) {
+  return WireFormatLite::SkipMessage(input);
+}
+
+void FieldSkipper::SkipUnknownEnum(int /* field_number */, int /* value */) {
+  // Nothing.
+}
+
+bool CodedOutputStreamFieldSkipper::SkipField(io::CodedInputStream* input,
+                                              uint32_t tag) {
+  return WireFormatLite::SkipField(input, tag, unknown_fields_);
+}
+
+bool CodedOutputStreamFieldSkipper::SkipMessage(io::CodedInputStream* input) {
+  return WireFormatLite::SkipMessage(input, unknown_fields_);
+}
+
+void CodedOutputStreamFieldSkipper::SkipUnknownEnum(int field_number,
+                                                    int value) {
+  unknown_fields_->WriteVarint32(field_number);
+  unknown_fields_->WriteVarint64(value);
+}
+
+bool WireFormatLite::ReadPackedEnumPreserveUnknowns(
+    io::CodedInputStream* input, int field_number, bool (*is_valid)(int),
+    io::CodedOutputStream* unknown_fields_stream, RepeatedField<int>* values) {
+  uint32_t length;
+  if (!input->ReadVarint32(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    int value;
+    if (!ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(input, &value)) {
+      return false;
+    }
+    if (is_valid == nullptr || is_valid(value)) {
+      values->Add(value);
+    } else {
+      uint32_t tag = WireFormatLite::MakeTag(field_number,
+                                             WireFormatLite::WIRETYPE_VARINT);
+      unknown_fields_stream->WriteVarint32(tag);
+      unknown_fields_stream->WriteVarint32(value);
+    }
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+#if !defined(PROTOBUF_LITTLE_ENDIAN)
+
+namespace {
+void EncodeFixedSizeValue(float v, uint8_t* dest) {
+  WireFormatLite::WriteFloatNoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(double v, uint8_t* dest) {
+  WireFormatLite::WriteDoubleNoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(uint32_t v, uint8_t* dest) {
+  WireFormatLite::WriteFixed32NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(uint64_t v, uint8_t* dest) {
+  WireFormatLite::WriteFixed64NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(int32_t v, uint8_t* dest) {
+  WireFormatLite::WriteSFixed32NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(int64_t v, uint8_t* dest) {
+  WireFormatLite::WriteSFixed64NoTagToArray(v, dest);
+}
+
+void EncodeFixedSizeValue(bool v, uint8_t* dest) {
+  WireFormatLite::WriteBoolNoTagToArray(v, dest);
+}
+}  // anonymous namespace
+
+#endif  // !defined(PROTOBUF_LITTLE_ENDIAN)
+
+template <typename CType>
+static void WriteArray(const CType* a, int n, io::CodedOutputStream* output) {
+#if defined(PROTOBUF_LITTLE_ENDIAN)
+  output->WriteRaw(reinterpret_cast<const char*>(a), n * sizeof(a[0]));
+#else
+  const int kAtATime = 128;
+  uint8_t buf[sizeof(CType) * kAtATime];
+  for (int i = 0; i < n; i += kAtATime) {
+    int to_do = std::min(kAtATime, n - i);
+    uint8_t* ptr = buf;
+    for (int j = 0; j < to_do; j++) {
+      EncodeFixedSizeValue(a[i + j], ptr);
+      ptr += sizeof(a[0]);
+    }
+    output->WriteRaw(buf, to_do * sizeof(a[0]));
+  }
+#endif
+}
+
+void WireFormatLite::WriteFloatArray(const float* a, int n,
+                                     io::CodedOutputStream* output) {
+  WriteArray<float>(a, n, output);
+}
+
+void WireFormatLite::WriteDoubleArray(const double* a, int n,
+                                      io::CodedOutputStream* output) {
+  WriteArray<double>(a, n, output);
+}
+
+void WireFormatLite::WriteFixed32Array(const uint32_t* a, int n,
+                                       io::CodedOutputStream* output) {
+  WriteArray<uint32_t>(a, n, output);
+}
+
+void WireFormatLite::WriteFixed64Array(const uint64_t* a, int n,
+                                       io::CodedOutputStream* output) {
+  WriteArray<uint64_t>(a, n, output);
+}
+
+void WireFormatLite::WriteSFixed32Array(const int32_t* a, int n,
+                                        io::CodedOutputStream* output) {
+  WriteArray<int32_t>(a, n, output);
+}
+
+void WireFormatLite::WriteSFixed64Array(const int64_t* a, int n,
+                                        io::CodedOutputStream* output) {
+  WriteArray<int64_t>(a, n, output);
+}
+
+void WireFormatLite::WriteBoolArray(const bool* a, int n,
+                                    io::CodedOutputStream* output) {
+  WriteArray<bool>(a, n, output);
+}
+
+void WireFormatLite::WriteInt32(int field_number, int32_t value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteInt32NoTag(value, output);
+}
+void WireFormatLite::WriteInt64(int field_number, int64_t value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteInt64NoTag(value, output);
+}
+void WireFormatLite::WriteUInt32(int field_number, uint32_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteUInt32NoTag(value, output);
+}
+void WireFormatLite::WriteUInt64(int field_number, uint64_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteUInt64NoTag(value, output);
+}
+void WireFormatLite::WriteSInt32(int field_number, int32_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteSInt32NoTag(value, output);
+}
+void WireFormatLite::WriteSInt64(int field_number, int64_t value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteSInt64NoTag(value, output);
+}
+void WireFormatLite::WriteFixed32(int field_number, uint32_t value,
+                                  io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED32, output);
+  WriteFixed32NoTag(value, output);
+}
+void WireFormatLite::WriteFixed64(int field_number, uint64_t value,
+                                  io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED64, output);
+  WriteFixed64NoTag(value, output);
+}
+void WireFormatLite::WriteSFixed32(int field_number, int32_t value,
+                                   io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED32, output);
+  WriteSFixed32NoTag(value, output);
+}
+void WireFormatLite::WriteSFixed64(int field_number, int64_t value,
+                                   io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED64, output);
+  WriteSFixed64NoTag(value, output);
+}
+void WireFormatLite::WriteFloat(int field_number, float value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED32, output);
+  WriteFloatNoTag(value, output);
+}
+void WireFormatLite::WriteDouble(int field_number, double value,
+                                 io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_FIXED64, output);
+  WriteDoubleNoTag(value, output);
+}
+void WireFormatLite::WriteBool(int field_number, bool value,
+                               io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteBoolNoTag(value, output);
+}
+void WireFormatLite::WriteEnum(int field_number, int value,
+                               io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_VARINT, output);
+  WriteEnumNoTag(value, output);
+}
+
+constexpr size_t kInt32MaxSize = std::numeric_limits<int32_t>::max();
+
+void WireFormatLite::WriteString(int field_number, const std::string& value,
+                                 io::CodedOutputStream* output) {
+  // String is for UTF-8 text only
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteString(value);
+}
+void WireFormatLite::WriteStringMaybeAliased(int field_number,
+                                             const std::string& value,
+                                             io::CodedOutputStream* output) {
+  // String is for UTF-8 text only
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteRawMaybeAliased(value.data(), value.size());
+}
+void WireFormatLite::WriteBytes(int field_number, const std::string& value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteString(value);
+}
+void WireFormatLite::WriteBytesMaybeAliased(int field_number,
+                                            const std::string& value,
+                                            io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  GOOGLE_CHECK_LE(value.size(), kInt32MaxSize);
+  output->WriteVarint32(value.size());
+  output->WriteRawMaybeAliased(value.data(), value.size());
+}
+
+
+void WireFormatLite::WriteGroup(int field_number, const MessageLite& value,
+                                io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_START_GROUP, output);
+  value.SerializeWithCachedSizes(output);
+  WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+
+void WireFormatLite::WriteMessage(int field_number, const MessageLite& value,
+                                  io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  const int size = value.GetCachedSize();
+  output->WriteVarint32(size);
+  value.SerializeWithCachedSizes(output);
+}
+
+uint8_t* WireFormatLite::InternalWriteGroup(int field_number,
+                                            const MessageLite& value,
+                                            uint8_t* target,
+                                            io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
+  target = value._InternalSerialize(target, stream);
+  target = stream->EnsureSpace(target);
+  return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
+}
+
+uint8_t* WireFormatLite::InternalWriteMessage(int field_number,
+                                              const MessageLite& value,
+                                              int cached_size, uint8_t* target,
+                                              io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(
+      static_cast<uint32_t>(cached_size), target);
+  return value._InternalSerialize(target, stream);
+}
+
+void WireFormatLite::WriteSubMessageMaybeToArray(
+    int /*size*/, const MessageLite& value, io::CodedOutputStream* output) {
+  output->SetCur(value._InternalSerialize(output->Cur(), output->EpsCopy()));
+}
+
+void WireFormatLite::WriteGroupMaybeToArray(int field_number,
+                                            const MessageLite& value,
+                                            io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_START_GROUP, output);
+  const int size = value.GetCachedSize();
+  WriteSubMessageMaybeToArray(size, value, output);
+  WriteTag(field_number, WIRETYPE_END_GROUP, output);
+}
+
+void WireFormatLite::WriteMessageMaybeToArray(int field_number,
+                                              const MessageLite& value,
+                                              io::CodedOutputStream* output) {
+  WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
+  const int size = value.GetCachedSize();
+  output->WriteVarint32(size);
+  WriteSubMessageMaybeToArray(size, value, output);
+}
+
+PROTOBUF_NDEBUG_INLINE static bool ReadBytesToString(
+    io::CodedInputStream* input, std::string* value);
+inline static bool ReadBytesToString(io::CodedInputStream* input,
+                                     std::string* value) {
+  uint32_t length;
+  return input->ReadVarint32(&length) && input->ReadString(value, length);
+}
+
+bool WireFormatLite::ReadBytes(io::CodedInputStream* input,
+                               std::string* value) {
+  return ReadBytesToString(input, value);
+}
+
+bool WireFormatLite::ReadBytes(io::CodedInputStream* input, std::string** p) {
+  if (*p == &GetEmptyStringAlreadyInited()) {
+    *p = new std::string();
+  }
+  return ReadBytesToString(input, *p);
+}
+
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
+                       bool emit_stacktrace) {
+  std::string stacktrace;
+  (void)emit_stacktrace;  // Parameter is used by Google-internal code.
+  std::string quoted_field_name = "";
+  if (!field_name.empty()) {
+    if (!message_name.empty()) {
+      quoted_field_name =
+          StrCat(" '", message_name, ".", field_name, "'");
+    } else {
+      quoted_field_name = StrCat(" '", field_name, "'");
+    }
+  }
+  std::string error_message =
+      StrCat("String field", quoted_field_name,
+                   " contains invalid UTF-8 data "
+                   "when ",
+                   operation_str,
+                   " a protocol buffer. Use the 'bytes' type if you intend to "
+                   "send raw bytes. ",
+                   stacktrace);
+  GOOGLE_LOG(ERROR) << error_message;
+}
+
+bool WireFormatLite::VerifyUtf8String(const char* data, int size, Operation op,
+                                      const char* field_name) {
+  if (!IsStructurallyValidUTF8(data, size)) {
+    const char* operation_str = nullptr;
+    switch (op) {
+      case PARSE:
+        operation_str = "parsing";
+        break;
+      case SERIALIZE:
+        operation_str = "serializing";
+        break;
+        // no default case: have the compiler warn if a case is not covered.
+    }
+    PrintUTF8ErrorLog("", field_name, operation_str, false);
+    return false;
+  }
+  return true;
+}
+
+// this code is deliberately written such that clang makes it into really
+// efficient SSE code.
+template <bool ZigZag, bool SignExtended, typename T>
+static size_t VarintSize(const T* data, const int n) {
+  static_assert(sizeof(T) == 4, "This routine only works for 32 bit integers");
+  // is_unsigned<T> => !ZigZag
+  static_assert(
+      (std::is_unsigned<T>::value ^ ZigZag) || std::is_signed<T>::value,
+      "Cannot ZigZag encode unsigned types");
+  // is_unsigned<T> => !SignExtended
+  static_assert(
+      (std::is_unsigned<T>::value ^ SignExtended) || std::is_signed<T>::value,
+      "Cannot SignExtended unsigned types");
+  static_assert(!(SignExtended && ZigZag),
+                "Cannot SignExtended and ZigZag on the same type");
+  uint32_t sum = n;
+  uint32_t msb_sum = 0;
+  for (int i = 0; i < n; i++) {
+    uint32_t x = data[i];
+    if (ZigZag) {
+      x = WireFormatLite::ZigZagEncode32(x);
+    } else if (SignExtended) {
+      msb_sum += x >> 31;
+    }
+    // clang is so smart that it produces optimal SSE sequence unrolling
+    // the loop 8 ints at a time. With a sequence of 4
+    // cmpres = cmpgt x, sizeclass  ( -1 or 0)
+    // sum = sum - cmpres
+    if (x > 0x7F) sum++;
+    if (x > 0x3FFF) sum++;
+    if (x > 0x1FFFFF) sum++;
+    if (x > 0xFFFFFFF) sum++;
+  }
+  if (SignExtended) sum += msb_sum * 5;
+  return sum;
+}
+
+template <bool ZigZag, typename T>
+static size_t VarintSize64(const T* data, const int n) {
+  static_assert(sizeof(T) == 8, "This routine only works for 64 bit integers");
+  // is_unsigned<T> => !ZigZag
+  static_assert(!ZigZag || !std::is_unsigned<T>::value,
+                "Cannot ZigZag encode unsigned types");
+  uint64_t sum = n;
+  for (int i = 0; i < n; i++) {
+    uint64_t x = data[i];
+    if (ZigZag) {
+      x = WireFormatLite::ZigZagEncode64(x);
+    }
+    // First step is a binary search, we can't branch in sse so we use the
+    // result of the compare to adjust sum and appropriately. This code is
+    // written to make clang recognize the vectorization.
+    uint64_t tmp = x >= (static_cast<uint64_t>(1) << 35) ? -1 : 0;
+    sum += 5 & tmp;
+    x >>= 35 & tmp;
+    if (x > 0x7F) sum++;
+    if (x > 0x3FFF) sum++;
+    if (x > 0x1FFFFF) sum++;
+    if (x > 0xFFFFFFF) sum++;
+  }
+  return sum;
+}
+
+// GCC does not recognize the vectorization opportunity
+// and other platforms are untested, in those cases using the optimized
+// varint size routine for each element is faster.
+// Hence we enable it only for clang
+#if defined(__SSE__) && defined(__clang__)
+size_t WireFormatLite::Int32Size(const RepeatedField<int32_t>& value) {
+  return VarintSize<false, true>(value.data(), value.size());
+}
+
+size_t WireFormatLite::UInt32Size(const RepeatedField<uint32_t>& value) {
+  return VarintSize<false, false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::SInt32Size(const RepeatedField<int32_t>& value) {
+  return VarintSize<true, false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::EnumSize(const RepeatedField<int>& value) {
+  // On ILP64, sizeof(int) == 8, which would require a different template.
+  return VarintSize<false, true>(value.data(), value.size());
+}
+
+#else  // !(defined(__SSE4_1__) && defined(__clang__))
+
+size_t WireFormatLite::Int32Size(const RepeatedField<int32_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += Int32Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::UInt32Size(const RepeatedField<uint32_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += UInt32Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::SInt32Size(const RepeatedField<int32_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += SInt32Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::EnumSize(const RepeatedField<int>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += EnumSize(value.Get(i));
+  }
+  return out;
+}
+
+#endif
+
+// Micro benchmarks show that the SSE improved loop only starts beating
+// the normal loop on Haswell platforms and then only for >32 ints. We
+// disable this for now. Some specialized users might find it worthwhile to
+// enable this.
+#define USE_SSE_FOR_64_BIT_INTEGER_ARRAYS 0
+#if USE_SSE_FOR_64_BIT_INTEGER_ARRAYS
+size_t WireFormatLite::Int64Size(const RepeatedField<int64_t>& value) {
+  return VarintSize64<false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::UInt64Size(const RepeatedField<uint64_t>& value) {
+  return VarintSize64<false>(value.data(), value.size());
+}
+
+size_t WireFormatLite::SInt64Size(const RepeatedField<int64_t>& value) {
+  return VarintSize64<true>(value.data(), value.size());
+}
+
+#else
+
+size_t WireFormatLite::Int64Size(const RepeatedField<int64_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += Int64Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::UInt64Size(const RepeatedField<uint64_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += UInt64Size(value.Get(i));
+  }
+  return out;
+}
+
+size_t WireFormatLite::SInt64Size(const RepeatedField<int64_t>& value) {
+  size_t out = 0;
+  const int n = value.size();
+  for (int i = 0; i < n; i++) {
+    out += SInt64Size(value.Get(i));
+  }
+  return out;
+}
+
+#endif
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/thirdparty/protobuf/src/wrappers.pb.cpp b/wpiutil/src/main/native/thirdparty/protobuf/src/wrappers.pb.cpp
new file mode 100644
index 0000000..40ba60a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/protobuf/src/wrappers.pb.cpp
@@ -0,0 +1,1979 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#include <google/protobuf/wrappers.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+PROTOBUF_NAMESPACE_OPEN
+PROTOBUF_CONSTEXPR DoubleValue::DoubleValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct DoubleValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR DoubleValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~DoubleValueDefaultTypeInternal() {}
+  union {
+    DoubleValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DoubleValueDefaultTypeInternal _DoubleValue_default_instance_;
+PROTOBUF_CONSTEXPR FloatValue::FloatValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct FloatValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR FloatValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~FloatValueDefaultTypeInternal() {}
+  union {
+    FloatValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FloatValueDefaultTypeInternal _FloatValue_default_instance_;
+PROTOBUF_CONSTEXPR Int64Value::Int64Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/int64_t{0}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct Int64ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR Int64ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~Int64ValueDefaultTypeInternal() {}
+  union {
+    Int64Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Int64ValueDefaultTypeInternal _Int64Value_default_instance_;
+PROTOBUF_CONSTEXPR UInt64Value::UInt64Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/uint64_t{0u}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct UInt64ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UInt64ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UInt64ValueDefaultTypeInternal() {}
+  union {
+    UInt64Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UInt64ValueDefaultTypeInternal _UInt64Value_default_instance_;
+PROTOBUF_CONSTEXPR Int32Value::Int32Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct Int32ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR Int32ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~Int32ValueDefaultTypeInternal() {}
+  union {
+    Int32Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Int32ValueDefaultTypeInternal _Int32Value_default_instance_;
+PROTOBUF_CONSTEXPR UInt32Value::UInt32Value(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/0u
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct UInt32ValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR UInt32ValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~UInt32ValueDefaultTypeInternal() {}
+  union {
+    UInt32Value _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UInt32ValueDefaultTypeInternal _UInt32Value_default_instance_;
+PROTOBUF_CONSTEXPR BoolValue::BoolValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/false
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct BoolValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR BoolValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~BoolValueDefaultTypeInternal() {}
+  union {
+    BoolValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 BoolValueDefaultTypeInternal _BoolValue_default_instance_;
+PROTOBUF_CONSTEXPR StringValue::StringValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct StringValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR StringValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~StringValueDefaultTypeInternal() {}
+  union {
+    StringValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StringValueDefaultTypeInternal _StringValue_default_instance_;
+PROTOBUF_CONSTEXPR BytesValue::BytesValue(
+    ::_pbi::ConstantInitialized): _impl_{
+    /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
+  , /*decltype(_impl_._cached_size_)*/{}} {}
+struct BytesValueDefaultTypeInternal {
+  PROTOBUF_CONSTEXPR BytesValueDefaultTypeInternal()
+      : _instance(::_pbi::ConstantInitialized{}) {}
+  ~BytesValueDefaultTypeInternal() {}
+  union {
+    BytesValue _instance;
+  };
+};
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 BytesValueDefaultTypeInternal _BytesValue_default_instance_;
+PROTOBUF_NAMESPACE_CLOSE
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[9];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+
+const uint32_t TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DoubleValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::DoubleValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FloatValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FloatValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int64Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int64Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt64Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt64Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int32Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Int32Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt32Value, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::UInt32Value, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BoolValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BoolValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::StringValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::StringValue, _impl_.value_),
+  ~0u,  // no _has_bits_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BytesValue, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  ~0u,  // no _inlined_string_donated_
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BytesValue, _impl_.value_),
+};
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DoubleValue)},
+  { 7, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FloatValue)},
+  { 14, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Int64Value)},
+  { 21, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UInt64Value)},
+  { 28, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Int32Value)},
+  { 35, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UInt32Value)},
+  { 42, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::BoolValue)},
+  { 49, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::StringValue)},
+  { 56, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::BytesValue)},
+};
+
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_DoubleValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FloatValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Int64Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UInt64Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Int32Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UInt32Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_BoolValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_StringValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_BytesValue_default_instance_._instance,
+};
+
+const char descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
+  "\n\036google/protobuf/wrappers.proto\022\017google"
+  ".protobuf\"\034\n\013DoubleValue\022\r\n\005value\030\001 \001(\001\""
+  "\033\n\nFloatValue\022\r\n\005value\030\001 \001(\002\"\033\n\nInt64Val"
+  "ue\022\r\n\005value\030\001 \001(\003\"\034\n\013UInt64Value\022\r\n\005valu"
+  "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013"
+  "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022"
+  "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001"
+  " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014B\203\001\n\023co"
+  "m.google.protobufB\rWrappersProtoP\001Z1goog"
+  "le.golang.org/protobuf/types/known/wrapp"
+  "erspb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKno"
+  "wnTypesb\006proto3"
+  ;
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
+    false, false, 455, descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto,
+    "google/protobuf/wrappers.proto",
+    &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once, nullptr, 0, 9,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
+};
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter() {
+  return &descriptor_table_google_2fprotobuf_2fwrappers_2eproto;
+}
+
+// Force running AddDescriptors() at dynamic initialization time.
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fwrappers_2eproto(&descriptor_table_google_2fprotobuf_2fwrappers_2eproto);
+PROTOBUF_NAMESPACE_OPEN
+
+// ===================================================================
+
+class DoubleValue::_Internal {
+ public:
+};
+
+DoubleValue::DoubleValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue)
+}
+DoubleValue::DoubleValue(const DoubleValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  DoubleValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DoubleValue)
+}
+
+inline void DoubleValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+DoubleValue::~DoubleValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DoubleValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void DoubleValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void DoubleValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void DoubleValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DoubleValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* DoubleValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // double value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 9)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<double>(ptr);
+          ptr += sizeof(double);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* DoubleValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DoubleValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // double value = 1;
+  static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
+  double tmp_value = this->_internal_value();
+  uint64_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DoubleValue)
+  return target;
+}
+
+size_t DoubleValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DoubleValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // double value = 1;
+  static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
+  double tmp_value = this->_internal_value();
+  uint64_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    total_size += 1 + 8;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData DoubleValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    DoubleValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DoubleValue::GetClassData() const { return &_class_data_; }
+
+
+void DoubleValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<DoubleValue*>(&to_msg);
+  auto& from = static_cast<const DoubleValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DoubleValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
+  double tmp_value = from._internal_value();
+  uint64_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void DoubleValue::CopyFrom(const DoubleValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DoubleValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DoubleValue::IsInitialized() const {
+  return true;
+}
+
+void DoubleValue::InternalSwap(DoubleValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata DoubleValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[0]);
+}
+
+// ===================================================================
+
+class FloatValue::_Internal {
+ public:
+};
+
+FloatValue::FloatValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue)
+}
+FloatValue::FloatValue(const FloatValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  FloatValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FloatValue)
+}
+
+inline void FloatValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+FloatValue::~FloatValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FloatValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void FloatValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void FloatValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void FloatValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FloatValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* FloatValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // float value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 13)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(ptr);
+          ptr += sizeof(float);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* FloatValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FloatValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // float value = 1;
+  static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
+  float tmp_value = this->_internal_value();
+  uint32_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteFloatToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FloatValue)
+  return target;
+}
+
+size_t FloatValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FloatValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // float value = 1;
+  static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
+  float tmp_value = this->_internal_value();
+  uint32_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    total_size += 1 + 4;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData FloatValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    FloatValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FloatValue::GetClassData() const { return &_class_data_; }
+
+
+void FloatValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<FloatValue*>(&to_msg);
+  auto& from = static_cast<const FloatValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FloatValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
+  float tmp_value = from._internal_value();
+  uint32_t raw_value;
+  memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
+  if (raw_value != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void FloatValue::CopyFrom(const FloatValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FloatValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FloatValue::IsInitialized() const {
+  return true;
+}
+
+void FloatValue::InternalSwap(FloatValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata FloatValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[1]);
+}
+
+// ===================================================================
+
+class Int64Value::_Internal {
+ public:
+};
+
+Int64Value::Int64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value)
+}
+Int64Value::Int64Value(const Int64Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Int64Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Int64Value)
+}
+
+inline void Int64Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){int64_t{0}}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Int64Value::~Int64Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Int64Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Int64Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Int64Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Int64Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Int64Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = int64_t{0};
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Int64Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int64 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Int64Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int64Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int64 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int64Value)
+  return target;
+}
+
+size_t Int64Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int64Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int64 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Int64Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Int64Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Int64Value::GetClassData() const { return &_class_data_; }
+
+
+void Int64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Int64Value*>(&to_msg);
+  auto& from = static_cast<const Int64Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int64Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Int64Value::CopyFrom(const Int64Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Int64Value::IsInitialized() const {
+  return true;
+}
+
+void Int64Value::InternalSwap(Int64Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Int64Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[2]);
+}
+
+// ===================================================================
+
+class UInt64Value::_Internal {
+ public:
+};
+
+UInt64Value::UInt64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value)
+}
+UInt64Value::UInt64Value(const UInt64Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UInt64Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UInt64Value)
+}
+
+inline void UInt64Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){uint64_t{0u}}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+UInt64Value::~UInt64Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UInt64Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UInt64Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void UInt64Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UInt64Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt64Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = uint64_t{0u};
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UInt64Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // uint64 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UInt64Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt64Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint64 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt64Value)
+  return target;
+}
+
+size_t UInt64Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt64Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // uint64 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UInt64Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UInt64Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UInt64Value::GetClassData() const { return &_class_data_; }
+
+
+void UInt64Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UInt64Value*>(&to_msg);
+  auto& from = static_cast<const UInt64Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt64Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UInt64Value::CopyFrom(const UInt64Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UInt64Value::IsInitialized() const {
+  return true;
+}
+
+void UInt64Value::InternalSwap(UInt64Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UInt64Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[3]);
+}
+
+// ===================================================================
+
+class Int32Value::_Internal {
+ public:
+};
+
+Int32Value::Int32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value)
+}
+Int32Value::Int32Value(const Int32Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  Int32Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Int32Value)
+}
+
+inline void Int32Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+Int32Value::~Int32Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Int32Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void Int32Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void Int32Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void Int32Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Int32Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* Int32Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // int32 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* Int32Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int32Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // int32 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int32Value)
+  return target;
+}
+
+size_t Int32Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int32Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // int32 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Int32Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    Int32Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Int32Value::GetClassData() const { return &_class_data_; }
+
+
+void Int32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<Int32Value*>(&to_msg);
+  auto& from = static_cast<const Int32Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int32Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void Int32Value::CopyFrom(const Int32Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Int32Value::IsInitialized() const {
+  return true;
+}
+
+void Int32Value::InternalSwap(Int32Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata Int32Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[4]);
+}
+
+// ===================================================================
+
+class UInt32Value::_Internal {
+ public:
+};
+
+UInt32Value::UInt32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value)
+}
+UInt32Value::UInt32Value(const UInt32Value& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  UInt32Value* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UInt32Value)
+}
+
+inline void UInt32Value::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){0u}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+UInt32Value::~UInt32Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UInt32Value)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void UInt32Value::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void UInt32Value::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void UInt32Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt32Value)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = 0u;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* UInt32Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // uint32 value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* UInt32Value::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt32Value)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint32 value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteUInt32ToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt32Value)
+  return target;
+}
+
+size_t UInt32Value::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt32Value)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // uint32 value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += ::_pbi::WireFormatLite::UInt32SizePlusOne(this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData UInt32Value::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    UInt32Value::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UInt32Value::GetClassData() const { return &_class_data_; }
+
+
+void UInt32Value::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<UInt32Value*>(&to_msg);
+  auto& from = static_cast<const UInt32Value&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt32Value)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void UInt32Value::CopyFrom(const UInt32Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UInt32Value::IsInitialized() const {
+  return true;
+}
+
+void UInt32Value::InternalSwap(UInt32Value* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata UInt32Value::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[5]);
+}
+
+// ===================================================================
+
+class BoolValue::_Internal {
+ public:
+};
+
+BoolValue::BoolValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue)
+}
+BoolValue::BoolValue(const BoolValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  BoolValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _this->_impl_.value_ = from._impl_.value_;
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.BoolValue)
+}
+
+inline void BoolValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){false}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+}
+
+BoolValue::~BoolValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.BoolValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void BoolValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+}
+
+void BoolValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void BoolValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.BoolValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_ = false;
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* BoolValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // bool value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 8)) {
+          _impl_.value_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* BoolValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BoolValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // bool value = 1;
+  if (this->_internal_value() != 0) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BoolValue)
+  return target;
+}
+
+size_t BoolValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BoolValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // bool value = 1;
+  if (this->_internal_value() != 0) {
+    total_size += 1 + 1;
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData BoolValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    BoolValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*BoolValue::GetClassData() const { return &_class_data_; }
+
+
+void BoolValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<BoolValue*>(&to_msg);
+  auto& from = static_cast<const BoolValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BoolValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from._internal_value() != 0) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void BoolValue::CopyFrom(const BoolValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BoolValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool BoolValue::IsInitialized() const {
+  return true;
+}
+
+void BoolValue::InternalSwap(BoolValue* other) {
+  using std::swap;
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  swap(_impl_.value_, other->_impl_.value_);
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata BoolValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[6]);
+}
+
+// ===================================================================
+
+class StringValue::_Internal {
+ public:
+};
+
+StringValue::StringValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue)
+}
+StringValue::StringValue(const StringValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  StringValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_value().empty()) {
+    _this->_impl_.value_.Set(from._internal_value(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.StringValue)
+}
+
+inline void StringValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+StringValue::~StringValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.StringValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void StringValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.value_.Destroy();
+}
+
+void StringValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void StringValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.StringValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* StringValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // string value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.StringValue.value"));
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* StringValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // string value = 1;
+  if (!this->_internal_value().empty()) {
+    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+      this->_internal_value().data(), static_cast<int>(this->_internal_value().length()),
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.StringValue.value");
+    target = stream->WriteStringMaybeAliased(
+        1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.StringValue)
+  return target;
+}
+
+size_t StringValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.StringValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // string value = 1;
+  if (!this->_internal_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+        this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData StringValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    StringValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*StringValue::GetClassData() const { return &_class_data_; }
+
+
+void StringValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<StringValue*>(&to_msg);
+  auto& from = static_cast<const StringValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.StringValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_value().empty()) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void StringValue::CopyFrom(const StringValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.StringValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool StringValue::IsInitialized() const {
+  return true;
+}
+
+void StringValue::InternalSwap(StringValue* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.value_, lhs_arena,
+      &other->_impl_.value_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata StringValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[7]);
+}
+
+// ===================================================================
+
+class BytesValue::_Internal {
+ public:
+};
+
+BytesValue::BytesValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
+                         bool is_message_owned)
+  : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
+  SharedCtor(arena, is_message_owned);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue)
+}
+BytesValue::BytesValue(const BytesValue& from)
+  : ::PROTOBUF_NAMESPACE_ID::Message() {
+  BytesValue* const _this = this; (void)_this;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}};
+
+  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+  if (!from._internal_value().empty()) {
+    _this->_impl_.value_.Set(from._internal_value(), 
+      _this->GetArenaForAllocation());
+  }
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.BytesValue)
+}
+
+inline void BytesValue::SharedCtor(
+    ::_pb::Arena* arena, bool is_message_owned) {
+  (void)arena;
+  (void)is_message_owned;
+  new (&_impl_) Impl_{
+      decltype(_impl_.value_){}
+    , /*decltype(_impl_._cached_size_)*/{}
+  };
+  _impl_.value_.InitDefault();
+  #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+    _impl_.value_.Set("", GetArenaForAllocation());
+  #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+}
+
+BytesValue::~BytesValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.BytesValue)
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
+  SharedDtor();
+}
+
+inline void BytesValue::SharedDtor() {
+  GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  _impl_.value_.Destroy();
+}
+
+void BytesValue::SetCachedSize(int size) const {
+  _impl_._cached_size_.Set(size);
+}
+
+void BytesValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.BytesValue)
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  _impl_.value_.ClearToEmpty();
+  _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+}
+
+const char* BytesValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
+#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
+  while (!ctx->Done(&ptr)) {
+    uint32_t tag;
+    ptr = ::_pbi::ReadTag(ptr, &tag);
+    switch (tag >> 3) {
+      // bytes value = 1;
+      case 1:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
+          auto str = _internal_mutable_value();
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
+      default:
+        goto handle_unusual;
+    }  // switch
+  handle_unusual:
+    if ((tag == 0) || ((tag & 7) == 4)) {
+      CHK_(ptr);
+      ctx->SetLastTag(tag);
+      goto message_done;
+    }
+    ptr = UnknownFieldParse(
+        tag,
+        _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
+        ptr, ctx);
+    CHK_(ptr != nullptr);
+  }  // while
+message_done:
+  return ptr;
+failure:
+  ptr = nullptr;
+  goto message_done;
+#undef CHK_
+}
+
+uint8_t* BytesValue::_InternalSerialize(
+    uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BytesValue)
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // bytes value = 1;
+  if (!this->_internal_value().empty()) {
+    target = stream->WriteBytesMaybeAliased(
+        1, this->_internal_value(), target);
+  }
+
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BytesValue)
+  return target;
+}
+
+size_t BytesValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BytesValue)
+  size_t total_size = 0;
+
+  uint32_t cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  // bytes value = 1;
+  if (!this->_internal_value().empty()) {
+    total_size += 1 +
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
+        this->_internal_value());
+  }
+
+  return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
+}
+
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData BytesValue::_class_data_ = {
+    ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
+    BytesValue::MergeImpl
+};
+const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*BytesValue::GetClassData() const { return &_class_data_; }
+
+
+void BytesValue::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
+  auto* const _this = static_cast<BytesValue*>(&to_msg);
+  auto& from = static_cast<const BytesValue&>(from_msg);
+  // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BytesValue)
+  GOOGLE_DCHECK_NE(&from, _this);
+  uint32_t cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (!from._internal_value().empty()) {
+    _this->_internal_set_value(from._internal_value());
+  }
+  _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
+}
+
+void BytesValue::CopyFrom(const BytesValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BytesValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool BytesValue::IsInitialized() const {
+  return true;
+}
+
+void BytesValue::InternalSwap(BytesValue* other) {
+  using std::swap;
+  auto* lhs_arena = GetArenaForAllocation();
+  auto* rhs_arena = other->GetArenaForAllocation();
+  _internal_metadata_.InternalSwap(&other->_internal_metadata_);
+  ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
+      &_impl_.value_, lhs_arena,
+      &other->_impl_.value_, rhs_arena
+  );
+}
+
+::PROTOBUF_NAMESPACE_ID::Metadata BytesValue::GetMetadata() const {
+  return ::_pbi::AssignDescriptors(
+      &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
+      file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[8]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+PROTOBUF_NAMESPACE_CLOSE
+PROTOBUF_NAMESPACE_OPEN
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DoubleValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FloatValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FloatValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FloatValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int64Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int64Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Int64Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt64Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int32Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int32Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Int32Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt32Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BoolValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BoolValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::BoolValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::StringValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::StringValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::StringValue >(arena);
+}
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BytesValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BytesValue >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::BytesValue >(arena);
+}
+PROTOBUF_NAMESPACE_CLOSE
+
+// @@protoc_insertion_point(global_scope)
+#include <google/protobuf/port_undef.inc>
diff --git a/wpiutil/src/main/native/windows/StackTrace.cpp b/wpiutil/src/main/native/windows/StackTrace.cpp
index de31b2a..5df8a6a 100644
--- a/wpiutil/src/main/native/windows/StackTrace.cpp
+++ b/wpiutil/src/main/native/windows/StackTrace.cpp
@@ -23,13 +23,7 @@
 }  // namespace
 
 void StackTraceWalker::OnOutput(LPCTSTR szText) {
-#ifdef _UNICODE
-  wpi::SmallString<128> utf8;
-  wpi::sys::windows::UTF16ToUTF8(szText, wcslen(szText), utf8);
-  m_output.append(utf8.data(), utf8.size());
-#else
   m_output.append(szText);
-#endif
 }
 
 namespace wpi {
diff --git a/wpiutil/src/main/native/windows/StackWalker.cpp b/wpiutil/src/main/native/windows/StackWalker.cpp
index 6f0fbf2..b2bcbaa 100644
--- a/wpiutil/src/main/native/windows/StackWalker.cpp
+++ b/wpiutil/src/main/native/windows/StackWalker.cpp
@@ -1,4 +1,4 @@
-/**********************************************************************
+/**********************************************************************
  *
  * StackWalker.cpp
  * https://github.com/JochenKalmbach/StackWalker
@@ -87,76 +87,209 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <tchar.h>
+#include <windows.h>
+#include <new>
+
 #pragma comment(lib, "version.lib") // for "VerQueryValue"
 #pragma comment(lib, "Advapi32.lib") // for "GetUserName"
+
 #pragma warning(disable : 4826)
-
-#ifdef UNICODE
-  #define DBGHELP_TRANSLATE_TCHAR
-
+#if _MSC_VER >= 1900
+#pragma warning(disable : 4091)   // For fix unnamed enums from DbgHelp.h
 #endif
+
+
+// If VC7 and later, then use the shipped 'dbghelp.h'-file
 #pragma pack(push, 8)
+#if _MSC_VER >= 1300
 #include <dbghelp.h>
+#else
+// inline the important dbghelp.h-declarations...
+typedef enum
+{
+  SymNone = 0,
+  SymCoff,
+  SymCv,
+  SymPdb,
+  SymExport,
+  SymDeferred,
+  SymSym,
+  SymDia,
+  SymVirtual,
+  NumSymTypes
+} SYM_TYPE;
+typedef struct _IMAGEHLP_LINE64
+{
+  DWORD   SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64)
+  PVOID   Key;          // internal
+  DWORD   LineNumber;   // line number in file
+  PCHAR   FileName;     // full filename
+  DWORD64 Address;      // first instruction of line
+} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
+typedef struct _IMAGEHLP_MODULE64
+{
+  DWORD    SizeOfStruct;         // set to sizeof(IMAGEHLP_MODULE64)
+  DWORD64  BaseOfImage;          // base load address of module
+  DWORD    ImageSize;            // virtual size of the loaded module
+  DWORD    TimeDateStamp;        // date/time stamp from pe header
+  DWORD    CheckSum;             // checksum from the pe header
+  DWORD    NumSyms;              // number of symbols in the symbol table
+  SYM_TYPE SymType;              // type of symbols loaded
+  CHAR     ModuleName[32];       // module name
+  CHAR     ImageName[256];       // image name
+  CHAR     LoadedImageName[256]; // symbol file name
+} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
+typedef struct _IMAGEHLP_SYMBOL64
+{
+  DWORD   SizeOfStruct;  // set to sizeof(IMAGEHLP_SYMBOL64)
+  DWORD64 Address;       // virtual address including dll base address
+  DWORD   Size;          // estimated size of symbol, can be zero
+  DWORD   Flags;         // info about the symbols, see the SYMF defines
+  DWORD   MaxNameLength; // maximum size of symbol name in 'Name'
+  CHAR    Name[1];       // symbol name (null terminated string)
+} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
+typedef enum
+{
+  AddrMode1616,
+  AddrMode1632,
+  AddrModeReal,
+  AddrModeFlat
+} ADDRESS_MODE;
+typedef struct _tagADDRESS64
+{
+  DWORD64      Offset;
+  WORD         Segment;
+  ADDRESS_MODE Mode;
+} ADDRESS64, *LPADDRESS64;
+typedef struct _KDHELP64
+{
+  DWORD64 Thread;
+  DWORD   ThCallbackStack;
+  DWORD   ThCallbackBStore;
+  DWORD   NextCallback;
+  DWORD   FramePointer;
+  DWORD64 KiCallUserMode;
+  DWORD64 KeUserCallbackDispatcher;
+  DWORD64 SystemRangeStart;
+  DWORD64 Reserved[8];
+} KDHELP64, *PKDHELP64;
+typedef struct _tagSTACKFRAME64
+{
+  ADDRESS64 AddrPC;         // program counter
+  ADDRESS64 AddrReturn;     // return address
+  ADDRESS64 AddrFrame;      // frame pointer
+  ADDRESS64 AddrStack;      // stack pointer
+  ADDRESS64 AddrBStore;     // backing store pointer
+  PVOID     FuncTableEntry; // pointer to pdata/fpo or NULL
+  DWORD64   Params[4];      // possible arguments to the function
+  BOOL      Far;            // WOW far call
+  BOOL      Virtual;        // is this a virtual frame?
+  DWORD64   Reserved[3];
+  KDHELP64  KdHelp;
+} STACKFRAME64, *LPSTACKFRAME64;
+typedef BOOL(__stdcall* PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE  hProcess,
+                                                        DWORD64 qwBaseAddress,
+                                                        PVOID   lpBuffer,
+                                                        DWORD   nSize,
+                                                        LPDWORD lpNumberOfBytesRead);
+typedef PVOID(__stdcall* PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE hProcess, DWORD64 AddrBase);
+typedef DWORD64(__stdcall* PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address);
+typedef DWORD64(__stdcall* PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE      hProcess,
+                                                         HANDLE      hThread,
+                                                         LPADDRESS64 lpaddr);
+
+// clang-format off
+#define SYMOPT_CASE_INSENSITIVE         0x00000001
+#define SYMOPT_UNDNAME                  0x00000002
+#define SYMOPT_DEFERRED_LOADS           0x00000004
+#define SYMOPT_NO_CPP                   0x00000008
+#define SYMOPT_LOAD_LINES               0x00000010
+#define SYMOPT_OMAP_FIND_NEAREST        0x00000020
+#define SYMOPT_LOAD_ANYTHING            0x00000040
+#define SYMOPT_IGNORE_CVREC             0x00000080
+#define SYMOPT_NO_UNQUALIFIED_LOADS     0x00000100
+#define SYMOPT_FAIL_CRITICAL_ERRORS     0x00000200
+#define SYMOPT_EXACT_SYMBOLS            0x00000400
+#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS   0x00000800
+#define SYMOPT_IGNORE_NT_SYMPATH        0x00001000
+#define SYMOPT_INCLUDE_32BIT_MODULES    0x00002000
+#define SYMOPT_PUBLICS_ONLY             0x00004000
+#define SYMOPT_NO_PUBLICS               0x00008000
+#define SYMOPT_AUTO_PUBLICS             0x00010000
+#define SYMOPT_NO_IMAGE_SEARCH          0x00020000
+#define SYMOPT_SECURE                   0x00040000
+#define SYMOPT_DEBUG                    0x80000000
+#define UNDNAME_COMPLETE                 (0x0000) // Enable full undecoration
+#define UNDNAME_NAME_ONLY                (0x1000) // Crack only the name for primary declaration;
+// clang-format on
+
+#endif // _MSC_VER < 1300
 #pragma pack(pop)
 
+// Some missing defines (for VC5/6):
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
 
-static void MyStrCpy(TCHAR* szDest, size_t nMaxDestSize, const TCHAR* szSrc)
+// secure-CRT_functions are only available starting with VC8
+#if _MSC_VER < 1400
+#define strcpy_s(dst, len, src) strcpy(dst, src)
+#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)
+#define strcat_s(dst, len, src) strcat(dst, src)
+#define _snprintf_s _snprintf
+#define _tcscat_s _tcscat
+#endif
+
+static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
 {
   if (nMaxDestSize <= 0)
     return;
-  _tcsncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
+  strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
   // INFO: _TRUNCATE will ensure that it is null-terminated;
   // but with older compilers (<1400) it uses "strncpy" and this does not!)
   szDest[nMaxDestSize - 1] = 0;
 } // MyStrCpy
 
-#ifdef _UNICODE
-  typedef SYMBOL_INFOW   tSymbolInfo;
-  typedef IMAGEHLP_LINEW64  tImageHelperLine;
-#else
-  typedef SYMBOL_INFO   tSymbolInfo;
-  typedef IMAGEHLP_LINE64  tImageHelperLine;
-#endif
-
 // Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
 #define USED_CONTEXT_FLAGS CONTEXT_FULL
 
 class StackWalkerInternal
 {
 public:
-  StackWalkerInternal(StackWalker* parent, HANDLE hProcess)
+  StackWalkerInternal(StackWalker* parent, HANDLE hProcess, PCONTEXT ctx)
   {
     m_parent = parent;
     m_hDbhHelp = NULL;
-    symCleanup = NULL;
+    pSC = NULL;
     m_hProcess = hProcess;
-    m_szSymPath = NULL;
-    symFunctionTableAccess64 = NULL;
-    symGetLineFromAddr64 = NULL;
-    symGetModuleBase64 = NULL;
-    symGetModuleInfo64 = NULL;
-    symGetOptions = NULL;
-    symFromAddr = NULL;
-    symInitialize = NULL;
-    symLoadModuleEx = NULL;
-    symSetOptions = NULL;
-    stackWalk64 = NULL;
-    unDecorateSymbolName = NULL;
-    symGetSearchPath = NULL;
+    pSFTA = NULL;
+    pSGLFA = NULL;
+    pSGMB = NULL;
+    pSGMI = NULL;
+    pSGO = NULL;
+    pSGSFA = NULL;
+    pSI = NULL;
+    pSLM = NULL;
+    pSSO = NULL;
+    pSW = NULL;
+    pUDSN = NULL;
+    pSGSP = NULL;
+    m_ctx.ContextFlags = 0;
+    if (ctx != NULL)
+      m_ctx = *ctx;
   }
+
   ~StackWalkerInternal()
   {
-    if (symCleanup != NULL)
-      symCleanup(m_hProcess); // SymCleanup
+    if (pSC != NULL)
+      pSC(m_hProcess); // SymCleanup
     if (m_hDbhHelp != NULL)
       FreeLibrary(m_hDbhHelp);
     m_hDbhHelp = NULL;
     m_parent = NULL;
-    if (m_szSymPath != NULL)
-      free(m_szSymPath);
-    m_szSymPath = NULL;
   }
-  BOOL Init(LPCTSTR szSymPath)
+
+  BOOL Init(LPCSTR szSymPath)
   {
     if (m_parent == NULL)
       return FALSE;
@@ -229,72 +362,52 @@
       m_hDbhHelp = LoadLibrary(_T("dbghelp.dll"));
     if (m_hDbhHelp == NULL)
       return FALSE;
+    pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize");
+    pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup");
 
-#ifdef _UNICODE
-    static const char strSymInitialize[] = "SymInitializeW";
-    static const char strUnDecorateSymbolName[] = "UnDecorateSymbolNameW";
-    static const char strSymGetSearchPath[] = "SymGetSearchPathW";
-    static const char strSymLoadModuleEx[] = "SymLoadModuleExW";
-    static const char strSymGetLineFromAddr64[] = "SymGetLineFromAddrW64";
-    static const char strSymGetModuleInfo64[] = "SymGetModuleInfoW64";
-    static const char strSymFromAddr[] = "SymFromAddrW";
-#else
-    static const char strSymInitialize[] = "SymInitialize";
-    static const char strUnDecorateSymbolName[] = "UnDecorateSymbolName";
-    static const char strSymGetSearchPath[] = "SymGetSearchPath";
-    static const char strSymLoadModuleEx[] = "SymLoadModuleEx";
-    static const char strSymGetLineFromAddr64[] = "SymGetLineFromAddr64";
-    static const char strSymGetModuleInfo64[] = "SymGetModuleInfo64";
-    static const char strSymFromAddr[] = "SymFromAddr";
-#endif
-    symInitialize = (tSI)GetProcAddress(m_hDbhHelp, strSymInitialize);
-    symCleanup = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup");
+    pSW = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64");
+    pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions");
+    pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions");
 
-    stackWalk64 = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64");
-    symGetOptions = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions");
-    symSetOptions = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions");
+    pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64");
+    pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64");
+    pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64");
+    pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64");
+    pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64");
+    pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName");
+    pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64");
+    pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath");
 
-    symFunctionTableAccess64 = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64");
-    symGetLineFromAddr64 = (tSGLFA)GetProcAddress(m_hDbhHelp, strSymGetLineFromAddr64);
-    symGetModuleBase64 = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64");
-    symGetModuleInfo64 = (tSGMI)GetProcAddress(m_hDbhHelp, strSymGetModuleInfo64);
-    symFromAddr = (tSFA)GetProcAddress(m_hDbhHelp, strSymFromAddr);
-    unDecorateSymbolName = (tUDSN)GetProcAddress(m_hDbhHelp, strUnDecorateSymbolName);
-    symLoadModuleEx = (tSLM)GetProcAddress(m_hDbhHelp, strSymLoadModuleEx);
-    symGetSearchPath = (tSGSP)GetProcAddress(m_hDbhHelp, strSymGetSearchPath);
-
-    if (symCleanup == NULL || symFunctionTableAccess64 == NULL || symGetModuleBase64 == NULL || symGetModuleInfo64 == NULL || symGetOptions == NULL ||
-        symFromAddr == NULL || symInitialize == NULL || symSetOptions == NULL || stackWalk64 == NULL || unDecorateSymbolName == NULL ||
-        symLoadModuleEx == NULL)
+    if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL ||
+        pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL ||
+        pSLM == NULL)
     {
       FreeLibrary(m_hDbhHelp);
       m_hDbhHelp = NULL;
-      symCleanup = NULL;
+      pSC = NULL;
       return FALSE;
     }
 
     // SymInitialize
-    if (szSymPath != NULL)
-      m_szSymPath = _tcsdup(szSymPath);
-    if (this->symInitialize(m_hProcess, m_szSymPath, FALSE) == FALSE)
-      this->m_parent->OnDbgHelpErr(_T("SymInitialize"), GetLastError(), 0);
+    if (this->pSI(m_hProcess, szSymPath, FALSE) == FALSE)
+      this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
 
-    DWORD symOptions = this->symGetOptions(); // SymGetOptions
+    DWORD symOptions = this->pSGO(); // SymGetOptions
     symOptions |= SYMOPT_LOAD_LINES;
     symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
     //symOptions |= SYMOPT_NO_PROMPTS;
     // SymSetOptions
-    symOptions = this->symSetOptions(symOptions);
+    symOptions = this->pSSO(symOptions);
 
-    TCHAR buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
-    if (this->symGetSearchPath != NULL)
+    char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
+    if (this->pSGSP != NULL)
     {
-      if (this->symGetSearchPath(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
-        this->m_parent->OnDbgHelpErr(_T("SymGetSearchPath"), GetLastError(), 0);
+      if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
+        this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
     }
-    TCHAR  szUserName[1024] = {0};
+    char  szUserName[1024] = {0};
     DWORD dwSize = 1024;
-    GetUserName(szUserName, &dwSize);
+    GetUserNameA(szUserName, &dwSize);
     this->m_parent->OnSymInit(buf, symOptions, szUserName);
 
     return TRUE;
@@ -302,41 +415,12 @@
 
   StackWalker* m_parent;
 
+  CONTEXT m_ctx;
   HMODULE m_hDbhHelp;
   HANDLE  m_hProcess;
-  LPTSTR   m_szSymPath;
 
 #pragma pack(push, 8)
-  typedef struct IMAGEHLP_MODULE64_V3
-  {
-    DWORD    SizeOfStruct;         // set to sizeof(IMAGEHLP_MODULE64)
-    DWORD64  BaseOfImage;          // base load address of module
-    DWORD    ImageSize;            // virtual size of the loaded module
-    DWORD    TimeDateStamp;        // date/time stamp from pe header
-    DWORD    CheckSum;             // checksum from the pe header
-    DWORD    NumSyms;              // number of symbols in the symbol table
-    SYM_TYPE SymType;              // type of symbols loaded
-    TCHAR     ModuleName[32];       // module name
-    TCHAR     ImageName[256];       // image name
-    TCHAR     LoadedImageName[256]; // symbol file name
-    // new elements: 07-Jun-2002
-    TCHAR  LoadedPdbName[256];   // pdb file name
-    DWORD CVSig;                // Signature of the CV record in the debug directories
-    TCHAR  CVData[MAX_PATH * 3]; // Contents of the CV record
-    DWORD PdbSig;               // Signature of PDB
-    GUID  PdbSig70;             // Signature of PDB (VC 7 and up)
-    DWORD PdbAge;               // DBI age of pdb
-    BOOL  PdbUnmatched;         // loaded an unmatched pdb
-    BOOL  DbgUnmatched;         // loaded an unmatched dbg
-    BOOL  LineNumbers;          // we have line number information
-    BOOL  GlobalSymbols;        // we have internal symbol information
-    BOOL  TypeInfo;             // we have type information
-    // new elements: 17-Dec-2003
-    BOOL SourceIndexed; // pdb supports source server
-    BOOL Publics;       // contains public symbols
-  };
-
-  typedef struct IMAGEHLP_MODULE64_V2
+  typedef struct _IMAGEHLP_MODULE64_V3
   {
     DWORD    SizeOfStruct;         // set to sizeof(IMAGEHLP_MODULE64)
     DWORD64  BaseOfImage;          // base load address of module
@@ -348,64 +432,90 @@
     CHAR     ModuleName[32];       // module name
     CHAR     ImageName[256];       // image name
     CHAR     LoadedImageName[256]; // symbol file name
-  };
+    // new elements: 07-Jun-2002
+    CHAR  LoadedPdbName[256];   // pdb file name
+    DWORD CVSig;                // Signature of the CV record in the debug directories
+    CHAR  CVData[MAX_PATH * 3]; // Contents of the CV record
+    DWORD PdbSig;               // Signature of PDB
+    GUID  PdbSig70;             // Signature of PDB (VC 7 and up)
+    DWORD PdbAge;               // DBI age of pdb
+    BOOL  PdbUnmatched;         // loaded an unmatched pdb
+    BOOL  DbgUnmatched;         // loaded an unmatched dbg
+    BOOL  LineNumbers;          // we have line number information
+    BOOL  GlobalSymbols;        // we have internal symbol information
+    BOOL  TypeInfo;             // we have type information
+    // new elements: 17-Dec-2003
+    BOOL SourceIndexed; // pdb supports source server
+    BOOL Publics;       // contains public symbols
+  } IMAGEHLP_MODULE64_V3, *PIMAGEHLP_MODULE64_V3;
+
+  typedef struct _IMAGEHLP_MODULE64_V2
+  {
+    DWORD    SizeOfStruct;         // set to sizeof(IMAGEHLP_MODULE64)
+    DWORD64  BaseOfImage;          // base load address of module
+    DWORD    ImageSize;            // virtual size of the loaded module
+    DWORD    TimeDateStamp;        // date/time stamp from pe header
+    DWORD    CheckSum;             // checksum from the pe header
+    DWORD    NumSyms;              // number of symbols in the symbol table
+    SYM_TYPE SymType;              // type of symbols loaded
+    CHAR     ModuleName[32];       // module name
+    CHAR     ImageName[256];       // image name
+    CHAR     LoadedImageName[256]; // symbol file name
+  } IMAGEHLP_MODULE64_V2, *PIMAGEHLP_MODULE64_V2;
 #pragma pack(pop)
 
   // SymCleanup()
   typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess);
-  tSC symCleanup;
+  tSC pSC;
 
   // SymFunctionTableAccess64()
   typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase);
-  tSFTA symFunctionTableAccess64;
+  tSFTA pSFTA;
 
   // SymGetLineFromAddr64()
   typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess,
                                   IN DWORD64 dwAddr,
                                   OUT PDWORD pdwDisplacement,
-                                  OUT tImageHelperLine* Line);
-  tSGLFA symGetLineFromAddr64;
+                                  OUT PIMAGEHLP_LINE64 Line);
+  tSGLFA pSGLFA;
 
   // SymGetModuleBase64()
   typedef DWORD64(__stdcall* tSGMB)(IN HANDLE hProcess, IN DWORD64 dwAddr);
-  tSGMB symGetModuleBase64;
+  tSGMB pSGMB;
 
   // SymGetModuleInfo64()
   typedef BOOL(__stdcall* tSGMI)(IN HANDLE hProcess,
                                  IN DWORD64 dwAddr,
                                  OUT IMAGEHLP_MODULE64_V3* ModuleInfo);
-  tSGMI symGetModuleInfo64;
+  tSGMI pSGMI;
 
   // SymGetOptions()
   typedef DWORD(__stdcall* tSGO)(VOID);
-  tSGO symGetOptions;
-
+  tSGO pSGO;
 
   // SymGetSymFromAddr64()
-  typedef BOOL(__stdcall* tSFA)(IN HANDLE hProcess,
-                                  IN DWORD64 Address,
+  typedef BOOL(__stdcall* tSGSFA)(IN HANDLE hProcess,
+                                  IN DWORD64 dwAddr,
                                   OUT PDWORD64 pdwDisplacement,
-                                  OUT tSymbolInfo* Symbol);
-  tSFA symFromAddr;
+                                  OUT PIMAGEHLP_SYMBOL64 Symbol);
+  tSGSFA pSGSFA;
 
   // SymInitialize()
-  typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PTSTR UserSearchPath, IN BOOL fInvadeProcess);
-  tSI symInitialize;
+  typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN LPCSTR UserSearchPath, IN BOOL fInvadeProcess);
+  tSI pSI;
 
   // SymLoadModule64()
   typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess,
                                    IN HANDLE hFile,
-                                   IN PTSTR ImageName,
-                                   IN PTSTR ModuleName,
+                                   IN LPCSTR ImageName,
+                                   IN LPCSTR ModuleName,
                                    IN DWORD64 BaseOfDll,
-                                   IN DWORD SizeOfDll,
-                                   IN PMODLOAD_DATA Data,
-                                   IN DWORD         Flags);
-  tSLM symLoadModuleEx;
+                                   IN DWORD SizeOfDll);
+  tSLM pSLM;
 
   // SymSetOptions()
   typedef DWORD(__stdcall* tSSO)(IN DWORD SymOptions);
-  tSSO symSetOptions;
+  tSSO pSSO;
 
   // StackWalk64()
   typedef BOOL(__stdcall* tSW)(DWORD                            MachineType,
@@ -417,17 +527,17 @@
                                PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
                                PGET_MODULE_BASE_ROUTINE64       GetModuleBaseRoutine,
                                PTRANSLATE_ADDRESS_ROUTINE64     TranslateAddress);
-  tSW stackWalk64;
+  tSW pSW;
 
   // UnDecorateSymbolName()
-  typedef DWORD(__stdcall WINAPI* tUDSN)(PCTSTR DecoratedName,
-                                         PTSTR  UnDecoratedName,
+  typedef DWORD(__stdcall WINAPI* tUDSN)(PCSTR DecoratedName,
+                                         PSTR  UnDecoratedName,
                                          DWORD UndecoratedLength,
                                          DWORD Flags);
-  tUDSN unDecorateSymbolName;
+  tUDSN pUDSN;
 
-  typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PTSTR SearchPath, DWORD SearchPathLength);
-  tSGSP symGetSearchPath;
+  typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
+  tSGSP pSGSP;
 
 private:
 // **************************************** ToolHelp32 ************************
@@ -444,8 +554,8 @@
     BYTE*   modBaseAddr;   // Base address of module in th32ProcessID's context
     DWORD   modBaseSize;   // Size in bytes of module starting at modBaseAddr
     HMODULE hModule;       // The hModule of this module in th32ProcessID's context
-    TCHAR   szModule[MAX_MODULE_NAME32 + 1];
-    TCHAR   szExePath[MAX_PATH];
+    char    szModule[MAX_MODULE_NAME32 + 1];
+    char    szExePath[MAX_PATH];
   } MODULEENTRY32;
   typedef MODULEENTRY32* PMODULEENTRY32;
   typedef MODULEENTRY32* LPMODULEENTRY32;
@@ -463,31 +573,25 @@
     // try both dlls...
     const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")};
     HINSTANCE    hToolhelp = NULL;
-    tCT32S       createToolhelp32Snapshot = NULL;
-    tM32F        module32First = NULL;
-    tM32N        module32Next = NULL;
+    tCT32S       pCT32S = NULL;
+    tM32F        pM32F = NULL;
+    tM32N        pM32N = NULL;
 
     HANDLE        hSnap;
-    MODULEENTRY32 moduleEntry32;
-    moduleEntry32.dwSize = sizeof(moduleEntry32);
+    MODULEENTRY32 me;
+    me.dwSize = sizeof(me);
     BOOL   keepGoing;
+    size_t i;
 
-#ifdef _UNICODE
-    static const char strModule32First[] = "Module32FirstW";
-    static const char strModule32Next[] = "Module32NextW";
- #else
-    static const char strModule32First[] = "Module32First";
-    static const char strModule32Next[] = "Module32Next";
-#endif
-    for (size_t i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)
+    for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)
     {
       hToolhelp = LoadLibrary(dllname[i]);
       if (hToolhelp == NULL)
         continue;
-      createToolhelp32Snapshot = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
-      module32First = (tM32F)GetProcAddress(hToolhelp, strModule32First);  
-      module32Next = (tM32N)GetProcAddress(hToolhelp, strModule32Next); 
-      if ((createToolhelp32Snapshot != NULL) && (module32First != NULL) && (module32Next != NULL))
+      pCT32S = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
+      pM32F = (tM32F)GetProcAddress(hToolhelp, "Module32First");
+      pM32N = (tM32N)GetProcAddress(hToolhelp, "Module32Next");
+      if ((pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL))
         break; // found the functions!
       FreeLibrary(hToolhelp);
       hToolhelp = NULL;
@@ -496,21 +600,21 @@
     if (hToolhelp == NULL)
       return FALSE;
 
-    hSnap = createToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
+    hSnap = pCT32S(TH32CS_SNAPMODULE, pid);
     if (hSnap == (HANDLE)-1)
     {
       FreeLibrary(hToolhelp);
       return FALSE;
     }
 
-    keepGoing = !!module32First(hSnap, &moduleEntry32);
+    keepGoing = !!pM32F(hSnap, &me);
     int cnt = 0;
     while (keepGoing)
     {
-      this->LoadModule(hProcess, moduleEntry32.szExePath, moduleEntry32.szModule, (DWORD64)moduleEntry32.modBaseAddr,
-                       moduleEntry32.modBaseSize);
+      this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr,
+                       me.modBaseSize);
       cnt++;
-      keepGoing = !!module32Next(hSnap, &moduleEntry32);
+      keepGoing = !!pM32N(hSnap, &me);
     }
     CloseHandle(hSnap);
     FreeLibrary(hToolhelp);
@@ -533,41 +637,39 @@
     typedef BOOL(__stdcall * tEPM)(HANDLE hProcess, HMODULE * lphModule, DWORD cb,
                                    LPDWORD lpcbNeeded);
     // GetModuleFileNameEx()
-    typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename,
+    typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,
                                       DWORD nSize);
     // GetModuleBaseName()
-    typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename,
+    typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,
                                      DWORD nSize);
     // GetModuleInformation()
     typedef BOOL(__stdcall * tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize);
 
-      //ModuleEntry e;
+    HINSTANCE hPsapi;
+    tEPM      pEPM;
+    tGMFNE    pGMFNE;
+    tGMBN     pGMBN;
+    tGMI      pGMI;
+
+    DWORD i;
+    //ModuleEntry e;
     DWORD        cbNeeded;
     MODULEINFO   mi;
-    HMODULE*     hMods = 0;
-    TCHAR*        tt = NULL;
-    TCHAR*        tt2 = NULL;
+    HMODULE*     hMods = NULL;
+    char*        tt = NULL;
+    char*        tt2 = NULL;
     const SIZE_T TTBUFLEN = 8096;
     int          cnt = 0;
 
-    HINSTANCE hPsapi = LoadLibrary(_T("psapi.dll"));
+    hPsapi = LoadLibrary(_T("psapi.dll"));
     if (hPsapi == NULL)
       return FALSE;
 
-#ifdef _UNICODE
-    static const char strGetModuleFileName[] = "GetModuleFileNameExW";
-    static const char strGetModuleBaseName[] = "GetModuleBaseNameW";
-#else
-    static const char strGetModuleFileName[] = "GetModulefileNameExA";
-    static const char strGetModuleBaseName[] = "GetModuleBaseNameA";
-#endif
-
-    tEPM   enumProcessModules = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules");
-    tGMFNE getModuleFileNameEx = (tGMFNE)GetProcAddress(hPsapi, strGetModuleFileName);
-    tGMBN  getModuleBaseName = (tGMFNE)GetProcAddress(hPsapi, strGetModuleBaseName);
-    tGMI   getModuleInformation = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation");
-    if ((enumProcessModules == NULL) || (getModuleFileNameEx == NULL) ||
-        (getModuleBaseName == NULL) || (getModuleInformation == NULL))
+    pEPM = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules");
+    pGMFNE = (tGMFNE)GetProcAddress(hPsapi, "GetModuleFileNameExA");
+    pGMBN = (tGMFNE)GetProcAddress(hPsapi, "GetModuleBaseNameA");
+    pGMI = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation");
+    if ((pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL))
     {
       // we couldn't find all functions
       FreeLibrary(hPsapi);
@@ -575,12 +677,12 @@
     }
 
     hMods = (HMODULE*)malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));
-    tt = (TCHAR*)malloc(sizeof(TCHAR) * TTBUFLEN);
-    tt2 = (TCHAR*)malloc(sizeof(TCHAR) * TTBUFLEN);
+    tt = (char*)malloc(sizeof(char) * TTBUFLEN);
+    tt2 = (char*)malloc(sizeof(char) * TTBUFLEN);
     if ((hMods == NULL) || (tt == NULL) || (tt2 == NULL))
       goto cleanup;
 
-    if (!enumProcessModules(hProcess, hMods, TTBUFLEN, &cbNeeded))
+    if (!pEPM(hProcess, hMods, TTBUFLEN, &cbNeeded))
     {
       //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
       goto cleanup;
@@ -592,20 +694,20 @@
       goto cleanup;
     }
 
-    for (DWORD i = 0; i < cbNeeded / sizeof(hMods[0]); i++)
+    for (i = 0; i < cbNeeded / sizeof(hMods[0]); i++)
     {
       // base address, size
-      getModuleInformation(hProcess, hMods[i], &mi, sizeof(mi));
+      pGMI(hProcess, hMods[i], &mi, sizeof(mi));
       // image file name
       tt[0] = 0;
-      getModuleFileNameEx(hProcess, hMods[i], tt, TTBUFLEN);
+      pGMFNE(hProcess, hMods[i], tt, TTBUFLEN);
       // module name
       tt2[0] = 0;
-      getModuleBaseName(hProcess, hMods[i], tt2, TTBUFLEN);
+      pGMBN(hProcess, hMods[i], tt2, TTBUFLEN);
 
       DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64)mi.lpBaseOfDll, mi.SizeOfImage);
       if (dwRes != ERROR_SUCCESS)
-        this->m_parent->OnDbgHelpErr(_T("LoadModule"), dwRes, 0);
+        this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
       cnt++;
     }
 
@@ -622,16 +724,16 @@
     return cnt != 0;
   } // GetModuleListPSAPI
 
-  DWORD LoadModule(HANDLE hProcess, LPCTSTR img, LPCTSTR mod, DWORD64 baseAddr, DWORD size)
+  DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
   {
-    TCHAR* szImg = _tcsdup(img);
-    TCHAR* szMod = _tcsdup(mod);
+    CHAR* szImg = _strdup(img);
+    CHAR* szMod = _strdup(mod);
     DWORD result = ERROR_SUCCESS;
     if ((szImg == NULL) || (szMod == NULL))
       result = ERROR_NOT_ENOUGH_MEMORY;
     else
     {
-      if (symLoadModuleEx(hProcess, 0, szImg, szMod, baseAddr, size, 0, 0) == 0)
+      if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
         result = GetLastError();
     }
     ULONGLONG fileVersion = 0;
@@ -642,13 +744,13 @@
       {
         VS_FIXEDFILEINFO* fInfo = NULL;
         DWORD             dwHandle;
-        DWORD             dwSize = GetFileVersionInfoSize(szImg, &dwHandle);
+        DWORD             dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
         if (dwSize > 0)
         {
           LPVOID vData = malloc(dwSize);
           if (vData != NULL)
           {
-            if (GetFileVersionInfo(szImg, dwHandle, dwSize, vData) != 0)
+            if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
             {
               UINT  len;
               TCHAR szSubBlock[] = _T("\\");
@@ -667,41 +769,41 @@
 
       // Retrieve some additional-infos about the module
       IMAGEHLP_MODULE64_V3 Module;
-      const TCHAR*          szSymType = _T("-unknown-");
+      const char*          szSymType = "-unknown-";
       if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
       {
         switch (Module.SymType)
         {
           case SymNone:
-            szSymType = _T("-nosymbols-");
+            szSymType = "-nosymbols-";
             break;
           case SymCoff: // 1
-            szSymType = _T("COFF");
+            szSymType = "COFF";
             break;
           case SymCv: // 2
-            szSymType = _T("CV");
+            szSymType = "CV";
             break;
           case SymPdb: // 3
-            szSymType = _T("PDB");
+            szSymType = "PDB";
             break;
           case SymExport: // 4
-            szSymType = _T("-exported-");
+            szSymType = "-exported-";
             break;
           case SymDeferred: // 5
-            szSymType = _T("-deferred-");
+            szSymType = "-deferred-";
             break;
           case SymSym: // 6
-            szSymType = _T("SYM");
+            szSymType = "SYM";
             break;
           case 7: // SymDia:
-            szSymType = _T("DIA");
+            szSymType = "DIA";
             break;
           case 8: //SymVirtual:
-            szSymType = _T("Virtual");
+            szSymType = "Virtual";
             break;
         }
       }
-      LPCTSTR pdbName = Module.LoadedImageName;
+      LPCSTR pdbName = Module.LoadedImageName;
       if (Module.LoadedPdbName[0] != 0)
         pdbName = Module.LoadedPdbName;
       this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName,
@@ -727,7 +829,7 @@
   BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3* pModuleInfo)
   {
     memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
-    if (this->symGetModuleInfo64 == NULL)
+    if (this->pSGMI == NULL)
     {
       SetLastError(ERROR_DLL_INIT_FAILED);
       return FALSE;
@@ -745,7 +847,7 @@
     static bool s_useV3Version = true;
     if (s_useV3Version)
     {
-      if (this->symGetModuleInfo64(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
+      if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
       {
         // only copy as much memory as is reserved...
         memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
@@ -759,7 +861,7 @@
     // could not retrieve the bigger structure, try with the smaller one (as defined in VC7.1)...
     pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
     memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
-    if (this->symGetModuleInfo64(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
+    if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
     {
       // only copy as much memory as is reserved...
       memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
@@ -774,41 +876,102 @@
 };
 
 // #############################################################
-StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
+extern "C" void* __cdecl _getptd();
+#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1900
+extern "C" void** __cdecl __current_exception_context();
+#endif
+
+static PCONTEXT get_current_exception_context()
 {
-  this->m_options = OptionsAll;
-  this->m_modulesLoaded = FALSE;
-  this->m_hProcess = hProcess;
-  this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
-  this->m_dwProcessId = dwProcessId;
-  this->m_szSymPath = NULL;
-  this->m_MaxRecursionCount = 1000;
+  PCONTEXT * pctx = NULL;
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900  
+  LPSTR ptd = (LPSTR)_getptd();
+  if (ptd)
+    pctx = (PCONTEXT *)(ptd + (sizeof(void*) == 4 ? 0x8C : 0xF8));
+#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1900
+  pctx = (PCONTEXT *)__current_exception_context();
+#endif
+  return pctx ? *pctx : NULL;
 }
-StackWalker::StackWalker(int options, LPCTSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
+
+bool StackWalker::Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId,
+                       HANDLE hProcess, PEXCEPTION_POINTERS exp)
 {
+  PCONTEXT ctx = NULL;
+  if (extype == AfterCatch)
+    ctx = get_current_exception_context();
+  if (extype == AfterExcept && exp)
+    ctx = exp->ContextRecord;
   this->m_options = options;
   this->m_modulesLoaded = FALSE;
-  this->m_hProcess = hProcess;
-  this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
-  this->m_dwProcessId = dwProcessId;
-  if (szSymPath != NULL)
-  {
-    this->m_szSymPath = _tcsdup(szSymPath);
-    this->m_options |= SymBuildPath;
-  }
-  else
-    this->m_szSymPath = NULL;
+  this->m_szSymPath = NULL;
   this->m_MaxRecursionCount = 1000;
+  this->m_sw = NULL;
+  SetTargetProcess(dwProcessId, hProcess);
+  SetSymPath(szSymPath);
+  /* MSVC ignore std::nothrow specifier for `new` operator */
+  LPVOID buf = malloc(sizeof(StackWalkerInternal));
+  if (!buf)
+    return false;
+  memset(buf, 0, sizeof(StackWalkerInternal));
+  this->m_sw = new(buf) StackWalkerInternal(this, this->m_hProcess, ctx);  // placement new
+  return true;
+}
+
+StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
+{
+  Init(NonExcept, OptionsAll, NULL, dwProcessId, hProcess);
+}
+
+StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
+{
+  Init(NonExcept, options, szSymPath, dwProcessId, hProcess);
+}
+
+StackWalker::StackWalker(ExceptType extype, int options, PEXCEPTION_POINTERS exp)
+{
+  Init(extype, options, NULL, GetCurrentProcessId(), GetCurrentProcess(), exp);
 }
 
 StackWalker::~StackWalker()
 {
-  if (m_szSymPath != NULL)
+  SetSymPath(NULL);
+  if (m_sw != NULL) {
+    m_sw->~StackWalkerInternal();  // call the object's destructor
+    free(m_sw);
+  }
+  m_sw = NULL;
+}
+
+bool StackWalker::SetSymPath(LPCSTR szSymPath)
+{
+  if (m_szSymPath)
     free(m_szSymPath);
   m_szSymPath = NULL;
-  if (this->m_sw != NULL)
-    delete this->m_sw;
-  this->m_sw = NULL;
+  if (szSymPath == NULL)
+    return true;
+  m_szSymPath = _strdup(szSymPath);
+  if (m_szSymPath)
+    m_options |= SymBuildPath;
+  return true;
+}
+
+bool StackWalker::SetTargetProcess(DWORD dwProcessId, HANDLE hProcess)
+{
+  m_dwProcessId = dwProcessId;
+  m_hProcess = hProcess;
+  if (m_sw)
+    m_sw->m_hProcess = hProcess;
+  return true;
+}
+
+PCONTEXT StackWalker::GetCurrentExceptionContext()
+{
+  return get_current_exception_context();
 }
 
 BOOL StackWalker::LoadModules()
@@ -822,11 +985,11 @@
     return TRUE;
 
   // Build the sym-path:
-  TCHAR* szSymPath = NULL;
+  char* szSymPath = NULL;
   if ((this->m_options & SymBuildPath) != 0)
   {
     const size_t nSymPathLen = 4096;
-    szSymPath = (TCHAR*)malloc(nSymPathLen * sizeof(TCHAR));
+    szSymPath = (char*)malloc(nSymPathLen);
     if (szSymPath == NULL)
     {
       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@@ -836,27 +999,27 @@
     // Now first add the (optional) provided sympath:
     if (this->m_szSymPath != NULL)
     {
-      _tcscat_s(szSymPath, nSymPathLen, this->m_szSymPath);
-      _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+      strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
+      strcat_s(szSymPath, nSymPathLen, ";");
     }
 
-    _tcscat_s(szSymPath, nSymPathLen, _T(".;"));
+    strcat_s(szSymPath, nSymPathLen, ".;");
 
     const size_t nTempLen = 1024;
-    TCHAR         szTemp[nTempLen];
+    char         szTemp[nTempLen];
     // Now add the current directory:
-    if (GetCurrentDirectory(nTempLen, szTemp) > 0)
+    if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
     {
       szTemp[nTempLen - 1] = 0;
-      _tcscat_s(szSymPath, nSymPathLen, szTemp);
-      _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
     }
 
     // Now add the path for the main-module:
-    if (GetModuleFileName(NULL, szTemp, nTempLen) > 0)
+    if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
     {
       szTemp[nTempLen - 1] = 0;
-      for (TCHAR* p = (szTemp + _tcslen(szTemp) - 1); p >= szTemp; --p)
+      for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p)
       {
         // locate the rightmost path separator
         if ((*p == '\\') || (*p == '/') || (*p == ':'))
@@ -865,48 +1028,48 @@
           break;
         }
       } // for (search for path separator...)
-      if (_tcslen(szTemp) > 0)
+      if (strlen(szTemp) > 0)
       {
-        _tcscat_s(szSymPath, nSymPathLen, szTemp);
-        _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+        strcat_s(szSymPath, nSymPathLen, szTemp);
+        strcat_s(szSymPath, nSymPathLen, ";");
       }
     }
-    if (GetEnvironmentVariable(_T("_NT_SYMBOL_PATH"), szTemp, nTempLen) > 0)
+    if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
     {
       szTemp[nTempLen - 1] = 0;
-      _tcscat_s(szSymPath, nSymPathLen, szTemp);
-      _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
     }
-    if (GetEnvironmentVariable(_T("_NT_ALTERNATE_SYMBOL_PATH"), szTemp, nTempLen) > 0)
+    if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
     {
       szTemp[nTempLen - 1] = 0;
-      _tcscat_s(szSymPath, nSymPathLen, szTemp);
-      _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
     }
-    if (GetEnvironmentVariable(_T("SYSTEMROOT"), szTemp, nTempLen) > 0)
+    if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
     {
       szTemp[nTempLen - 1] = 0;
-      _tcscat_s(szSymPath, nSymPathLen, szTemp);
-      _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
       // also add the "system32"-directory:
-      _tcscat_s(szTemp, nTempLen, _T("\\system32"));
-      _tcscat_s(szSymPath, nSymPathLen, szTemp);
-      _tcscat_s(szSymPath, nSymPathLen, _T(";"));
+      strcat_s(szTemp, nTempLen, "\\system32");
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
     }
 
     if ((this->m_options & SymUseSymSrv) != 0)
     {
-      if (GetEnvironmentVariable(_T("SYSTEMDRIVE"), szTemp, nTempLen) > 0)
+      if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
       {
         szTemp[nTempLen - 1] = 0;
-        _tcscat_s(szSymPath, nSymPathLen, _T("SRV*"));
-        _tcscat_s(szSymPath, nSymPathLen, szTemp);
-        _tcscat_s(szSymPath, nSymPathLen, _T("\\websymbols"));
-        _tcscat_s(szSymPath, nSymPathLen, _T("*http://msdl.microsoft.com/download/symbols;"));
+        strcat_s(szSymPath, nSymPathLen, "SRV*");
+        strcat_s(szSymPath, nSymPathLen, szTemp);
+        strcat_s(szSymPath, nSymPathLen, "\\websymbols");
+        strcat_s(szSymPath, nSymPathLen, "*https://msdl.microsoft.com/download/symbols;");
       }
       else
-        _tcscat_s(szSymPath, nSymPathLen,
-                 _T("SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"));
+        strcat_s(szSymPath, nSymPathLen,
+                 "SRV*c:\\websymbols*https://msdl.microsoft.com/download/symbols;");
     }
   } // if SymBuildPath
 
@@ -917,7 +1080,7 @@
   szSymPath = NULL;
   if (bRet == FALSE)
   {
-    this->OnDbgHelpErr(_T("Error while initializing dbghelp.dll"), 0, 0);
+    this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
     SetLastError(ERROR_DLL_INIT_FAILED);
     return FALSE;
   }
@@ -942,10 +1105,9 @@
 {
   CONTEXT                                   c;
   CallstackEntry                            csEntry;
-
-  tSymbolInfo* pSym = NULL;
+  IMAGEHLP_SYMBOL64*                        pSym = NULL;
   StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module;
-  tImageHelperLine                           Line;
+  IMAGEHLP_LINE64                           Line;
   int                                       frameNum;
   bool                                      bLastEntryCalled = true;
   int                                       curRecursionCount = 0;
@@ -973,7 +1135,10 @@
     if (GetThreadId(hThread) == GetCurrentThreadId())
 #endif
     {
-      GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
+      if (m_sw->m_ctx.ContextFlags != 0)
+        c = m_sw->m_ctx;   // context taken at Init
+      else
+        GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
     }
     else
     {
@@ -1026,16 +1191,24 @@
   s.AddrBStore.Mode = AddrModeFlat;
   s.AddrStack.Offset = c.IntSp;
   s.AddrStack.Mode = AddrModeFlat;
+#elif _M_ARM64
+  imageType = IMAGE_FILE_MACHINE_ARM64;
+  s.AddrPC.Offset = c.Pc;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.Fp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.Sp;
+  s.AddrStack.Mode = AddrModeFlat;
 #else
 #error "Platform not supported!"
 #endif
 
-  pSym = (tSymbolInfo*)malloc(sizeof(tSymbolInfo) + STACKWALK_MAX_NAMELEN*sizeof(TCHAR));
+  pSym = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
   if (!pSym)
     goto cleanup; // not enough memory...
-  memset(pSym, 0, sizeof(tSymbolInfo) + STACKWALK_MAX_NAMELEN*sizeof(TCHAR));
-  pSym->SizeOfStruct = sizeof(tSymbolInfo);
-  pSym->MaxNameLen = STACKWALK_MAX_NAMELEN;
+  memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
+  pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+  pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
 
   memset(&Line, 0, sizeof(Line));
   Line.SizeOfStruct = sizeof(Line);
@@ -1050,11 +1223,11 @@
     // assume that either you are done, or that the stack is so hosed that the next
     // deeper frame could not be found.
     // CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386!
-    if (!this->m_sw->stackWalk64(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem,
-                         this->m_sw->symFunctionTableAccess64, this->m_sw->symGetModuleBase64, NULL))
+    if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem,
+                         this->m_sw->pSFTA, this->m_sw->pSGMB, NULL))
     {
       // INFO: "StackWalk64" does not set "GetLastError"...
-      this->OnDbgHelpErr(_T("StackWalk64"), 0, s.AddrPC.Offset);
+      this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);
       break;
     }
 
@@ -1072,7 +1245,7 @@
     {
       if ((this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount))
       {
-        this->OnDbgHelpErr(_T("StackWalk64-Endless-Callstack!"), 0, s.AddrPC.Offset);
+        this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
         break;
       }
       curRecursionCount++;
@@ -1083,23 +1256,23 @@
     {
       // we seem to have a valid PC
       // show procedure info (SymGetSymFromAddr64())
-      if (this->m_sw->symFromAddr(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol),
+      if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol),
                              pSym) != FALSE)
       {
         MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name);
         // UnDecorateSymbolName()
-        DWORD res = this->m_sw->unDecorateSymbolName(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
-        res = this->m_sw->unDecorateSymbolName(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
+        this->m_sw->pUDSN(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
+        this->m_sw->pUDSN(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
       }
       else
       {
-        this->OnDbgHelpErr(_T("SymGetSymFromAddr64"), GetLastError(), s.AddrPC.Offset);
+        this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
       }
 
       // show line number info, NT5.0-method (SymGetLineFromAddr64())
-      if (this->m_sw->symGetLineFromAddr64 != NULL)
+      if (this->m_sw->pSGLFA != NULL)
       { // yes, we have SymGetLineFromAddr64()
-        if (this->m_sw->symGetLineFromAddr64(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine),
+        if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine),
                                &Line) != FALSE)
         {
           csEntry.lineNumber = Line.LineNumber;
@@ -1107,7 +1280,7 @@
         }
         else
         {
-          this->OnDbgHelpErr(_T("SymGetLineFromAddr64"), GetLastError(), s.AddrPC.Offset);
+          this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
         }
       } // yes, we have SymGetLineFromAddr64()
 
@@ -1157,7 +1330,7 @@
       } // got module info OK
       else
       {
-        this->OnDbgHelpErr(_T("SymGetModuleInfo64"), GetLastError(), s.AddrPC.Offset);
+        this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
       }
     } // we seem to have a valid PC
 
@@ -1203,20 +1376,22 @@
   }
 
   // SymGetSymFromAddr64() is required
-  if (this->m_sw->symFromAddr == NULL)
+  if (this->m_sw->pSGSFA == NULL)
     return FALSE;
 
   // Show object info (SymGetSymFromAddr64())
   DWORD64            dwAddress = DWORD64(pObject);
   DWORD64            dwDisplacement = 0;
-  tSymbolInfo* pSym =
-      (tSymbolInfo*)malloc(sizeof(tSymbolInfo) + STACKWALK_MAX_NAMELEN*sizeof(TCHAR));
-  memset(pSym, 0, sizeof(tSymbolInfo) + STACKWALK_MAX_NAMELEN*sizeof(TCHAR));
-  pSym->SizeOfStruct = sizeof(tSymbolInfo);
-  pSym->MaxNameLen = STACKWALK_MAX_NAMELEN;
-  if (this->m_sw->symFromAddr(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE)
+  const SIZE_T       symSize = sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN;
+  IMAGEHLP_SYMBOL64* pSym = (IMAGEHLP_SYMBOL64*) malloc(symSize);
+  if (!pSym)
+    return FALSE;
+  memset(pSym, 0, symSize);
+  pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+  pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
+  if (this->m_sw->pSGSFA(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE)
   {
-    this->OnDbgHelpErr(_T("SymGetSymFromAddr64"), GetLastError(), dwAddress);
+    this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), dwAddress);
     return FALSE;
   }
   // Object name output
@@ -1247,22 +1422,22 @@
   }
 }
 
-void StackWalker::OnLoadModule(LPCTSTR    img,
-                               LPCTSTR    mod,
+void StackWalker::OnLoadModule(LPCSTR    img,
+                               LPCSTR    mod,
                                DWORD64   baseAddr,
                                DWORD     size,
                                DWORD     result,
-                               LPCTSTR    symType,
-                               LPCTSTR    pdbName,
+                               LPCSTR    symType,
+                               LPCSTR    pdbName,
                                ULONGLONG fileVersion)
 {
-  TCHAR   buffer[STACKWALK_MAX_NAMELEN];
+  CHAR   buffer[STACKWALK_MAX_NAMELEN];
   size_t maxLen = STACKWALK_MAX_NAMELEN;
 #if _MSC_VER >= 1400
   maxLen = _TRUNCATE;
 #endif
   if (fileVersion == 0)
-    _sntprintf_s(buffer, maxLen, _T("%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n"),
+    _snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n",
                 img, mod, (LPVOID)baseAddr, size, result, symType, pdbName);
   else
   {
@@ -1270,9 +1445,9 @@
     DWORD v3 = (DWORD)((fileVersion >> 16) & 0xFFFF);
     DWORD v2 = (DWORD)((fileVersion >> 32) & 0xFFFF);
     DWORD v1 = (DWORD)((fileVersion >> 48) & 0xFFFF);
-    _sntprintf_s(
+    _snprintf_s(
         buffer, maxLen,
-        _T("%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n"),
+        "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n",
         img, mod, (LPVOID)baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
   }
   buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NULL terminated
@@ -1281,7 +1456,7 @@
 
 void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry)
 {
-  TCHAR   buffer[STACKWALK_MAX_NAMELEN];
+  CHAR   buffer[STACKWALK_MAX_NAMELEN];
   size_t maxLen = STACKWALK_MAX_NAMELEN;
 #if _MSC_VER >= 1400
   maxLen = _TRUNCATE;
@@ -1289,48 +1464,48 @@
   if ((eType != lastEntry) && (entry.offset != 0))
   {
     if (entry.name[0] == 0)
-      MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, _T("(function-name not available)"));
+      MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)");
     if (entry.undName[0] != 0)
       MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);
     if (entry.undFullName[0] != 0)
       MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);
     if (entry.lineFileName[0] == 0)
     {
-      MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, _T("(filename not available)"));
+      MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
       if (entry.moduleName[0] == 0)
-        MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, _T("(module-name not available)"));
-      _sntprintf_s(buffer, maxLen, _T("%p (%s): %s: %s\n"), (LPVOID)entry.offset, entry.moduleName,
+        MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");
+      _snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID)entry.offset, entry.moduleName,
                   entry.lineFileName, entry.name);
     }
     else
-      _sntprintf_s(buffer, maxLen, _T("%s (%d): %s\n"), entry.lineFileName, entry.lineNumber,
+      _snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber,
                   entry.name);
     buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
     OnOutput(buffer);
   }
 }
 
-void StackWalker::OnDbgHelpErr(LPCTSTR szFuncName, DWORD gle, DWORD64 addr)
+void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
 {
-  TCHAR   buffer[STACKWALK_MAX_NAMELEN];
+  CHAR   buffer[STACKWALK_MAX_NAMELEN];
   size_t maxLen = STACKWALK_MAX_NAMELEN;
 #if _MSC_VER >= 1400
   maxLen = _TRUNCATE;
 #endif
-  _sntprintf_s(buffer, maxLen, _T("ERROR: %s, GetLastError: %d (Address: %p)\n"), szFuncName, gle,
+  _snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle,
               (LPVOID)addr);
   buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
   OnOutput(buffer);
 }
 
-void StackWalker::OnSymInit(LPCTSTR szSearchPath, DWORD symOptions, LPCTSTR szUserName)
+void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
 {
-  TCHAR   buffer[STACKWALK_MAX_NAMELEN];
+  CHAR   buffer[STACKWALK_MAX_NAMELEN];
   size_t maxLen = STACKWALK_MAX_NAMELEN;
 #if _MSC_VER >= 1400
   maxLen = _TRUNCATE;
 #endif
-  _sntprintf_s(buffer, maxLen, _T("SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n"),
+  _snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n",
               szSearchPath, symOptions, szUserName);
   buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
   OnOutput(buffer);
@@ -1347,16 +1522,16 @@
     OnOutput(buffer);
   }
 #else
-  OSVERSIONINFOEX ver;
-  ZeroMemory(&ver, sizeof(OSVERSIONINFOEX));
+  OSVERSIONINFOEXA ver;
+  ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
   ver.dwOSVersionInfoSize = sizeof(ver);
 #if _MSC_VER >= 1900
 #pragma warning(push)
 #pragma warning(disable : 4996)
 #endif
-  if (GetVersionEx((OSVERSIONINFO*)&ver) != FALSE)
+  if (GetVersionExA((OSVERSIONINFOA*)&ver) != FALSE)
   {
-    _sntprintf_s(buffer, maxLen, _T("OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n"), ver.dwMajorVersion,
+    _snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion,
                 ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask,
                 ver.wProductType);
     buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
@@ -1368,7 +1543,7 @@
 #endif
 }
 
-void StackWalker::OnOutput(LPCTSTR buffer)
+void StackWalker::OnOutput(LPCSTR buffer)
 {
-  OutputDebugString(buffer);
+  OutputDebugStringA(buffer);
 }
diff --git a/wpiutil/src/main/native/windows/StackWalker.h b/wpiutil/src/main/native/windows/StackWalker.h
index 89be951..5ab241e 100644
--- a/wpiutil/src/main/native/windows/StackWalker.h
+++ b/wpiutil/src/main/native/windows/StackWalker.h
@@ -43,14 +43,27 @@
 
 #include <windows.h>
 
-#if _MSC_VER >= 1900
-#pragma warning(disable : 4091)
+// special defines for VC5/6 (if no actual PSDK is installed):
+#if _MSC_VER < 1300
+typedef unsigned __int64 DWORD64, *PDWORD64;
+#if defined(_WIN64)
+typedef unsigned __int64 SIZE_T, *PSIZE_T;
+#else
+typedef unsigned long SIZE_T, *PSIZE_T;
 #endif
+#endif // _MSC_VER < 1300
 
 class StackWalkerInternal; // forward
 class StackWalker
 {
 public:
+  typedef enum ExceptType
+  {
+    NonExcept   = 0,     // RtlCaptureContext
+    AfterExcept = 1,
+    AfterCatch  = 2,     // get_current_exception_context
+  } ExceptType;
+
   typedef enum StackWalkOptions
   {
     // No addition info will be retrieved
@@ -85,13 +98,28 @@
     OptionsAll = 0x3F
   } StackWalkOptions;
 
+  StackWalker(ExceptType extype, int options = OptionsAll, PEXCEPTION_POINTERS exp = NULL);
+
   StackWalker(int    options = OptionsAll, // 'int' is by design, to combine the enum-flags
-              LPCTSTR szSymPath = NULL,
+              LPCSTR szSymPath = NULL,
               DWORD  dwProcessId = GetCurrentProcessId(),
               HANDLE hProcess = GetCurrentProcess());
+
   StackWalker(DWORD dwProcessId, HANDLE hProcess);
+
   virtual ~StackWalker();
 
+  bool SetSymPath(LPCSTR szSymPath);
+
+  bool SetTargetProcess(DWORD dwProcessId, HANDLE hProcess);
+
+  PCONTEXT GetCurrentExceptionContext();
+
+private:
+  bool Init(ExceptType extype, int options, LPCSTR szSymPath, DWORD dwProcessId,
+            HANDLE hProcess, PEXCEPTION_POINTERS exp = NULL);
+
+public:
   typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
       HANDLE  hProcess,
       DWORD64 qwBaseAddress,
@@ -127,18 +155,18 @@
   typedef struct CallstackEntry
   {
     DWORD64 offset; // if 0, we have no valid entry
-    TCHAR    name[STACKWALK_MAX_NAMELEN];
-    TCHAR    undName[STACKWALK_MAX_NAMELEN];
-    TCHAR    undFullName[STACKWALK_MAX_NAMELEN];
+    CHAR    name[STACKWALK_MAX_NAMELEN];
+    CHAR    undName[STACKWALK_MAX_NAMELEN];
+    CHAR    undFullName[STACKWALK_MAX_NAMELEN];
     DWORD64 offsetFromSmybol;
     DWORD   offsetFromLine;
     DWORD   lineNumber;
-    TCHAR    lineFileName[STACKWALK_MAX_NAMELEN];
+    CHAR    lineFileName[STACKWALK_MAX_NAMELEN];
     DWORD   symType;
     LPCSTR  symTypeString;
-    TCHAR    moduleName[STACKWALK_MAX_NAMELEN];
+    CHAR    moduleName[STACKWALK_MAX_NAMELEN];
     DWORD64 baseOfImage;
-    TCHAR    loadedImageName[STACKWALK_MAX_NAMELEN];
+    CHAR    loadedImageName[STACKWALK_MAX_NAMELEN];
   } CallstackEntry;
 
   typedef enum CallstackEntryType
@@ -148,24 +176,24 @@
     lastEntry
   } CallstackEntryType;
 
-  virtual void OnSymInit(LPCTSTR szSearchPath, DWORD symOptions, LPCTSTR szUserName);
-  virtual void OnLoadModule(LPCTSTR    img,
-                            LPCTSTR    mod,
+  virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
+  virtual void OnLoadModule(LPCSTR    img,
+                            LPCSTR    mod,
                             DWORD64   baseAddr,
                             DWORD     size,
                             DWORD     result,
-                            LPCTSTR    symType,
-                            LPCTSTR    pdbName,
+                            LPCSTR    symType,
+                            LPCSTR    pdbName,
                             ULONGLONG fileVersion);
   virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
-  virtual void OnDbgHelpErr(LPCTSTR szFuncName, DWORD gle, DWORD64 addr);
-  virtual void OnOutput(LPCTSTR szText);
+  virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
+  virtual void OnOutput(LPCSTR szText);
 
   StackWalkerInternal* m_sw;
   HANDLE               m_hProcess;
   DWORD                m_dwProcessId;
   BOOL                 m_modulesLoaded;
-  LPTSTR               m_szSymPath;
+  LPSTR                m_szSymPath;
 
   int m_options;
   int m_MaxRecursionCount;
@@ -179,6 +207,57 @@
   friend StackWalkerInternal;
 }; // class StackWalker
 
+// The "ugly" assembler-implementation is needed for systems before XP
+// If you have a new PSDK and you only compile for XP and later, then you can use
+// the "RtlCaptureContext"
+// Currently there is no define which determines the PSDK-Version...
+// So we just use the compiler-version (and assumes that the PSDK is
+// the one which was installed by the VS-IDE)
+
+// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
+//       But I currently use it in x64/IA64 environments...
+//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
+
+#if defined(_M_IX86)
+#ifdef CURRENT_THREAD_VIA_EXCEPTION
+// TODO: The following is not a "good" implementation,
+// because the callstack is only valid in the "__except" block...
+#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags)               \
+  do                                                                            \
+  {                                                                             \
+    memset(&c, 0, sizeof(CONTEXT));                                             \
+    EXCEPTION_POINTERS* pExp = NULL;                                            \
+    __try                                                                       \
+    {                                                                           \
+      throw 0;                                                                  \
+    }                                                                           \
+    __except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER   \
+                                                  : EXCEPTION_EXECUTE_HANDLER)) \
+    {                                                                           \
+    }                                                                           \
+    if (pExp != NULL)                                                           \
+      memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT));                         \
+    c.ContextFlags = contextFlags;                                              \
+  } while (0);
+#else
+// clang-format off
+// The following should be enough for walking the callstack...
+#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
+  do                                                              \
+  {                                                               \
+    memset(&c, 0, sizeof(CONTEXT));                               \
+    c.ContextFlags = contextFlags;                                \
+    __asm    call x                                               \
+    __asm x: pop eax                                              \
+    __asm    mov c.Eip, eax                                       \
+    __asm    mov c.Ebp, ebp                                       \
+    __asm    mov c.Esp, esp                                       \
+  } while (0)
+// clang-format on
+#endif
+
+#else
+
 // The following is defined for x86 (XP and higher), x64 and IA64:
 #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
   do                                                              \
@@ -187,6 +266,7 @@
     c.ContextFlags = contextFlags;                                \
     RtlCaptureContext(&c);                                        \
   } while (0);
+#endif
 
 #endif //defined(_MSC_VER)
 
diff --git a/wpiutil/src/test/java/edu/wpi/first/util/InterpolatingTreeMapTest.java b/wpiutil/src/test/java/edu/wpi/first/util/InterpolatingTreeMapTest.java
index ea23dc5..2203ca8 100644
--- a/wpiutil/src/test/java/edu/wpi/first/util/InterpolatingTreeMapTest.java
+++ b/wpiutil/src/test/java/edu/wpi/first/util/InterpolatingTreeMapTest.java
@@ -8,6 +8,7 @@
 
 import org.junit.jupiter.api.Test;
 
+@SuppressWarnings("removal")
 class InterpolatingTreeMapTest {
   @Test
   void testInterpolationDouble() {
diff --git a/wpiutil/src/test/java/edu/wpi/first/util/cleanup/CleanupPoolTest.java b/wpiutil/src/test/java/edu/wpi/first/util/cleanup/CleanupPoolTest.java
new file mode 100644
index 0000000..a953a85
--- /dev/null
+++ b/wpiutil/src/test/java/edu/wpi/first/util/cleanup/CleanupPoolTest.java
@@ -0,0 +1,154 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.cleanup;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class CleanupPoolTest {
+  static class AutoCloseableObject implements AutoCloseable {
+    public boolean m_closed;
+
+    @Override
+    public void close() {
+      m_closed = true;
+    }
+  }
+
+  static class AutoCloseableObjectWithCallback implements AutoCloseable {
+    private final Runnable m_cb;
+
+    AutoCloseableObjectWithCallback(Runnable cb) {
+      m_cb = cb;
+    }
+
+    @Override
+    public void close() {
+      m_cb.run();
+    }
+  }
+
+  static class FailingAutoCloseableObject implements AutoCloseable {
+    public static final String message = "This is an expected failure";
+
+    @Override
+    public void close() {
+      throw new RuntimeException(message);
+    }
+  }
+
+  @Test
+  void cleanupStackWorks() {
+    List<AutoCloseableObject> objects = new ArrayList<>();
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+
+    try (CleanupPool pool = new CleanupPool()) {
+      for (AutoCloseableObject autoCloseableObject : objects) {
+        pool.register(autoCloseableObject);
+      }
+    }
+
+    for (AutoCloseableObject autoCloseableObject : objects) {
+      assertTrue(autoCloseableObject.m_closed);
+    }
+  }
+
+  @Test
+  @SuppressWarnings("PMD.AvoidCatchingGenericException")
+  void cleanupStackWithExceptionNotInCloseWorks() {
+    List<AutoCloseableObject> objects = new ArrayList<>();
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+
+    String message = "This is a known failure";
+
+    try (CleanupPool pool = new CleanupPool()) {
+      for (AutoCloseableObject autoCloseableObject : objects) {
+        pool.register(autoCloseableObject);
+      }
+      throw new Exception(message);
+    } catch (Exception e) {
+      assertEquals(message, e.getMessage());
+    }
+
+    for (AutoCloseableObject autoCloseableObject : objects) {
+      assertTrue(autoCloseableObject.m_closed);
+    }
+  }
+
+  @Test
+  @SuppressWarnings("PMD.AvoidCatchingGenericException")
+  void cleanupStackWithExceptionInCloseWorks() {
+    List<AutoCloseableObject> objects = new ArrayList<>();
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+
+    try (CleanupPool pool = new CleanupPool()) {
+      for (AutoCloseableObject autoCloseableObject : objects) {
+        pool.register(new FailingAutoCloseableObject());
+        pool.register(autoCloseableObject);
+      }
+    }
+
+    for (AutoCloseableObject autoCloseableObject : objects) {
+      assertTrue(autoCloseableObject.m_closed);
+    }
+  }
+
+  @Test
+  void cleanupStackRemovalWorks() {
+    List<AutoCloseableObject> objects = new ArrayList<>();
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+    objects.add(new AutoCloseableObject());
+
+    try (CleanupPool pool = new CleanupPool()) {
+      for (AutoCloseableObject autoCloseableObject : objects) {
+        pool.register(autoCloseableObject);
+      }
+
+      pool.remove(objects.get(0));
+    }
+
+    int idx = 0;
+    for (AutoCloseableObject autoCloseableObject : objects) {
+      if (idx == 0) {
+        assertFalse(autoCloseableObject.m_closed);
+      } else {
+        assertTrue(autoCloseableObject.m_closed);
+      }
+      idx++;
+    }
+  }
+
+  @Test
+  void cleanupStackIsLifo() {
+    List<AutoCloseableObjectWithCallback> objects = new ArrayList<>();
+    List<Integer> order = new ArrayList<>();
+    objects.add(new AutoCloseableObjectWithCallback(() -> order.add(0)));
+    objects.add(new AutoCloseableObjectWithCallback(() -> order.add(1)));
+    objects.add(new AutoCloseableObjectWithCallback(() -> order.add(2)));
+
+    try (CleanupPool pool = new CleanupPool()) {
+      for (AutoCloseable autoCloseableObject : objects) {
+        pool.register(autoCloseableObject);
+      }
+    }
+
+    assertEquals(order.size(), 3);
+    assertEquals(order.get(0), 2);
+    assertEquals(order.get(1), 1);
+    assertEquals(order.get(2), 0);
+  }
+}
diff --git a/wpiutil/src/test/java/edu/wpi/first/util/cleanup/ReflectionCleanupTest.java b/wpiutil/src/test/java/edu/wpi/first/util/cleanup/ReflectionCleanupTest.java
new file mode 100644
index 0000000..7bf3d64
--- /dev/null
+++ b/wpiutil/src/test/java/edu/wpi/first/util/cleanup/ReflectionCleanupTest.java
@@ -0,0 +1,62 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.cleanup;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class ReflectionCleanupTest {
+  static class CleanupClass implements AutoCloseable {
+    public boolean m_closed;
+
+    @Override
+    public void close() {
+      m_closed = true;
+    }
+  }
+
+  @SuppressWarnings("PMD.TestClassWithoutTestCases")
+  static class CleanupTest implements ReflectionCleanup {
+    public CleanupClass m_class1 = new CleanupClass();
+    public CleanupClass m_class2 = new CleanupClass();
+    public Object m_nonCleanupObject = new Object();
+    public Object m_nullCleanupObject;
+
+    @Override
+    public void close() {
+      reflectionCleanup(CleanupTest.class);
+    }
+  }
+
+  static class CleanupTest2 extends CleanupTest {
+    @SkipCleanup public CleanupClass m_class3 = new CleanupClass();
+    public CleanupClass m_class4 = new CleanupClass();
+
+    @Override
+    public void close() {
+      reflectionCleanup(CleanupTest2.class);
+    }
+  }
+
+  @Test
+  void cleanupClosesAllFields() {
+    CleanupTest test = new CleanupTest();
+    test.close();
+    assertTrue(test.m_class1.m_closed);
+    assertTrue(test.m_class2.m_closed);
+  }
+
+  @Test
+  void cleanupOnlyClosesExplicitClassAndSkipWorks() {
+    CleanupTest2 test = new CleanupTest2();
+    test.close();
+    assertFalse(test.m_class1.m_closed);
+    assertFalse(test.m_class2.m_closed);
+    assertFalse(test.m_class3.m_closed);
+    assertTrue(test.m_class4.m_closed);
+  }
+}
diff --git a/wpiutil/src/test/java/edu/wpi/first/util/struct/DynamicStructTest.java b/wpiutil/src/test/java/edu/wpi/first/util/struct/DynamicStructTest.java
new file mode 100644
index 0000000..9e77c80
--- /dev/null
+++ b/wpiutil/src/test/java/edu/wpi/first/util/struct/DynamicStructTest.java
@@ -0,0 +1,390 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class DynamicStructTest {
+  @SuppressWarnings("MemberName")
+  private StructDescriptorDatabase db;
+
+  @BeforeEach
+  public void init() {
+    db = new StructDescriptorDatabase();
+  }
+
+  @Test
+  void testEmpty() {
+    var desc = assertDoesNotThrow(() -> db.add("test", ""));
+    assertEquals(desc.getName(), "test");
+    assertEquals(desc.getSchema(), "");
+    assertTrue(desc.getFields().isEmpty());
+    assertTrue(desc.isValid());
+    assertEquals(desc.getSize(), 0);
+  }
+
+  @Test
+  void testNestedStruct() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "int32 a"));
+    assertTrue(desc.isValid());
+    var desc2 = assertDoesNotThrow(() -> db.add("test2", "test a"));
+    assertTrue(desc2.isValid());
+    assertEquals(desc2.getSize(), 4);
+  }
+
+  @Test
+  void testDelayedValid() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "foo a"));
+    assertFalse(desc.isValid());
+    var desc2 = assertDoesNotThrow(() -> db.add("test2", "foo a[2]"));
+    assertFalse(desc2.isValid());
+    var desc3 = assertDoesNotThrow(() -> db.add("foo", "int32 a"));
+    assertTrue(desc3.isValid());
+    assertTrue(desc.isValid());
+    assertEquals(desc.getSize(), 4);
+    assertTrue(desc2.isValid());
+    assertEquals(desc2.getSize(), 8);
+  }
+
+  @Test
+  void testInvalidBitfield() {
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "float a:1"),
+        "field a: type float cannot be bitfield");
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "double a:1"),
+        "field a: type double cannot be bitfield");
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "foo a:1"),
+        "field a: type foo cannot be bitfield");
+  }
+
+  @Test
+  void testCircularStructReference() {
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "test a"),
+        "field a: recursive struct reference");
+  }
+
+  @Test
+  void testNestedCircularStructRef() {
+    assertDoesNotThrow(() -> db.add("test", "foo a"));
+    assertDoesNotThrow(() -> db.add("foo", "bar a"));
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("bar", "test a"),
+        "circular struct reference: bar <- foo <- test");
+
+    // ok
+    var desc = assertDoesNotThrow(() -> db.add("baz", "bar a"));
+    assertFalse(desc.isValid());
+  }
+
+  @Test
+  void testNestedCircularStructRef2() {
+    assertDoesNotThrow(() -> db.add("test", "foo a"));
+    assertDoesNotThrow(() -> db.add("bar", "test a"));
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("foo", "bar a"),
+        "circular struct reference: foo <- test <- bar");
+  }
+
+  @Test
+  void testBitfieldBasic() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "int32 a:2; uint32 b:30"));
+    assertEquals(desc.getSize(), 4);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 2);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x3);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 4);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 30);
+    assertEquals(field.getBitShift(), 2);
+    assertEquals(field.getBitMask(), 0x3fffffff);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 4);
+  }
+
+  @Test
+  void testBitfieldDiffType() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "int32 a:2; int16 b:2"));
+    assertEquals(desc.getSize(), 6);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 2);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x3);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 4);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 2);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x3);
+    assertEquals(field.getOffset(), 4);
+    assertEquals(field.getSize(), 2);
+  }
+
+  @Test
+  void testBitfieldOverflow() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "int8 a:4; int8 b:5"));
+    assertEquals(desc.getSize(), 2);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 4);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0xf);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 1);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 5);
+    assertEquals(field.getBitMask(), 0x1f);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getOffset(), 1);
+    assertEquals(field.getSize(), 1);
+  }
+
+  @Test
+  void testBitfieldBoolBegin8() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "bool a:1; int8 b:5"));
+    assertEquals(desc.getSize(), 1);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 1);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x1);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 1);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 5);
+    assertEquals(field.getBitMask(), 0x1f);
+    assertEquals(field.getBitShift(), 1);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 1);
+  }
+
+  @Test
+  void testBitfieldBoolBegin16() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "bool a:1; int16 b:5"));
+    assertEquals(desc.getSize(), 3);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 1);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x1);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 1);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 5);
+    assertEquals(field.getBitMask(), 0x1f);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getOffset(), 1);
+    assertEquals(field.getSize(), 2);
+  }
+
+  @Test
+  void testBitfieldBoolMid() {
+    var desc =
+        assertDoesNotThrow(() -> db.add("test", "int16 a:2; bool b:1; bool c:1; uint16 d:5"));
+    assertEquals(desc.getSize(), 2);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 4);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 2);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x3);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 1);
+    assertEquals(field.getBitMask(), 0x1);
+    assertEquals(field.getBitShift(), 2);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+    field = fields.get(2);
+    assertEquals(field.getBitWidth(), 1);
+    assertEquals(field.getBitMask(), 0x1);
+    assertEquals(field.getBitShift(), 3);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+    field = fields.get(3);
+    assertEquals(field.getBitWidth(), 5);
+    assertEquals(field.getBitMask(), 0x1f);
+    assertEquals(field.getBitShift(), 4);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+  }
+
+  @Test
+  void testBitfieldBoolEnd() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "int16 a:15; bool b:1"));
+    assertEquals(desc.getSize(), 2);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 15);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0x7fff);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 1);
+    assertEquals(field.getBitMask(), 0x1);
+    assertEquals(field.getBitShift(), 15);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+  }
+
+  @Test
+  void testBitfieldBoolEnd2() {
+    var desc = assertDoesNotThrow(() -> db.add("test", "int16 a:16; bool b:1"));
+    assertEquals(desc.getSize(), 3);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 2);
+    var field = fields.get(0);
+    assertEquals(field.getBitWidth(), 16);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getBitMask(), 0xffff);
+    assertEquals(field.getOffset(), 0);
+    assertEquals(field.getSize(), 2);
+    field = fields.get(1);
+    assertEquals(field.getBitWidth(), 1);
+    assertEquals(field.getBitMask(), 0x1);
+    assertEquals(field.getBitShift(), 0);
+    assertEquals(field.getOffset(), 2);
+    assertEquals(field.getSize(), 1);
+  }
+
+  @Test
+  void testBitfieldBoolWrongSize() {
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "bool a:2"),
+        "field a: bit width must be 1 for bool type");
+  }
+
+  @Test
+  void testBitfieldTooBig() {
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "int16 a:17"),
+        "field a: bit width 17 exceeds type size");
+  }
+
+  @Test
+  void testDuplicateFieldName() {
+    assertThrows(
+        BadSchemaException.class,
+        () -> db.add("test", "int16 a; int8 a"),
+        "field a: duplicate field name");
+  }
+
+  private static Stream<Arguments> provideSimpleTestParams() {
+    return Stream.of(
+        Arguments.of("bool a", 1, StructFieldType.kBool, false, false, 8, 0xff),
+        Arguments.of("char a", 1, StructFieldType.kChar, false, false, 8, 0xff),
+        Arguments.of("int8 a", 1, StructFieldType.kInt8, true, false, 8, 0xff),
+        Arguments.of("int16 a", 2, StructFieldType.kInt16, true, false, 16, 0xffff),
+        Arguments.of("int32 a", 4, StructFieldType.kInt32, true, false, 32, 0xffffffffL),
+        Arguments.of("int64 a", 8, StructFieldType.kInt64, true, false, 64, -1),
+        Arguments.of("uint8 a", 1, StructFieldType.kUint8, false, true, 8, 0xff),
+        Arguments.of("uint16 a", 2, StructFieldType.kUint16, false, true, 16, 0xffff),
+        Arguments.of("uint32 a", 4, StructFieldType.kUint32, false, true, 32, 0xffffffffL),
+        Arguments.of("uint64 a", 8, StructFieldType.kUint64, false, true, 64, -1),
+        Arguments.of("float a", 4, StructFieldType.kFloat, false, false, 32, 0xffffffffL),
+        Arguments.of("float32 a", 4, StructFieldType.kFloat, false, false, 32, 0xffffffffL),
+        Arguments.of("double a", 8, StructFieldType.kDouble, false, false, 64, -1),
+        Arguments.of("float64 a", 8, StructFieldType.kDouble, false, false, 64, -1),
+        Arguments.of("foo a", 0, StructFieldType.kStruct, false, false, 0, 0));
+  }
+
+  @ParameterizedTest
+  @MethodSource("provideSimpleTestParams")
+  void testStandardCheck(
+      String schema,
+      int size,
+      StructFieldType type,
+      boolean isInt,
+      boolean isUint,
+      int bitWidth,
+      long bitMask) {
+    var desc = assertDoesNotThrow(() -> db.add("test", schema));
+    assertEquals(desc.getName(), "test");
+    assertEquals(desc.getSchema(), schema);
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 1);
+    var field = fields.get(0);
+    assertEquals(field.getParent(), desc);
+    assertEquals(field.getName(), "a");
+    assertEquals(field.isInt(), isInt);
+    assertEquals(field.isUint(), isUint);
+    assertFalse(field.isArray());
+    if (type != StructFieldType.kStruct) {
+      assertTrue(desc.isValid());
+      assertEquals(desc.getSize(), size);
+      assertEquals(field.getSize(), size);
+      assertEquals(field.getBitWidth(), bitWidth);
+      assertEquals(field.getBitMask(), bitMask);
+    } else {
+      assertFalse(desc.isValid());
+      assertNotNull(field.getStruct());
+    }
+  }
+
+  @ParameterizedTest
+  @MethodSource("provideSimpleTestParams")
+  void testStandardArray(
+      String schema,
+      int size,
+      StructFieldType type,
+      boolean isInt,
+      boolean isUint,
+      int bitWidth,
+      long bitMask) {
+    var desc = assertDoesNotThrow(() -> db.add("test", schema + "[2]"));
+    assertEquals(desc.getName(), "test");
+    assertEquals(desc.getSchema(), schema + "[2]");
+    var fields = desc.getFields();
+    assertEquals(fields.size(), 1);
+    var field = fields.get(0);
+    assertEquals(field.getParent(), desc);
+    assertEquals(field.getName(), "a");
+    assertEquals(field.isInt(), isInt);
+    assertEquals(field.isUint(), isUint);
+    assertTrue(field.isArray());
+    assertEquals(field.getArraySize(), 2);
+    if (type != StructFieldType.kStruct) {
+      assertTrue(desc.isValid());
+      assertEquals(desc.getSize(), size * 2);
+    } else {
+      assertFalse(desc.isValid());
+      assertNotNull(field.getStruct());
+    }
+  }
+}
diff --git a/wpiutil/src/test/java/edu/wpi/first/util/struct/parser/ParserTest.java b/wpiutil/src/test/java/edu/wpi/first/util/struct/parser/ParserTest.java
new file mode 100644
index 0000000..52ba8da
--- /dev/null
+++ b/wpiutil/src/test/java/edu/wpi/first/util/struct/parser/ParserTest.java
@@ -0,0 +1,212 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.util.struct.parser;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class ParserTest {
+  @Test
+  void testEmpty() {
+    Parser p = new Parser("");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertTrue(schema.declarations.isEmpty());
+  }
+
+  @Test
+  void testEmptySemicolon() {
+    Parser p = new Parser(";");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertTrue(schema.declarations.isEmpty());
+  }
+
+  @Test
+  void testSimple() {
+    Parser p = new Parser("int32 a");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.arraySize, 1);
+  }
+
+  @Test
+  void testSimpleTrailingSemi() {
+    Parser p = new Parser("int32 a;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+  }
+
+  @Test
+  void testArray() {
+    Parser p = new Parser("int32 a[2]");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.arraySize, 2);
+  }
+
+  @Test
+  void testArrayTrailingSemi() {
+    Parser p = new Parser("int32 a[2];");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+  }
+
+  @Test
+  void testBitfield() {
+    Parser p = new Parser("int32 a:2");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.bitWidth, 2);
+  }
+
+  @Test
+  void testBitfieldTrailingSemi() {
+    Parser p = new Parser("int32 a:2;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+  }
+
+  @Test
+  void testEnumKeyword() {
+    Parser p = new Parser("enum {x=1} int32 a;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.enumValues.size(), 1);
+    assertEquals(decl.enumValues.get("x"), 1);
+  }
+
+  @Test
+  void testEnumNoKeyword() {
+    Parser p = new Parser("{x=1} int32 a;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.enumValues.size(), 1);
+    assertEquals(decl.enumValues.get("x"), 1);
+  }
+
+  @Test
+  void testEnumNoValues() {
+    Parser p = new Parser("{} int32 a;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertTrue(decl.enumValues.isEmpty());
+  }
+
+  @Test
+  void testEnumMultipleValues() {
+    Parser p = new Parser("{x=1,y=-2} int32 a;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.enumValues.size(), 2);
+    assertEquals(decl.enumValues.get("x"), 1);
+    assertEquals(decl.enumValues.get("y"), -2);
+  }
+
+  @Test
+  void testEnumTrailingComma() {
+    Parser p = new Parser("{x=1,y=2,} int32 a;");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 1);
+    var decl = schema.declarations.get(0);
+    assertEquals(decl.typeString, "int32");
+    assertEquals(decl.name, "a");
+    assertEquals(decl.enumValues.size(), 2);
+    assertEquals(decl.enumValues.get("x"), 1);
+    assertEquals(decl.enumValues.get("y"), 2);
+  }
+
+  @Test
+  void testMultipleNoTrailingSemi() {
+    Parser p = new Parser("int32 a; int16 b");
+    ParsedSchema schema = assertDoesNotThrow(() -> p.parse());
+    assertEquals(schema.declarations.size(), 2);
+    assertEquals(schema.declarations.get(0).typeString, "int32");
+    assertEquals(schema.declarations.get(0).name, "a");
+    assertEquals(schema.declarations.get(1).typeString, "int16");
+    assertEquals(schema.declarations.get(1).name, "b");
+  }
+
+  @Test
+  void testErrBitfieldArray() {
+    Parser p = new Parser("int32 a[1]:2");
+    assertThrows(ParseException.class, () -> p.parse(), "10: expected ';', got ':'");
+  }
+
+  @Test
+  void testErrNoArrayValue() {
+    Parser p = new Parser("int32 a[]");
+    assertThrows(ParseException.class, () -> p.parse(), "8: expected integer, got ']'");
+  }
+
+  @Test
+  void testErrNoBitfieldValue() {
+    Parser p = new Parser("int32 a:");
+    assertThrows(ParseException.class, () -> p.parse(), "8: expected integer, got ''");
+  }
+
+  @Test
+  void testErrNoNameArray() {
+    Parser p = new Parser("int32 [2]");
+    assertThrows(ParseException.class, () -> p.parse(), "6: expected identifier, got '['");
+  }
+
+  @Test
+  void testErrNoNameBitField() {
+    Parser p = new Parser("int32 :2");
+    assertThrows(ParseException.class, () -> p.parse(), "6: expected identifier, got ':'");
+  }
+
+  @Test
+  void testNegativeBitField() {
+    Parser p = new Parser("int32 a:-1");
+    assertThrows(
+        ParseException.class, () -> p.parse(), "8: bitfield width '-1' is not a positive integer");
+  }
+
+  @Test
+  void testNegativeArraySize() {
+    Parser p = new Parser("int32 a[-1]");
+    assertThrows(
+        ParseException.class, () -> p.parse(), "8: array size '-1' is not a positive integer");
+  }
+
+  @Test
+  void testZeroBitField() {
+    Parser p = new Parser("int32 a:0");
+    assertThrows(
+        ParseException.class, () -> p.parse(), "8: bitfield width '0' is not a positive integer");
+  }
+
+  @Test
+  void testZeroArraySize() {
+    Parser p = new Parser("int32 a[0]");
+    assertThrows(
+        ParseException.class, () -> p.parse(), "8: array size '0' is not a positive integer");
+  }
+}
diff --git a/wpiutil/src/test/native/cpp/ArrayTest.cpp b/wpiutil/src/test/native/cpp/ArrayTest.cpp
index 1f28157..f70b201 100644
--- a/wpiutil/src/test/native/cpp/ArrayTest.cpp
+++ b/wpiutil/src/test/native/cpp/ArrayTest.cpp
@@ -2,7 +2,8 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
 #include "wpi/array.h"
 
 namespace {
diff --git a/wpiutil/src/test/native/cpp/Base64Test.cpp b/wpiutil/src/test/native/cpp/Base64Test.cpp
index 542858d..514bb55 100644
--- a/wpiutil/src/test/native/cpp/Base64Test.cpp
+++ b/wpiutil/src/test/native/cpp/Base64Test.cpp
@@ -2,7 +2,8 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
 #include "wpi/Base64.h"
 #include "wpi/SmallString.h"
 
diff --git a/wpiutil/src/test/native/cpp/CircularBufferTest.cpp b/wpiutil/src/test/native/cpp/CircularBufferTest.cpp
index ad2285e..a56e2e5 100644
--- a/wpiutil/src/test/native/cpp/CircularBufferTest.cpp
+++ b/wpiutil/src/test/native/cpp/CircularBufferTest.cpp
@@ -6,7 +6,7 @@
 
 #include <array>
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 static const std::array<double, 10> values = {
     {751.848, 766.366, 342.657, 234.252, 716.126, 132.344, 445.697, 22.727,
diff --git a/wpiutil/src/test/native/cpp/ScopeExitTest.cpp b/wpiutil/src/test/native/cpp/ScopeExitTest.cpp
index 9cecb1c..d6f99ca 100644
--- a/wpiutil/src/test/native/cpp/ScopeExitTest.cpp
+++ b/wpiutil/src/test/native/cpp/ScopeExitTest.cpp
@@ -2,7 +2,8 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
 #include "wpi/scope"
 
 TEST(ScopeExitTest, ScopeExit) {
@@ -23,6 +24,7 @@
   {
     wpi::scope_exit exit1{[&] { ++exitCount; }};
     wpi::scope_exit exit2 = std::move(exit1);
+    // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
     wpi::scope_exit exit3 = std::move(exit1);
     EXPECT_EQ(0, exitCount);
   }
diff --git a/wpiutil/src/test/native/cpp/StaticCircularBufferTest.cpp b/wpiutil/src/test/native/cpp/StaticCircularBufferTest.cpp
index f95f9cb..338bd8e 100644
--- a/wpiutil/src/test/native/cpp/StaticCircularBufferTest.cpp
+++ b/wpiutil/src/test/native/cpp/StaticCircularBufferTest.cpp
@@ -6,7 +6,7 @@
 
 #include <array>
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 static const std::array<double, 10> values = {
     {751.848, 766.366, 342.657, 234.252, 716.126, 132.344, 445.697, 22.727,
diff --git a/wpiutil/src/test/native/cpp/SynchronizationTest.cpp b/wpiutil/src/test/native/cpp/SynchronizationTest.cpp
index a349c54..70d6d13 100644
--- a/wpiutil/src/test/native/cpp/SynchronizationTest.cpp
+++ b/wpiutil/src/test/native/cpp/SynchronizationTest.cpp
@@ -6,7 +6,7 @@
 
 #include <thread>
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 TEST(EventTest, AutoReset) {
   auto event = wpi::CreateEvent(false, false);
diff --git a/wpiutil/src/test/native/cpp/UidVectorTest.cpp b/wpiutil/src/test/native/cpp/UidVectorTest.cpp
index f9e1624..dda7d79 100644
--- a/wpiutil/src/test/native/cpp/UidVectorTest.cpp
+++ b/wpiutil/src/test/native/cpp/UidVectorTest.cpp
@@ -4,7 +4,7 @@
 
 #include "wpi/UidVector.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 namespace wpi {
 
diff --git a/wpiutil/src/test/native/cpp/UnescapeCStringTest.cpp b/wpiutil/src/test/native/cpp/UnescapeCStringTest.cpp
index 7f0ca5f..8b35b97 100644
--- a/wpiutil/src/test/native/cpp/UnescapeCStringTest.cpp
+++ b/wpiutil/src/test/native/cpp/UnescapeCStringTest.cpp
@@ -2,7 +2,8 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
 #include "wpi/SmallString.h"
 #include "wpi/StringExtras.h"
 
diff --git a/wpiutil/src/test/native/cpp/ct_string_test.cpp b/wpiutil/src/test/native/cpp/ct_string_test.cpp
new file mode 100644
index 0000000..6c3c7d0
--- /dev/null
+++ b/wpiutil/src/test/native/cpp/ct_string_test.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/ct_string.h"  // NOLINT(build/include_order)
+
+#include <string>
+#include <string_view>
+
+#include <gtest/gtest.h>
+
+TEST(CtStringTest, Concat) {
+  using namespace wpi::literals;
+  constexpr std::string_view astring = "name";
+  constexpr int arrsize = 5;
+  constexpr auto str = Concat(
+      wpi::ct_string<char, std::char_traits<char>, astring.size()>{astring},
+      "["_ct_string, wpi::NumToCtString<arrsize>(), "]"_ct_string);
+  static_assert(str.size() == 7);
+  ASSERT_EQ(std::string{str}, "name[5]");
+}
+
+TEST(CtStringTest, OperatorPlus) {
+  using namespace wpi::literals;
+  constexpr std::string_view astring = "name";
+  constexpr auto str =
+      wpi::ct_string<char, std::char_traits<char>, astring.size()>{astring} +
+      "[]"_ct_string;
+  static_assert(str.size() == 6);
+  ASSERT_EQ(std::string{str}, "name[]");
+}
+
+TEST(CtStringTest, StringViewConversion) {
+  using namespace wpi::literals;
+  constexpr auto str = "[]"_ct_string;
+  std::string_view sv = str;
+  ASSERT_EQ(sv, "[]");
+}
diff --git a/wpiutil/src/test/native/cpp/future_test.cpp b/wpiutil/src/test/native/cpp/future_test.cpp
index 8817f2d..97e5e60 100644
--- a/wpiutil/src/test/native/cpp/future_test.cpp
+++ b/wpiutil/src/test/native/cpp/future_test.cpp
@@ -4,10 +4,10 @@
 
 #include "wpi/future.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"  // NOLINT(build/include_order)
-
 #include <thread>
 
+#include <gtest/gtest.h>
+
 namespace wpi {
 
 TEST(FutureTest, Then) {
diff --git a/wpiutil/src/test/native/cpp/json/unit-algorithms.cpp b/wpiutil/src/test/native/cpp/json/unit-algorithms.cpp
deleted file mode 100644
index f1a8745..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-algorithms.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-#include <algorithm>
-
-class JsonAlgorithmsTest : public ::testing::Test {
- protected:
-    json j_array = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz"};
-    json j_object = {{"one", 1}, {"two", 2}};
-};
-
-// non-modifying sequence operations
-TEST_F(JsonAlgorithmsTest, AllOf)
-{
-    EXPECT_TRUE(std::all_of(j_array.begin(), j_array.end(), [](const json & value)
-    {
-        return value.size() > 0;
-    }));
-    EXPECT_TRUE(std::all_of(j_object.begin(), j_object.end(), [](const json & value)
-    {
-        return value.type() == json::value_t::number_integer;
-    }));
-}
-
-TEST_F(JsonAlgorithmsTest, AnyOf)
-{
-    EXPECT_TRUE(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
-    {
-        return value.is_string() && value.get<std::string>() == "foo";
-    }));
-    EXPECT_TRUE(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
-    {
-        return value.get<int>() > 1;
-    }));
-}
-
-TEST_F(JsonAlgorithmsTest, NoneOf)
-{
-    EXPECT_TRUE(std::none_of(j_array.begin(), j_array.end(), [](const json & value)
-    {
-        return value.size() == 0;
-    }));
-    EXPECT_TRUE(std::none_of(j_object.begin(), j_object.end(), [](const json & value)
-    {
-        return value.get<int>() <= 0;
-    }));
-}
-
-TEST_F(JsonAlgorithmsTest, ForEachReading)
-{
-    int sum = 0;
-
-    std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value)
-    {
-        if (value.is_number())
-        {
-            sum += static_cast<int>(value);
-        }
-    });
-
-    EXPECT_EQ(sum, 45);
-}
-
-TEST_F(JsonAlgorithmsTest, ForEachWriting)
-{
-    auto add17 = [](json & value)
-    {
-        if (value.is_array())
-        {
-            value.push_back(17);
-        }
-    };
-
-    std::for_each(j_array.begin(), j_array.end(), add17);
-
-    EXPECT_EQ(j_array[6], json({1, 2, 3, 17}));
-}
-
-TEST_F(JsonAlgorithmsTest, Count)
-{
-    EXPECT_EQ(std::count(j_array.begin(), j_array.end(), json(true)), 1);
-}
-
-TEST_F(JsonAlgorithmsTest, CountIf)
-{
-    auto count1 = std::count_if(j_array.begin(), j_array.end(), [](const json & value)
-    {
-        return (value.is_number());
-    });
-    EXPECT_EQ(count1, 3);
-    auto count2 = std::count_if(j_array.begin(), j_array.end(), [](const json&)
-    {
-        return true;
-    });
-    EXPECT_EQ(count2, 9);
-}
-
-TEST_F(JsonAlgorithmsTest, Mismatch)
-{
-    json j_array2 = {13, 29, 3, {{"one", 1}, {"two", 2}, {"three", 3}}, true, false, {1, 2, 3}, "foo", "baz"};
-    auto res = std::mismatch(j_array.begin(), j_array.end(), j_array2.begin());
-    EXPECT_EQ(*res.first, json({{"one", 1}, {"two", 2}}));
-    EXPECT_EQ(*res.second, json({{"one", 1}, {"two", 2}, {"three", 3}}));
-}
-
-TEST_F(JsonAlgorithmsTest, EqualOperatorEquals)
-{
-    EXPECT_TRUE(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
-    EXPECT_TRUE(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
-    EXPECT_FALSE(std::equal(j_array.begin(), j_array.end(), j_object.begin()));
-}
-
-TEST_F(JsonAlgorithmsTest, EqualUserComparison)
-{
-    // compare objects only by size of its elements
-    json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
-    EXPECT_FALSE(std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
-    EXPECT_TRUE(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
-                     [](const json & a, const json & b)
-    {
-        return (a.size() == b.size());
-    }));
-}
-
-TEST_F(JsonAlgorithmsTest, Find)
-{
-    auto it = std::find(j_array.begin(), j_array.end(), json(false));
-    EXPECT_EQ(std::distance(j_array.begin(), it), 5);
-}
-
-TEST_F(JsonAlgorithmsTest, FindIf)
-{
-    auto it = std::find_if(j_array.begin(), j_array.end(),
-                           [](const json & value)
-    {
-        return value.is_boolean();
-    });
-    EXPECT_EQ(std::distance(j_array.begin(), it), 4);
-}
-
-TEST_F(JsonAlgorithmsTest, FindIfNot)
-{
-    auto it = std::find_if_not(j_array.begin(), j_array.end(),
-                               [](const json & value)
-    {
-        return value.is_number();
-    });
-    EXPECT_EQ(std::distance(j_array.begin(), it), 3);
-}
-
-TEST_F(JsonAlgorithmsTest, AdjacentFind)
-{
-    EXPECT_EQ(std::adjacent_find(j_array.begin(), j_array.end()), j_array.end());
-    auto it = std::adjacent_find(j_array.begin(), j_array.end(),
-                             [](const json & v1, const json & v2)
-    {
-        return v1.type() == v2.type();
-    });
-    EXPECT_EQ(it, j_array.begin());
-}
-
-// modifying sequence operations
-TEST_F(JsonAlgorithmsTest, Reverse)
-{
-    std::reverse(j_array.begin(), j_array.end());
-    EXPECT_EQ(j_array, json({"baz", "foo", {1, 2, 3}, false, true, {{"one", 1}, {"two", 2}}, 3, 29, 13}));
-}
-
-TEST_F(JsonAlgorithmsTest, Rotate)
-{
-    std::rotate(j_array.begin(), j_array.begin() + 1, j_array.end());
-    EXPECT_EQ(j_array, json({29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", 13}));
-}
-
-TEST_F(JsonAlgorithmsTest, Partition)
-{
-    auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v)
-    {
-        return v.is_string();
-    });
-    EXPECT_EQ(std::distance(j_array.begin(), it), 2);
-    EXPECT_FALSE(it[2].is_string());
-}
-
-// sorting operations
-TEST_F(JsonAlgorithmsTest, SortOperatorEquals)
-{
-    json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
-    std::sort(j.begin(), j.end());
-    EXPECT_EQ(j, json({nullptr, false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
-}
-
-TEST_F(JsonAlgorithmsTest, SortUserComparison)
-{
-    json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr};
-    std::sort(j.begin(), j.end(), [](const json & a, const json & b)
-    {
-        return a.size() < b.size();
-    });
-    EXPECT_EQ(j, json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}}));
-}
-
-TEST_F(JsonAlgorithmsTest, SortObject)
-{
-    json j({{"one", 1}, {"two", 2}});
-    EXPECT_THROW_MSG(std::sort(j.begin(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-}
-
-TEST_F(JsonAlgorithmsTest, PartialSort)
-{
-    json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
-    std::partial_sort(j.begin(), j.begin() + 4, j.end());
-    EXPECT_EQ(j, json({nullptr, false, true, 3, {{"one", 1}, {"two", 2}}, 29, {1, 2, 3}, "foo", "baz", 13}));
-}
-
-// set operations
-TEST_F(JsonAlgorithmsTest, Merge)
-{
-    json j1 = {2, 4, 6, 8};
-    json j2 = {1, 2, 3, 5, 7};
-    json j3;
-
-    std::merge(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
-    EXPECT_EQ(j3, json({1, 2, 2, 3, 4, 5, 6, 7, 8}));
-}
-
-TEST_F(JsonAlgorithmsTest, SetDifference)
-{
-    json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
-    json j2 = {1, 2, 3, 5, 7};
-    json j3;
-
-    std::set_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
-    EXPECT_EQ(j3, json({4, 6, 8}));
-}
-
-TEST_F(JsonAlgorithmsTest, SetIntersection)
-{
-    json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
-    json j2 = {1, 2, 3, 5, 7};
-    json j3;
-
-    std::set_intersection(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
-    EXPECT_EQ(j3, json({1, 2, 3, 5, 7}));
-}
-
-TEST_F(JsonAlgorithmsTest, SetUnion)
-{
-    json j1 = {2, 4, 6, 8};
-    json j2 = {1, 2, 3, 5, 7};
-    json j3;
-
-    std::set_union(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
-    EXPECT_EQ(j3, json({1, 2, 3, 4, 5, 6, 7, 8}));
-}
-
-TEST_F(JsonAlgorithmsTest, SetSymmetricDifference)
-{
-    json j1 = {2, 4, 6, 8};
-    json j2 = {1, 2, 3, 5, 7};
-    json j3;
-
-    std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
-    EXPECT_EQ(j3, json({1, 3, 4, 5, 6, 7, 8}));
-}
-
-TEST_F(JsonAlgorithmsTest, HeapOperations)
-{
-    std::make_heap(j_array.begin(), j_array.end());
-    EXPECT_TRUE(std::is_heap(j_array.begin(), j_array.end()));
-    std::sort_heap(j_array.begin(), j_array.end());
-    EXPECT_EQ(j_array, json({false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-capacity.cpp b/wpiutil/src/test/native/cpp/json/unit-capacity.cpp
deleted file mode 100644
index 8f5433e..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-capacity.cpp
+++ /dev/null
@@ -1,528 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonEmptyTest, Boolean)
-{
-    json j = true;
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, String)
-{
-    json j = "hello world";
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, ArrayEmpty)
-{
-    json j = json::array();
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_TRUE(j.empty());
-        EXPECT_TRUE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, ArrayFilled)
-{
-    json j = {1, 2, 3};
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, ObjectEmpty)
-{
-    json j = json::object();
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_TRUE(j.empty());
-        EXPECT_TRUE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, ObjectFilled)
-{
-    json j = {{"one", 1}, {"two", 2}, {"three", 3}};
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, NumberInteger)
-{
-    json j = 23;
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, NumberUnsigned)
-{
-    json j = 23u;
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, NumberFloat)
-{
-    json j = 23.42;
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_FALSE(j.empty());
-        EXPECT_FALSE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonEmptyTest, Null)
-{
-    json j = nullptr;
-    json j_const(j);
-
-    // result of empty
-    {
-        EXPECT_TRUE(j.empty());
-        EXPECT_TRUE(j_const.empty());
-    }
-
-    // definition of empty
-    {
-        EXPECT_EQ(j.empty(), (j.begin() == j.end()));
-        EXPECT_EQ(j_const.empty(), (j_const.begin() == j_const.end()));
-    }
-}
-
-TEST(JsonSizeTest, Boolean)
-{
-    json j = true;
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 1u);
-        EXPECT_EQ(j_const.size(), 1u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, String)
-{
-    json j = "hello world";
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 1u);
-        EXPECT_EQ(j_const.size(), 1u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, ArrayEmpty)
-{
-    json j = json::array();
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 0u);
-        EXPECT_EQ(j_const.size(), 0u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, ArrayFilled)
-{
-    json j = {1, 2, 3};
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 3u);
-        EXPECT_EQ(j_const.size(), 3u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, ObjectEmpty)
-{
-    json j = json::object();
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 0u);
-        EXPECT_EQ(j_const.size(), 0u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, ObjectFilled)
-{
-    json j = {{"one", 1}, {"two", 2}, {"three", 3}};
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 3u);
-        EXPECT_EQ(j_const.size(), 3u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, NumberInteger)
-{
-    json j = 23;
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 1u);
-        EXPECT_EQ(j_const.size(), 1u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, NumberUnsigned)
-{
-    json j = 23u;
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 1u);
-        EXPECT_EQ(j_const.size(), 1u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, NumberFloat)
-{
-    json j = 23.42;
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 1u);
-        EXPECT_EQ(j_const.size(), 1u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonSizeTest, Null)
-{
-    json j = nullptr;
-    json j_const(j);
-
-    // result of size
-    {
-        EXPECT_EQ(j.size(), 0u);
-        EXPECT_EQ(j_const.size(), 0u);
-    }
-
-    // definition of size
-    {
-        EXPECT_EQ(std::distance(j.begin(), j.end()), static_cast<int>(j.size()));
-        EXPECT_EQ(std::distance(j_const.begin(), j_const.end()),
-                  static_cast<int>(j_const.size()));
-    }
-}
-
-TEST(JsonMaxSizeTest, Boolean)
-{
-    json j = true;
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_EQ(j.max_size(), 1u);
-        EXPECT_EQ(j_const.max_size(), 1u);
-    }
-}
-
-TEST(JsonMaxSizeTest, String)
-{
-    json j = "hello world";
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_EQ(j.max_size(), 1u);
-        EXPECT_EQ(j_const.max_size(), 1u);
-    }
-}
-
-TEST(JsonMaxSizeTest, ArrayEmpty)
-{
-    json j = json::array();
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_GE(j.max_size(), j.size());
-        EXPECT_GE(j_const.max_size(), j_const.size());
-    }
-}
-
-TEST(JsonMaxSizeTest, ArrayFilled)
-{
-    json j = {1, 2, 3};
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_GE(j.max_size(), j.size());
-        EXPECT_GE(j_const.max_size(), j_const.size());
-    }
-}
-
-TEST(JsonMaxSizeTest, ObjectEmpty)
-{
-    json j = json::object();
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_GE(j.max_size(), j.size());
-        EXPECT_GE(j_const.max_size(), j_const.size());
-    }
-}
-
-TEST(JsonMaxSizeTest, ObjectFilled)
-{
-    json j = {{"one", 1}, {"two", 2}, {"three", 3}};
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_GE(j.max_size(), j.size());
-        EXPECT_GE(j_const.max_size(), j_const.size());
-    }
-}
-
-TEST(JsonMaxSizeTest, NumberInteger)
-{
-    json j = 23;
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_EQ(j.max_size(), 1u);
-        EXPECT_EQ(j_const.max_size(), 1u);
-    }
-}
-
-TEST(JsonMaxSizeTest, NumberUnsigned)
-{
-    json j = 23u;
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_EQ(j.max_size(), 1u);
-        EXPECT_EQ(j_const.max_size(), 1u);
-    }
-}
-
-TEST(JsonMaxSizeTest, NumberFloat)
-{
-    json j = 23.42;
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_EQ(j.max_size(), 1u);
-        EXPECT_EQ(j_const.max_size(), 1u);
-    }
-}
-
-TEST(JsonMaxSizeTest, Null)
-{
-    json j = nullptr;
-    json j_const(j);
-
-    // result of max_size
-    {
-        EXPECT_EQ(j.max_size(), 0u);
-        EXPECT_EQ(j_const.max_size(), 0u);
-    }
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-cbor.cpp b/wpiutil/src/test/native/cpp/json/unit-cbor.cpp
deleted file mode 100644
index dfb3b60..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-cbor.cpp
+++ /dev/null
@@ -1,1704 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-
-#include <cmath>
-
-using wpi::json;
-
-#include <fstream>
-
-TEST(CborDiscardedTest, Case)
-{
-    // discarded values are not serialized
-    json j = json::value_t::discarded;
-    const auto result = json::to_cbor(j);
-    ASSERT_TRUE(result.empty());
-}
-
-TEST(CborNullTest, Case)
-{
-    json j = nullptr;
-    std::vector<uint8_t> expected = {0xf6};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-TEST(CborBooleanTest, True)
-{
-    json j = true;
-    std::vector<uint8_t> expected = {0xf5};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-TEST(CborBooleanTest, False)
-{
-    json j = false;
-    std::vector<uint8_t> expected = {0xf4};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// -9223372036854775808..-4294967297
-class CborSignedNeg8Test : public ::testing::TestWithParam<int64_t> {};
-TEST_P(CborSignedNeg8Test, Case)
-{
-    // create JSON value with integer number
-    json j = GetParam();
-
-    // check type
-    ASSERT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0x3b));
-    uint64_t positive = static_cast<uint64_t>(-1 - GetParam());
-    expected.push_back(static_cast<uint8_t>((positive >> 56) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 48) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 40) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 32) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(positive & 0xff));
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), 9u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], 0x3b);
-    uint64_t restored = (static_cast<uint64_t>(static_cast<uint8_t>(result[1])) << 070) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[2])) << 060) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[3])) << 050) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[4])) << 040) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[5])) << 030) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[6])) << 020) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[7])) << 010) +
-                        static_cast<uint64_t>(static_cast<uint8_t>(result[8]));
-    EXPECT_EQ(restored, positive);
-    EXPECT_EQ(-1 - static_cast<int64_t>(restored), GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-static const int64_t neg8_numbers[] = {
-    INT64_MIN,
-    -1000000000000000000,
-    -100000000000000000,
-    -10000000000000000,
-    -1000000000000000,
-    -100000000000000,
-    -10000000000000,
-    -1000000000000,
-    -100000000000,
-    -10000000000,
-    -4294967297,
-};
-
-INSTANTIATE_TEST_SUITE_P(CborSignedNeg8Tests, CborSignedNeg8Test,
-                        ::testing::ValuesIn(neg8_numbers));
-
-// -4294967296..-65537
-class CborSignedNeg4Test : public ::testing::TestWithParam<int64_t> {};
-TEST_P(CborSignedNeg4Test, Case)
-{
-    // create JSON value with integer number
-    json j = GetParam();
-
-    // check type
-    ASSERT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0x3a));
-    uint32_t positive = static_cast<uint32_t>(static_cast<uint64_t>(-1 - GetParam()) & 0x00000000ffffffff);
-    expected.push_back(static_cast<uint8_t>((positive >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((positive >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(positive & 0xff));
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), 5u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], 0x3a);
-    uint32_t restored = (static_cast<uint32_t>(static_cast<uint8_t>(result[1])) << 030) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[2])) << 020) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[3])) << 010) +
-                        static_cast<uint32_t>(static_cast<uint8_t>(result[4]));
-    EXPECT_EQ(restored, positive);
-    EXPECT_EQ(-1ll - restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-static const int64_t neg4_numbers[] = {
-    -65537,
-    -100000,
-    -1000000,
-    -10000000,
-    -100000000,
-    -1000000000,
-    -4294967296,
-};
-
-INSTANTIATE_TEST_SUITE_P(CborSignedNeg4Tests, CborSignedNeg4Test,
-                        ::testing::ValuesIn(neg4_numbers));
-
-// -65536..-257
-TEST(CborSignedTest, Neg2)
-{
-    for (int32_t i = -65536; i <= -257; ++i) {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x39));
-        uint16_t positive = static_cast<uint16_t>(-1 - i);
-        expected.push_back(static_cast<uint8_t>((positive >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(positive & 0xff));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0x39);
-        uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
-        EXPECT_EQ(restored, positive);
-        EXPECT_EQ(-1 - restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// -9263 (int 16)
-TEST(CborSignedTest, NegInt16)
-{
-    json j = -9263;
-    std::vector<uint8_t> expected = {0x39,0x24,0x2e};
-
-    const auto result = json::to_cbor(j);
-    ASSERT_EQ(result, expected);
-
-    int16_t restored = static_cast<int16_t>(-1 - ((result[1] << 8) + result[2]));
-    EXPECT_EQ(restored, -9263);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// -256..-24
-TEST(CborSignedTest, Neg1)
-{
-    for (auto i = -256; i < -24; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x38));
-        expected.push_back(static_cast<uint8_t>(-1 - i));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 2u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0x38);
-        EXPECT_EQ(static_cast<int16_t>(-1 - static_cast<uint8_t>(result[1])), i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// -24..-1
-TEST(CborSignedTest, Neg0)
-{
-    for (auto i = -24; i <= -1; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x20 - 1 - static_cast<uint8_t>(i)));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 1u);
-
-        // check individual bytes
-        EXPECT_EQ(static_cast<int8_t>(0x20 - 1 - result[0]), i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 0..23
-TEST(CborSignedTest, Pos0)
-{
-    for (size_t i = 0; i <= 23; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = -1;
-        j.get_ref<int64_t&>() = static_cast<int64_t>(i);
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 1u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(i));
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 24..255
-TEST(CborSignedTest, Pos1)
-{
-    for (size_t i = 24; i <= 255; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = -1;
-        j.get_ref<int64_t&>() = static_cast<int64_t>(i);
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x18));
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 2u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0x18);
-        EXPECT_EQ(result[1], static_cast<uint8_t>(i));
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 256..65535
-TEST(CborSignedTest, Pos2)
-{
-    for (size_t i = 256; i <= 65535; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = -1;
-        j.get_ref<int64_t&>() = static_cast<int64_t>(i);
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x19));
-        expected.push_back(static_cast<uint8_t>((i >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(i & 0xff));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0x19);
-        uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 65536..4294967295
-class CborSignedPos4Test : public ::testing::TestWithParam<uint32_t> {};
-TEST_P(CborSignedPos4Test, Case)
-{
-    // create JSON value with integer number
-    json j = -1;
-    j.get_ref<int64_t&>() =
-        static_cast<int64_t>(GetParam());
-
-    // check type
-    ASSERT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(0x1a);
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), 5u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], 0x1a);
-    uint32_t restored = (static_cast<uint32_t>(static_cast<uint8_t>(result[1])) << 030) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[2])) << 020) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[3])) << 010) +
-                        static_cast<uint32_t>(static_cast<uint8_t>(result[4]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-static const uint32_t pos4_numbers[] = {
-    65536u,
-    77777u,
-    1048576u,
-};
-
-INSTANTIATE_TEST_SUITE_P(CborSignedPos4Tests, CborSignedPos4Test,
-                        ::testing::ValuesIn(pos4_numbers));
-
-// 4294967296..4611686018427387903
-class CborSignedPos8Test : public ::testing::TestWithParam<uint64_t> {};
-TEST_P(CborSignedPos8Test, Case)
-{
-    // create JSON value with integer number
-    json j = -1;
-    j.get_ref<int64_t&>() =
-        static_cast<int64_t>(GetParam());
-
-    // check type
-    ASSERT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(0x1b);
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 070) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 060) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 050) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 040) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 030) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 020) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 010) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), 9u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], 0x1b);
-    uint64_t restored = (static_cast<uint64_t>(static_cast<uint8_t>(result[1])) << 070) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[2])) << 060) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[3])) << 050) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[4])) << 040) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[5])) << 030) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[6])) << 020) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[7])) << 010) +
-                        static_cast<uint64_t>(static_cast<uint8_t>(result[8]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-static const uint64_t pos8_numbers[] = {
-    4294967296ul,
-    4611686018427387903ul
-};
-
-INSTANTIATE_TEST_SUITE_P(CborSignedPos8Tests, CborSignedPos8Test,
-                        ::testing::ValuesIn(pos8_numbers));
-
-/*
-// -32768..-129 (int 16)
-{
-    for (int16_t i = -32768; i <= -129; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(0xd1);
-        expected.push_back(static_cast<uint8_t>((i >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(i & 0xff));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result == expected);
-        ASSERT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0xd1);
-        int16_t restored = (result[1] << 8) + result[2];
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-*/
-
-// 0..23 (Integer)
-TEST(CborUnsignedTest, Pos0)
-{
-    for (size_t i = 0; i <= 23; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with unsigned integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_unsigned());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 1u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(i));
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 24..255 (one-byte uint8_t)
-TEST(CborUnsignedTest, Pos1)
-{
-    for (size_t i = 24; i <= 255; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with unsigned integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_unsigned());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(0x18);
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 2u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0x18);
-        uint8_t restored = static_cast<uint8_t>(result[1]);
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 256..65535 (two-byte uint16_t)
-TEST(CborUnsignedTest, Pos2)
-{
-    for (size_t i = 256; i <= 65535; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with unsigned integer number
-        json j = i;
-
-        // check type
-        ASSERT_TRUE(j.is_number_unsigned());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(0x19);
-        expected.push_back(static_cast<uint8_t>((i >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(i & 0xff));
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], 0x19);
-        uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// 65536..4294967295 (four-byte uint32_t)
-class CborUnsignedPos4Test : public ::testing::TestWithParam<uint32_t> {};
-TEST_P(CborUnsignedPos4Test, Case)
-{
-    // create JSON value with unsigned integer number
-    json j = GetParam();
-
-    // check type
-    ASSERT_TRUE(j.is_number_unsigned());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(0x1a);
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), 5u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], 0x1a);
-    uint32_t restored = (static_cast<uint32_t>(static_cast<uint8_t>(result[1])) << 030) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[2])) << 020) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[3])) << 010) +
-                        static_cast<uint32_t>(static_cast<uint8_t>(result[4]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-INSTANTIATE_TEST_SUITE_P(CborUnsignedPos4Tests, CborUnsignedPos4Test,
-                        ::testing::ValuesIn(pos4_numbers));
-
-// 4294967296..4611686018427387903 (eight-byte uint64_t)
-class CborUnsignedPos8Test : public ::testing::TestWithParam<uint64_t> {};
-TEST_P(CborUnsignedPos8Test, Case)
-{
-    // create JSON value with integer number
-    json j = GetParam();
-
-    // check type
-    ASSERT_TRUE(j.is_number_unsigned());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(0x1b);
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 070) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 060) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 050) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 040) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 030) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 020) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 010) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), 9u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], 0x1b);
-    uint64_t restored = (static_cast<uint64_t>(static_cast<uint8_t>(result[1])) << 070) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[2])) << 060) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[3])) << 050) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[4])) << 040) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[5])) << 030) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[6])) << 020) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[7])) << 010) +
-                        static_cast<uint64_t>(static_cast<uint8_t>(result[8]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-INSTANTIATE_TEST_SUITE_P(CborUnsignedPos8Tests, CborUnsignedPos8Test,
-                        ::testing::ValuesIn(pos8_numbers));
-
-// 3.1415925
-TEST(CborFloatTest, Number)
-{
-    double v = 3.1415925;
-    json j = v;
-    std::vector<uint8_t> expected = {0xfb,0x40,0x09,0x21,0xfb,0x3f,0xa6,0xde,0xfc};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-    EXPECT_EQ(json::from_cbor(result), v);
-}
-
-TEST(CborFloatTest, HalfInfinity)
-{
-    json j = json::from_cbor(std::vector<uint8_t>({0xf9,0x7c,0x00}));
-    double d = j;
-    EXPECT_FALSE(std::isfinite(d));
-    EXPECT_EQ(j.dump(), "null");
-}
-
-TEST(CborFloatTest, HalfNaN)
-{
-    json j = json::from_cbor(std::vector<uint8_t>({0xf9,0x7c,0x01}));
-    double d = j;
-    EXPECT_TRUE(std::isnan(d));
-    EXPECT_EQ(j.dump(), "null");
-}
-
-// N = 0..23
-TEST(CborStringTest, String1)
-{
-    for (size_t N = 0; N <= 0x17; ++N)
-    {
-        SCOPED_TRACE(N);
-
-        // create JSON value with string containing of N * 'x'
-        const auto s = std::string(N, 'x');
-        json j = s;
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x60 + N));
-        for (size_t i = 0; i < N; ++i)
-        {
-            expected.push_back('x');
-        }
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), N + 1);
-        // check that no null byte is appended
-        if (N > 0)
-        {
-            EXPECT_NE(result.back(), '\x00');
-        }
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// N = 24..255
-TEST(CborStringTest, String2)
-{
-    for (size_t N = 24; N <= 255; ++N)
-    {
-        SCOPED_TRACE(N);
-
-        // create JSON value with string containing of N * 'x'
-        const auto s = std::string(N, 'x');
-        json j = s;
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0x78));
-        expected.push_back(static_cast<uint8_t>(N));
-        for (size_t i = 0; i < N; ++i)
-        {
-            expected.push_back('x');
-        }
-
-        // compare result + size
-        const auto result = json::to_cbor(j);
-        EXPECT_EQ(result, expected);
-        ASSERT_EQ(result.size(), N + 2);
-        // check that no null byte is appended
-        EXPECT_NE(result.back(), '\x00');
-
-        // roundtrip
-        EXPECT_EQ(json::from_cbor(result), j);
-    }
-}
-
-// N = 256..65535
-class CborString3Test : public ::testing::TestWithParam<size_t> {};
-TEST_P(CborString3Test, Case)
-{
-    // create JSON value with string containing of N * 'x'
-    const auto s = std::string(GetParam(), 'x');
-    json j = s;
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(0x79);
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-    for (size_t i = 0; i < GetParam(); ++i)
-    {
-        expected.push_back('x');
-    }
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), GetParam() + 3);
-    // check that no null byte is appended
-    EXPECT_NE(result.back(), '\x00');
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-static size_t string3_lens[] = {
-    256u,
-    999u,
-    1025u,
-    3333u,
-    2048u,
-    65535u
-};
-
-INSTANTIATE_TEST_SUITE_P(CborString3Tests, CborString3Test,
-                        ::testing::ValuesIn(string3_lens));
-
-// N = 65536..4294967295
-class CborString5Test : public ::testing::TestWithParam<size_t> {};
-TEST_P(CborString5Test, Case)
-{
-    // create JSON value with string containing of N * 'x'
-    const auto s = std::string(GetParam(), 'x');
-    json j = s;
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(0x7a);
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-    for (size_t i = 0; i < GetParam(); ++i)
-    {
-        expected.push_back('x');
-    }
-
-    // compare result + size
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-    ASSERT_EQ(result.size(), GetParam() + 5);
-    // check that no null byte is appended
-    EXPECT_NE(result.back(), '\x00');
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-static size_t string5_lens[] = {
-    65536u,
-    77777u,
-    1048576u
-};
-
-INSTANTIATE_TEST_SUITE_P(CborString5Tests, CborString5Test,
-                        ::testing::ValuesIn(string5_lens));
-
-TEST(CborArrayTest, Empty)
-{
-    json j = json::array();
-    std::vector<uint8_t> expected = {0x80};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// [null]
-TEST(CborArrayTest, Null)
-{
-    json j = {nullptr};
-    std::vector<uint8_t> expected = {0x81,0xf6};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// [1,2,3,4,5]
-TEST(CborArrayTest, Simple)
-{
-    json j = json::parse("[1,2,3,4,5]");
-    std::vector<uint8_t> expected = {0x85,0x01,0x02,0x03,0x04,0x05};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// [[[[]]]]
-TEST(CborArrayTest, NestEmpty)
-{
-    json j = json::parse("[[[[]]]]");
-    std::vector<uint8_t> expected = {0x81,0x81,0x81,0x80};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// array with uint16_t elements
-TEST(CborArrayTest, UInt16)
-{
-    json j(257, nullptr);
-    std::vector<uint8_t> expected(j.size() + 3, 0xf6); // all null
-    expected[0] = static_cast<uint8_t>(0x99); // array 16 bit
-    expected[1] = 0x01; // size (0x0101), byte 0
-    expected[2] = 0x01; // size (0x0101), byte 1
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// array with uint32_t elements
-TEST(CborArrayTest, UInt32)
-{
-    json j(65793, nullptr);
-    std::vector<uint8_t> expected(j.size() + 5, 0xf6); // all null
-    expected[0] = static_cast<uint8_t>(0x9a); // array 32 bit
-    expected[1] = 0x00; // size (0x00010101), byte 0
-    expected[2] = 0x01; // size (0x00010101), byte 1
-    expected[3] = 0x01; // size (0x00010101), byte 2
-    expected[4] = 0x01; // size (0x00010101), byte 3
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-/*
-// array with uint64_t elements
-TEST(CborArrayTest, UInt64)
-{
-    json j(4294967296, nullptr);
-    std::vector<uint8_t> expected(j.size() + 9, 0xf6); // all null
-    expected[0] = 0x9b; // array 64 bit
-    expected[1] = 0x00; // size (0x0000000100000000), byte 0
-    expected[2] = 0x00; // size (0x0000000100000000), byte 1
-    expected[3] = 0x00; // size (0x0000000100000000), byte 2
-    expected[4] = 0x01; // size (0x0000000100000000), byte 3
-    expected[5] = 0x00; // size (0x0000000100000000), byte 4
-    expected[6] = 0x00; // size (0x0000000100000000), byte 5
-    expected[7] = 0x00; // size (0x0000000100000000), byte 6
-    expected[8] = 0x00; // size (0x0000000100000000), byte 7
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-*/
-
-TEST(CborObjectTest, Empty)
-{
-    json j = json::object();
-    std::vector<uint8_t> expected = {0xa0};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// {"":null}
-TEST(CborObjectTest, EmptyKey)
-{
-    json j = {{"", nullptr}};
-    std::vector<uint8_t> expected = {0xa1,0x60,0xf6};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// {"a": {"b": {"c": {}}}}
-TEST(CborObjectTest, NestedEmpty)
-{
-    json j = json::parse("{\"a\": {\"b\": {\"c\": {}}}}");
-    std::vector<uint8_t> expected = {0xa1,0x61,0x61,0xa1,0x61,0x62,0xa1,0x61,0x63,0xa0};
-    const auto result = json::to_cbor(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// object with uint8_t elements
-TEST(CborObjectTest, UInt8)
-{
-    json j;
-    for (auto i = 0; i < 255; ++i)
-    {
-        // format i to a fixed width of 5
-        // each entry will need 7 bytes: 6 for string, 1 for null
-        std::stringstream ss;
-        ss << std::setw(5) << std::setfill('0') << i;
-        j.emplace(ss.str(), nullptr);
-    }
-
-    const auto result = json::to_cbor(j);
-
-    // Checking against an expected vector byte by byte is
-    // difficult, because no assumption on the order of key/value
-    // pairs are made. We therefore only check the prefix (type and
-    // size and the overall size. The rest is then handled in the
-    // roundtrip check.
-    ASSERT_EQ(result.size(), 1787u); // 1 type, 1 size, 255*7 content
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xb8)); // map 8 bit
-    EXPECT_EQ(result[1], static_cast<uint8_t>(0xff)); // size byte (0xff)
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// object with uint16_t elements
-TEST(CborObjectTest, UInt16)
-{
-    json j;
-    for (auto i = 0; i < 256; ++i)
-    {
-        // format i to a fixed width of 5
-        // each entry will need 7 bytes: 6 for string, 1 for null
-        std::stringstream ss;
-        ss << std::setw(5) << std::setfill('0') << i;
-        j.emplace(ss.str(), nullptr);
-    }
-
-    const auto result = json::to_cbor(j);
-
-    // Checking against an expected vector byte by byte is
-    // difficult, because no assumption on the order of key/value
-    // pairs are made. We therefore only check the prefix (type and
-    // size and the overall size. The rest is then handled in the
-    // roundtrip check.
-    ASSERT_EQ(result.size(), 1795u); // 1 type, 2 size, 256*7 content
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xb9)); // map 16 bit
-    EXPECT_EQ(result[1], 0x01); // byte 0 of size (0x0100)
-    EXPECT_EQ(result[2], 0x00); // byte 1 of size (0x0100)
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// object with uint32_t elements
-TEST(CborObjectTest, UInt32)
-{
-    json j;
-    for (auto i = 0; i < 65536; ++i)
-    {
-        // format i to a fixed width of 5
-        // each entry will need 7 bytes: 6 for string, 1 for null
-        std::stringstream ss;
-        ss << std::setw(5) << std::setfill('0') << i;
-        j.emplace(ss.str(), nullptr);
-    }
-
-    const auto result = json::to_cbor(j);
-
-    // Checking against an expected vector byte by byte is
-    // difficult, because no assumption on the order of key/value
-    // pairs are made. We therefore only check the prefix (type and
-    // size and the overall size. The rest is then handled in the
-    // roundtrip check.
-    ASSERT_EQ(result.size(), 458757u); // 1 type, 4 size, 65536*7 content
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xba)); // map 32 bit
-    EXPECT_EQ(result[1], 0x00); // byte 0 of size (0x00010000)
-    EXPECT_EQ(result[2], 0x01); // byte 1 of size (0x00010000)
-    EXPECT_EQ(result[3], 0x00); // byte 2 of size (0x00010000)
-    EXPECT_EQ(result[4], 0x00); // byte 3 of size (0x00010000)
-
-    // roundtrip
-    EXPECT_EQ(json::from_cbor(result), j);
-}
-
-// 0x7b (string)
-TEST(CborAdditionalDeserializationTest, Case7b)
-{
-    std::vector<uint8_t> given{0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x61};
-    json j = json::from_cbor(given);
-    EXPECT_EQ(j, "a");
-}
-
-// 0x9b (array)
-TEST(CborAdditionalDeserializationTest, Case9b)
-{
-    std::vector<uint8_t> given{0x9b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf4};
-    json j = json::from_cbor(given);
-    EXPECT_EQ(j, json::parse("[false]"));
-}
-
-// 0xbb (map)
-TEST(CborAdditionalDeserializationTest, Casebb)
-{
-    std::vector<uint8_t> given{0xbb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x60,0xf4};
-    json j = json::from_cbor(given);
-    EXPECT_EQ(j, json::parse("{\"\": false}"));
-}
-
-TEST(CborErrorTest, TooShortByteVector)
-{
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x18})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x19})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x19,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 3: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1a})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1a,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 3: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1a,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 4: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1a,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 5: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 3: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 4: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 5: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 6: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 7: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00,0x00,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 8: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 9: unexpected end of input");
-}
-
-TEST(CborErrorTest, UnsupportedBytesConcrete)
-{
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0x1c})), json::parse_error,
-                     "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0x1c");
-    EXPECT_THROW_MSG(json::from_cbor(std::vector<uint8_t>({0xf8})), json::parse_error,
-                     "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0xf8");
-}
-
-class CborUnsupportedBytesTest : public ::testing::TestWithParam<uint8_t> {
-};
-TEST_P(CborUnsupportedBytesTest, Case)
-{
-    EXPECT_THROW(json::from_cbor(std::vector<uint8_t>({GetParam()})), json::parse_error);
-}
-
-static const uint8_t unsupported_bytes_cases[] = {
-    // ?
-    0x1c, 0x1d, 0x1e, 0x1f,
-    // ?
-    0x3c, 0x3d, 0x3e, 0x3f,
-    // byte strings
-    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
-    // byte strings
-    0x58, 0x59, 0x5a, 0x5b,
-    // ?
-    0x5c, 0x5d, 0x5e,
-    // byte string
-    0x5f,
-    // ?
-    0x7c, 0x7d, 0x7e,
-    // ?
-    0x9c, 0x9d, 0x9e,
-    // ?
-    0xbc, 0xbd, 0xbe,
-    // date/time
-    0xc0, 0xc1,
-    // bignum
-    0xc2, 0xc3,
-    // fraction
-    0xc4,
-    // bigfloat
-    0xc5,
-    // tagged item
-    0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
-    // expected conversion
-    0xd5, 0xd6, 0xd7,
-    // more tagged items
-    0xd8, 0xd9, 0xda, 0xdb,
-    // ?
-    0xdc, 0xdd, 0xde, 0xdf,
-    // (simple value)
-    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
-    // undefined
-    0xf7,
-    // simple value
-    0xf8,
-};
-
-INSTANTIATE_TEST_SUITE_P(CborUnsupportedBytesTests, CborUnsupportedBytesTest,
-                        ::testing::ValuesIn(unsupported_bytes_cases));
-#if 0
-// use this testcase outside [hide] to run it with Valgrind
-TEST(CborRoundtripTest, Sample)
-{
-    std::string filename = "test/data/json_testsuite/sample.json";
-
-    // parse JSON file
-    std::ifstream f_json(filename);
-    json j1 = json::parse(f_json);
-
-    // parse CBOR file
-    std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
-    std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_cbor)),
-                                std::istreambuf_iterator<char>());
-    json j2;
-    j2 = json::from_cbor(packed);
-
-    // compare parsed JSON values
-    EXPECT_EQ(j1, j2);
-
-    // check with different start index
-    packed.insert(packed.begin(), 5, 0xff);
-    EXPECT_EQ(j1, json::from_cbor(packed, 5));
-}
-
-/*
-The following test cases were found during a two-day session with
-AFL-Fuzz. As a result, empty byte vectors and excessive lengths are
-detected.
-*/
-class CborRegressionFuzzTest : public ::testing::TestWithParam<const char*> {};
-TEST_P(CborRegressionFuzzTest, Case)
-{
-    try
-    {
-        // parse CBOR file
-        std::ifstream f_cbor(GetParam(), std::ios::binary);
-        std::vector<uint8_t> vec1(
-            (std::istreambuf_iterator<char>(f_cbor)),
-            std::istreambuf_iterator<char>());
-        json j1 = json::from_cbor(vec1);
-
-        try
-        {
-            // step 2: round trip
-            std::string vec2 = json::to_cbor(j1);
-
-            // parse serialization
-            json j2 = json::from_cbor(vec2);
-
-            // deserializations must match
-            EXPECT_EQ(j1, j2);
-        }
-        catch (const json::parse_error&)
-        {
-            // parsing a CBOR serialization must not fail
-            FAIL();
-        }
-    }
-    catch (const json::parse_error&)
-    {
-        // parse errors are ok, because input may be random bytes
-    }
-}
-
-static const char* fuzz_test_cases[] = {
-    "test/data/cbor_regression/test01",
-    "test/data/cbor_regression/test02",
-    "test/data/cbor_regression/test03",
-    "test/data/cbor_regression/test04",
-    "test/data/cbor_regression/test05",
-    "test/data/cbor_regression/test06",
-    "test/data/cbor_regression/test07",
-    "test/data/cbor_regression/test08",
-    "test/data/cbor_regression/test09",
-    "test/data/cbor_regression/test10",
-    "test/data/cbor_regression/test11",
-    "test/data/cbor_regression/test12",
-    "test/data/cbor_regression/test13",
-    "test/data/cbor_regression/test14",
-    "test/data/cbor_regression/test15",
-    "test/data/cbor_regression/test16",
-    "test/data/cbor_regression/test17",
-    "test/data/cbor_regression/test18",
-    "test/data/cbor_regression/test19",
-    "test/data/cbor_regression/test20",
-    "test/data/cbor_regression/test21",
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRegressionFuzzTests, CborRegressionFuzzTest,
-                        ::testing::ValuesIn(fuzz_test_cases));
-
-class CborRegressionFlynnTest : public ::testing::TestWithParam<const char*> {};
-TEST_F(CborRegressionFlynnTest, Case)
-{
-    // parse JSON file
-    std::ifstream f_json(GetParam());
-    json j1 = json::parse(f_json);
-
-    // parse CBOR file
-    std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
-    std::vector<uint8_t> packed(
-        (std::istreambuf_iterator<char>(f_cbor)),
-        std::istreambuf_iterator<char>());
-    json j2;
-    j2 = json::from_cbor(packed);
-
-    // compare parsed JSON values
-    EXPECT_EQ(j1, j2);
-}
-
-static const char* flynn_test_cases[] = {
-    "test/data/json_nlohmann_tests/all_unicode.json",
-    "test/data/json.org/1.json",
-    "test/data/json.org/2.json",
-    "test/data/json.org/3.json",
-    "test/data/json.org/4.json",
-    "test/data/json.org/5.json",
-    "test/data/json_roundtrip/roundtrip01.json",
-    "test/data/json_roundtrip/roundtrip02.json",
-    "test/data/json_roundtrip/roundtrip03.json",
-    "test/data/json_roundtrip/roundtrip04.json",
-    "test/data/json_roundtrip/roundtrip05.json",
-    "test/data/json_roundtrip/roundtrip06.json",
-    "test/data/json_roundtrip/roundtrip07.json",
-    "test/data/json_roundtrip/roundtrip08.json",
-    "test/data/json_roundtrip/roundtrip09.json",
-    "test/data/json_roundtrip/roundtrip10.json",
-    "test/data/json_roundtrip/roundtrip11.json",
-    "test/data/json_roundtrip/roundtrip12.json",
-    "test/data/json_roundtrip/roundtrip13.json",
-    "test/data/json_roundtrip/roundtrip14.json",
-    "test/data/json_roundtrip/roundtrip15.json",
-    "test/data/json_roundtrip/roundtrip16.json",
-    "test/data/json_roundtrip/roundtrip17.json",
-    "test/data/json_roundtrip/roundtrip18.json",
-    "test/data/json_roundtrip/roundtrip19.json",
-    "test/data/json_roundtrip/roundtrip20.json",
-    "test/data/json_roundtrip/roundtrip21.json",
-    "test/data/json_roundtrip/roundtrip22.json",
-    "test/data/json_roundtrip/roundtrip23.json",
-    "test/data/json_roundtrip/roundtrip24.json",
-    "test/data/json_roundtrip/roundtrip25.json",
-    "test/data/json_roundtrip/roundtrip26.json",
-    "test/data/json_roundtrip/roundtrip27.json",
-    "test/data/json_roundtrip/roundtrip28.json",
-    "test/data/json_roundtrip/roundtrip29.json",
-    "test/data/json_roundtrip/roundtrip30.json",
-    "test/data/json_roundtrip/roundtrip31.json",
-    "test/data/json_roundtrip/roundtrip32.json",
-    "test/data/json_testsuite/sample.json", // kills AppVeyor
-    "test/data/json_tests/pass1.json",
-    "test/data/json_tests/pass2.json",
-    "test/data/json_tests/pass3.json",
-    "test/data/regression/floats.json",
-    "test/data/regression/signed_ints.json",
-    "test/data/regression/unsigned_ints.json",
-    "test/data/regression/working_file.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_arraysWithSpaces.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_empty-string.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_empty.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_ending_with_newline.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_false.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_heterogeneous.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_null.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_1_and_newline.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_leading_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_several_null.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_trailing_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_0e+1.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_0e1.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_after_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_double_close_to_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_double_huge_neg_exp.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_int_with_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_minus_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_negative_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_negative_one.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_negative_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_capital_e.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_capital_e_neg_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_capital_e_pos_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_exponent.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_fraction_exponent.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_exp.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_exponent.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_underflow.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_simple_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_simple_real.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_too_big_neg_int.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_too_big_pos_int.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_very_big_negative_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_basic.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_duplicated_key.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_duplicated_key_and_value.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_empty.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_empty_key.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_escaped_null_in_key.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_extreme_numbers.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_long_strings.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_simple.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_string_unicode.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_with_newlines.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_UTF-16_Surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_accepted_surrogate_pair.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_accepted_surrogate_pairs.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_allowed_escapes.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_backslash_and_u_escaped_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_backslash_doublequotes.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_comments.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_double_escape_a.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_double_escape_n.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_escaped_control_character.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_escaped_noncharacter.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_in_array.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_in_array_with_leading_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_last_surrogates_1_and_2.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_newline_uescaped.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_nonCharacterInUTF-8_U+1FFFF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_null_escape.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_one-byte-utf-8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_pi.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_simple_ascii.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_three-byte-utf-8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_two-byte-utf-8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_u+2028_line_sep.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_u+2029_par_sep.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_uEscape.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unescaped_char_delete.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicodeEscapedBackslash.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_2.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_U+2064_invisible_plus.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_escaped_double_quote.json",
-    // "test/data/nst_json_testsuite/test_parsing/y_string_utf16.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_utf8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_with_del_character.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_false.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_negative_real.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_null.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_string.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_true.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_string_empty.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_trailing_newline.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_true_in_array.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_whitespace_array.json",
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRegressionFlynnTests, CborRegressionFlynnTest,
-                        ::testing::ValuesIn(flynn_test_cases));
-
-#endif
-TEST(CborFirstBytesTest, Unsupported)
-{
-    // these bytes will fail immediately with exception parse_error.112
-    std::set<uint8_t> unsupported =
-    {
-        //// types not supported by this library
-
-        // byte strings
-        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
-        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
-        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
-        // byte strings
-        0x58, 0x59, 0x5a, 0x5b, 0x5f,
-        // date/time
-        0xc0, 0xc1,
-        // bignum
-        0xc2, 0xc3,
-        // decimal fracion
-        0xc4,
-        // bigfloat
-        0xc5,
-        // tagged item
-        0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
-        0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd8,
-        0xd9, 0xda, 0xdb,
-        // expected conversion
-        0xd5, 0xd6, 0xd7,
-        // simple value
-        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
-        0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xef, 0xf0,
-        0xf1, 0xf2, 0xf3,
-        0xf8,
-        // undefined
-        0xf7,
-
-        //// bytes not specified by CBOR
-
-        0x1c, 0x1d, 0x1e, 0x1f,
-        0x3c, 0x3d, 0x3e, 0x3f,
-        0x5c, 0x5d, 0x5e,
-        0x7c, 0x7d, 0x7e,
-        0x9c, 0x9d, 0x9e,
-        0xbc, 0xbd, 0xbe,
-        0xdc, 0xdd, 0xde, 0xdf,
-        0xee,
-        0xfc, 0xfe, 0xfd,
-
-        /// break cannot be the first byte
-
-        0xff
-    };
-
-    for (auto i = 0; i < 256; ++i)
-    {
-        const auto byte = static_cast<uint8_t>(i);
-
-        try
-        {
-            json::from_cbor(std::vector<uint8_t>(1, byte));
-        }
-        catch (const json::parse_error& e)
-        {
-            // check that parse_error.112 is only thrown if the
-            // first byte is in the unsupported set
-            SCOPED_TRACE(e.what());
-            if (std::find(unsupported.begin(), unsupported.end(),
-                          static_cast<uint8_t>(byte)) != unsupported.end())
-            {
-                EXPECT_EQ(e.id, 112);
-            }
-            else
-            {
-                EXPECT_NE(e.id, 112);
-            }
-        }
-    }
-}
-
-// examples from RFC 7049 Appendix A
-namespace internal {
-struct CborRoundtripTestParam {
-  const char* plain;
-  std::vector<uint8_t> encoded;
-  bool test_encode;
-};
-}  // namespace internal
-
-class CborRoundtripTest
-    : public ::testing::TestWithParam<internal::CborRoundtripTestParam> {
-};
-TEST_P(CborRoundtripTest, Case)
-{
-    if (GetParam().test_encode)
-    {
-        EXPECT_EQ(json::to_cbor(json::parse(GetParam().plain)), GetParam().encoded);
-    }
-    EXPECT_EQ(json::parse(GetParam().plain), json::from_cbor(GetParam().encoded));
-}
-
-static const internal::CborRoundtripTestParam rfc7049_appendix_a_numbers[] = {
-    {"0", {0x00}, true},
-    {"1", {0x01}, true},
-    {"10", {0x0a}, true},
-    {"23", {0x17}, true},
-    {"24", {0x18,0x18}, true},
-    {"25", {0x18,0x19}, true},
-    {"100", {0x18,0x64}, true},
-    {"1000", {0x19,0x03,0xe8}, true},
-    {"1000000", {0x1a,0x00,0x0f,0x42,0x40}, true},
-    {"1000000000000", {0x1b,0x00,0x00,0x00,0xe8,0xd4,0xa5,0x10,0x00}, true},
-    {"18446744073709551615", {0x1b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, true},
-    // positive bignum is not supported
-    //{"18446744073709551616", {0xc2,0x49,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00", 11), true},
-    //{"-18446744073709551616", {0x3b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, true},
-    // negative bignum is not supported
-    //{"-18446744073709551617", {0xc3,0x49,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, true},
-    {"-1", {0x20}, true},
-    {"-10", {0x29}, true},
-    {"-100", {0x38,0x63}, true},
-    {"-1000", {0x39,0x03,0xe7}, true},
-    // half-precision float
-    {"0.0", {0xf9,0x00,0x00}, false},
-    // half-precision float
-    {"-0.0", {0xf9,0x80,0x00}, false},
-    // half-precision float
-    {"1.0", {0xf9,0x3c,0x00}, false},
-    {"1.1", {0xfb,0x3f,0xf1,0x99,0x99,0x99,0x99,0x99,0x9a}, true},
-    // half-precision float
-    {"1.5", {0xf9,0x3e,0x00}, false},
-    // half-precision float
-    {"65504.0", {0xf9,0x7b,0xff}, false},
-    {"100000.0", {0xfa,0x47,0xc3,0x50,0x00}, false},
-    {"3.4028234663852886e+38", {0xfa,0x7f,0x7f,0xff,0xff}, false},
-    {"1.0e+300", {0xfb,0x7e,0x37,0xe4,0x3c,0x88,0x00,0x75,0x9c}, true},
-    // half-precision float
-    {"5.960464477539063e-8", {0xf9,0x00,0x01}, false},
-    // half-precision float
-    {"0.00006103515625", {0xf9,0x04,0x00}, false},
-    // half-precision float
-    {"-4.0", {0xf9,0xc4,0x00}, false},
-    {"-4.1", {0xfb,0xc0,0x10,0x66,0x66,0x66,0x66,0x66,0x66}, true},
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRfc7049AppendixANumberTests, CborRoundtripTest,
-                        ::testing::ValuesIn(rfc7049_appendix_a_numbers));
-
-static const internal::CborRoundtripTestParam rfc7049_appendix_a_simple_values[] = {
-    {"false", {0xf4}, true},
-    {"true", {0xf5}, true},
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRfc7049AppendixASimpleValueTests, CborRoundtripTest,
-                        ::testing::ValuesIn(rfc7049_appendix_a_simple_values));
-
-static const internal::CborRoundtripTestParam rfc7049_appendix_a_strings[] = {
-    {"\"\"", {0x60}, true},
-    {"\"a\"", {0x61,0x61}, true},
-    {"\"IETF\"", {0x64,0x49,0x45,0x54,0x46}, true},
-    {"\"\\u00fc\"", {0x62,0xc3,0xbc}, true},
-    {"\"\\u6c34\"", {0x63,0xe6,0xb0,0xb4}, true},
-    {"\"\\ud800\\udd51\"", {0x64,0xf0,0x90,0x85,0x91}, true},
-    // indefinite length strings
-    {"\"streaming\"", {0x7f,0x65,0x73,0x74,0x72,0x65,0x61,0x64,0x6d,0x69,0x6e,0x67,0xff}, false},
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRfc7049AppendixAStringTests, CborRoundtripTest,
-                        ::testing::ValuesIn(rfc7049_appendix_a_strings));
-
-static const internal::CborRoundtripTestParam rfc7049_appendix_a_arrays[] = {
-    {"[]", {0x80}, true},
-    {"[1, 2, 3]", {0x83,0x01,0x02,0x03}, true},
-    {"[1, [2, 3], [4, 5]]", {0x83,0x01,0x82,0x02,0x03,0x82,0x04,0x05}, true},
-    {"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]", {0x98,0x19,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x18,0x18,0x19}, true},
-    // indefinite length arrays
-    {"[]", {0x9f,0xff}, false},
-    {"[1, [2, 3], [4, 5]] ", {0x9f,0x01,0x82,0x02,0x03,0x9f,0x04,0x05,0xff,0xff}, false},
-    {"[1, [2, 3], [4, 5]]", {0x9f,0x01,0x82,0x02,0x03,0x82,0x04,0x05,0xff}, false},
-    {"[1, [2, 3], [4, 5]]", {0x83,0x01,0x82,0x02,0x03,0x9f,0x04,0x05,0xff}, false},
-    {"[1, [2, 3], [4, 5]]", {0x83,0x01,0x9f,0x02,0x03,0xff,0x82,0x04,0x05}, false},
-    {"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]", {0x9f,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x18,0x18,0x19,0xff}, false},
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRfc7049AppendixAArrayTests, CborRoundtripTest,
-                        ::testing::ValuesIn(rfc7049_appendix_a_arrays));
-
-static const internal::CborRoundtripTestParam rfc7049_appendix_a_objects[] = {
-    {"{}", {0xa0}, true},
-    {"{\"a\": 1, \"b\": [2, 3]}", {0xa2,0x61,0x61,0x01,0x61,0x62,0x82,0x02,0x03}, true},
-    {"[\"a\", {\"b\": \"c\"}]", {0x82,0x61,0x61,0xa1,0x61,0x62,0x61,0x63}, true},
-    {"{\"a\": \"A\", \"b\": \"B\", \"c\": \"C\", \"d\": \"D\", \"e\": \"E\"}", {0xa5,0x61,0x61,0x61,0x41,0x61,0x62,0x61,0x42,0x61,0x63,0x61,0x43,0x61,0x64,0x61,0x44,0x61,0x65,0x61,0x45}, true},
-    // indefinite length objects
-    {"{\"a\": 1, \"b\": [2, 3]}", {0xbf,0x61,0x61,0x01,0x61,0x62,0x9f,0x02,0x03,0xff,0xff}, false},
-    {"[\"a\", {\"b\": \"c\"}]", {0x82,0x61,0x61,0xbf,0x61,0x62,0x61,0x63,0xff}, false},
-    {"{\"Fun\": true, \"Amt\": -2}", {0xbf,0x63,0x46,0x75,0x6e,0xf5,0x63,0x41,0x6d,0x74,0x21,0xff}, false},
-};
-
-INSTANTIATE_TEST_SUITE_P(CborRfc7049AppendixAObjectTests, CborRoundtripTest,
-                        ::testing::ValuesIn(rfc7049_appendix_a_objects));
diff --git a/wpiutil/src/test/native/cpp/json/unit-comparison.cpp b/wpiutil/src/test/native/cpp/json/unit-comparison.cpp
deleted file mode 100644
index 18934a2..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-comparison.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-class JsonComparisonTypesTest : public ::testing::Test {
- protected:
-    std::vector<json::value_t> j_types =
-    {
-        json::value_t::null,
-        json::value_t::boolean,
-        json::value_t::number_integer,
-        json::value_t::number_unsigned,
-        json::value_t::number_float,
-        json::value_t::object,
-        json::value_t::array,
-        json::value_t::string
-    };
-};
-
-TEST_F(JsonComparisonTypesTest, Less)
-{
-    static const std::vector<std::vector<bool>> expected =
-    {
-        {false, true, true, true, true, true, true, true},
-        {false, false, true, true, true, true, true, true},
-        {false, false, false, false, false, true, true, true},
-        {false, false, false, false, false, true, true, true},
-        {false, false, false, false, false, true, true, true},
-        {false, false, false, false, false, false, true, true},
-        {false, false, false, false, false, false, false, true},
-        {false, false, false, false, false, false, false, false}
-    };
-
-    for (size_t i = 0; i < j_types.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_types.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check precomputed values
-            EXPECT_EQ(operator<(j_types[i], j_types[j]), expected[i][j]);
-        }
-    }
-}
-
-class JsonComparisonValuesTest : public ::testing::Test {
- protected:
-    json j_values =
-    {
-        nullptr, nullptr,
-        17, 42,
-        8u, 13u,
-        3.14159, 23.42,
-        "foo", "bar",
-        true, false,
-        {1, 2, 3}, {"one", "two", "three"},
-        {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}
-    };
-};
-
-TEST_F(JsonComparisonValuesTest, Equal)
-{
-    static const std::vector<std::vector<bool>> expected =
-    {
-        {true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
-        {true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
-        {false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false},
-        {false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false},
-        {false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false},
-        {false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false},
-        {false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false},
-        {false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false},
-        {false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
-        {false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false},
-        {false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false},
-        {false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false},
-        {false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false},
-        {false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false},
-        {false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false},
-        {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}
-    };
-
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_values.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check precomputed values
-            EXPECT_EQ(j_values[i] == j_values[j], expected[i][j]);
-        }
-    }
-
-    // comparison with discarded elements
-    json j_discarded(json::value_t::discarded);
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        EXPECT_FALSE(j_values[i] == j_discarded);
-        EXPECT_FALSE(j_discarded == j_values[i]);
-        EXPECT_FALSE(j_discarded == j_discarded);
-    }
-
-    // compare with null pointer
-    json j_null;
-    EXPECT_TRUE(j_null == nullptr);
-    EXPECT_TRUE(nullptr == j_null);
-}
-
-TEST_F(JsonComparisonValuesTest, NotEqual)
-{
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_values.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check definition
-            EXPECT_EQ(j_values[i] != j_values[j], !(j_values[i] == j_values[j]));
-        }
-    }
-
-    // compare with null pointer
-    json j_null;
-    EXPECT_FALSE(j_null != nullptr);
-    EXPECT_FALSE(nullptr != j_null);
-    EXPECT_EQ(j_null != nullptr, !(j_null == nullptr));
-    EXPECT_EQ(nullptr != j_null, !(nullptr == j_null));
-}
-
-TEST_F(JsonComparisonValuesTest, Less)
-{
-    static const std::vector<std::vector<bool>> expected =
-    {
-        {false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
-        {false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
-        {false, false, false, true, false, false, false, true, true, true, false, false, true, true, true, true},
-        {false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, true},
-        {false, false, true, true, false, true, false, true, true, true, false, false, true, true, true, true},
-        {false, false, true, true, false, false, false, true, true, true, false, false, true, true, true, true},
-        {false, false, true, true, true, true, false, true, true, true, false, false, true, true, true, true},
-        {false, false, false, true, false, false, false, false, true, true, false, false, true, true, true, true},
-        {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
-        {false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
-        {false, false, true, true, true, true, true, true, true, true, false, false, true, true, true, true},
-        {false, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true},
-        {false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, false},
-        {false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false},
-        {false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false},
-        {false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, false}
-    };
-
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_values.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check precomputed values
-            EXPECT_EQ(j_values[i] < j_values[j], expected[i][j]);
-        }
-    }
-
-    // comparison with discarded elements
-    json j_discarded(json::value_t::discarded);
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        EXPECT_FALSE(j_values[i] < j_discarded);
-        EXPECT_FALSE(j_discarded < j_values[i]);
-        EXPECT_FALSE(j_discarded < j_discarded);
-    }
-}
-
-TEST_F(JsonComparisonValuesTest, LessEqual)
-{
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_values.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check definition
-            EXPECT_EQ(j_values[i] <= j_values[j], !(j_values[j] < j_values[i]));
-        }
-    }
-}
-
-TEST_F(JsonComparisonValuesTest, Greater)
-{
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_values.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check definition
-            EXPECT_EQ(j_values[i] > j_values[j], j_values[j] < j_values[i]);
-        }
-    }
-}
-
-TEST_F(JsonComparisonValuesTest, GreaterEqual)
-{
-    for (size_t i = 0; i < j_values.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        for (size_t j = 0; j < j_values.size(); ++j)
-        {
-            SCOPED_TRACE(j);
-            // check definition
-            EXPECT_EQ(j_values[i] >= j_values[j], !(j_values[i] < j_values[j]));
-        }
-    }
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-concepts.cpp b/wpiutil/src/test/native/cpp/json/unit-concepts.cpp
deleted file mode 100644
index 4ce5a5b..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-concepts.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonConceptsTest, ContainerRequirements)
-{
-    // X: container class: json
-    // T: type of objects: json
-    // a, b: values of type X: json
-
-    // TABLE 96 - Container Requirements
-
-    // X::value_type must return T
-    EXPECT_TRUE((std::is_same<json::value_type, json>::value));
-
-    // X::reference must return lvalue of T
-    EXPECT_TRUE((std::is_same<json::reference, json&>::value));
-
-    // X::const_reference must return const lvalue of T
-    EXPECT_TRUE((std::is_same<json::const_reference, const json&>::value));
-
-    // X::iterator must return iterator whose value_type is T
-    EXPECT_TRUE((std::is_same<json::iterator::value_type, json>::value));
-    // X::iterator must meet the forward iterator requirements
-    EXPECT_TRUE((std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<json::iterator>::iterator_category>::value));
-    // X::iterator must be convertible to X::const_iterator
-    EXPECT_TRUE((std::is_convertible<json::iterator, json::const_iterator>::value));
-
-    // X::const_iterator must return iterator whose value_type is T
-    EXPECT_TRUE((std::is_same<json::const_iterator::value_type, json>::value));
-    // X::const_iterator must meet the forward iterator requirements
-    EXPECT_TRUE((std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<json::const_iterator>::iterator_category>::value));
-
-    // X::difference_type must return a signed integer
-    EXPECT_TRUE((std::is_signed<json::difference_type>::value));
-    // X::difference_type must be identical to X::iterator::difference_type
-    EXPECT_TRUE((std::is_same<json::difference_type, json::iterator::difference_type>::value));
-    // X::difference_type must be identical to X::const_iterator::difference_type
-    EXPECT_TRUE((std::is_same<json::difference_type, json::const_iterator::difference_type>::value));
-
-    // X::size_type must return an unsigned integer
-    EXPECT_TRUE((std::is_unsigned<json::size_type>::value));
-    // X::size_type can represent any non-negative value of X::difference_type
-    EXPECT_TRUE(static_cast<json::size_type>(std::numeric_limits<json::difference_type>::max()) <=
-          std::numeric_limits<json::size_type>::max());
-
-    // the expression "X u" has the post-condition "u.empty()"
-    {
-        json u;
-        EXPECT_TRUE(u.empty());
-    }
-
-    // the expression "X()" has the post-condition "X().empty()"
-    EXPECT_TRUE(json().empty());
-}
-
-TEST(JsonConceptsTest, DefaultConstructible)
-{
-    EXPECT_TRUE(std::is_nothrow_default_constructible<json>::value);
-}
-
-TEST(JsonConceptsTest, MoveConstructible)
-{
-    EXPECT_TRUE(std::is_nothrow_move_constructible<json>::value);
-}
-
-TEST(JsonConceptsTest, CopyConstructible)
-{
-    EXPECT_TRUE(std::is_copy_constructible<json>::value);
-}
-
-TEST(JsonConceptsTest, MoveAssignable)
-{
-    EXPECT_TRUE(std::is_nothrow_move_assignable<json>::value);
-}
-
-TEST(JsonConceptsTest, CopyAssignable)
-{
-    EXPECT_TRUE(std::is_copy_assignable<json>::value);
-}
-
-TEST(JsonConceptsTest, Destructible)
-{
-    EXPECT_TRUE(std::is_nothrow_destructible<json>::value);
-}
-
-TEST(JsonConceptsTest, StandardLayoutType)
-{
-    EXPECT_TRUE(std::is_standard_layout<json>::value);
-}
-
-TEST(JsonIteratorConceptsTest, CopyConstructible)
-{
-    EXPECT_TRUE(std::is_nothrow_copy_constructible<json::iterator>::value);
-    EXPECT_TRUE(std::is_nothrow_copy_constructible<json::const_iterator>::value);
-}
-
-TEST(JsonIteratorConceptsTest, CopyAssignable)
-{
-    // STL iterators used by json::iterator don't pass this test in Debug mode
-#if !defined(_MSC_VER) || (_ITERATOR_DEBUG_LEVEL == 0)
-    EXPECT_TRUE(std::is_nothrow_copy_assignable<json::iterator>::value);
-    EXPECT_TRUE(std::is_nothrow_copy_assignable<json::const_iterator>::value);
-#endif
-}
-
-TEST(JsonIteratorConceptsTest, Destructible)
-{
-    EXPECT_TRUE(std::is_nothrow_destructible<json::iterator>::value);
-    EXPECT_TRUE(std::is_nothrow_destructible<json::const_iterator>::value);
-}
-
-TEST(JsonIteratorConceptsTest, Swappable)
-{
-    json j {1, 2, 3};
-    json::iterator it1 = j.begin();
-    json::iterator it2 = j.end();
-    std::swap(it1, it2);
-    EXPECT_EQ(it1, j.end());
-    EXPECT_EQ(it2, j.begin());
-}
-
-TEST(JsonIteratorConceptsTest, SwappableConst)
-{
-    json j {1, 2, 3};
-    json::const_iterator it1 = j.cbegin();
-    json::const_iterator it2 = j.cend();
-    std::swap(it1, it2);
-    EXPECT_EQ(it1, j.end());
-    EXPECT_EQ(it2, j.begin());
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-constructor1.cpp b/wpiutil/src/test/native/cpp/json/unit-constructor1.cpp
deleted file mode 100644
index 273bfb6..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-constructor1.cpp
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include <array>
-#include <cmath>
-#include <deque>
-#include <forward_list>
-#include <list>
-#include <map>
-#include <set>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "unit-json.h"
-using wpi::json;
-using wpi::JsonTest;
-
-class JsonConstructTypeTest : public ::testing::TestWithParam<json::value_t> {};
-TEST_P(JsonConstructTypeTest, Case)
-{
-    auto t = GetParam();
-    json j(t);
-    EXPECT_EQ(j.type(), t);
-}
-
-static const json::value_t construct_type_cases[] = {
-    json::value_t::null,
-    json::value_t::discarded,
-    json::value_t::object,
-    json::value_t::array,
-    json::value_t::boolean,
-    json::value_t::string,
-    json::value_t::number_integer,
-    json::value_t::number_unsigned,
-    json::value_t::number_float,
-};
-
-INSTANTIATE_TEST_SUITE_P(JsonConstructTypeTests, JsonConstructTypeTest,
-                        ::testing::ValuesIn(construct_type_cases));
-
-
-TEST(JsonConstructNullTest, NoParameter)
-{
-    json j{};
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonConstructNullTest, Parameter)
-{
-    json j(nullptr);
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonConstructObjectExplicitTest, Empty)
-{
-    json::object_t o;
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-TEST(JsonConstructObjectExplicitTest, Filled)
-{
-    json::object_t o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-class JsonConstructObjectImplicitTest : public ::testing::Test {
- public:
-    JsonConstructObjectImplicitTest() : j_reference(o_reference) {}
-
- protected:
-    json::object_t o_reference {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j_reference;
-};
-
-// std::map<std::string, json>
-TEST_F(JsonConstructObjectImplicitTest, StdMapStringJson)
-{
-    std::map<std::string, json> o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j, j_reference);
-}
-
-// std::pair<CompatibleString, T>
-TEST_F(JsonConstructObjectImplicitTest, StdPairStringT)
-{
-    std::pair<std::string, std::string> p{"first", "second"};
-    json j(p);
-
-    EXPECT_EQ(j.get<decltype(p)>(), p);
-
-    std::pair<std::string, int> p2{"first", 1};
-    // use char const*
-    json j2(std::make_pair("first", 1));
-
-    EXPECT_EQ(j2.get<decltype(p2)>(), p2);
-}
-
-// std::map<std::string, std::string>
-TEST_F(JsonConstructObjectImplicitTest, StdMapStringString)
-{
-    std::map<std::string, std::string> m;
-    m["a"] = "b";
-    m["c"] = "d";
-    m["e"] = "f";
-
-    json j(m);
-    EXPECT_EQ(j.get<decltype(m)>(), m);
-}
-
-// std::map<const char*, json>
-TEST_F(JsonConstructObjectImplicitTest, StdMapCharPointerJson)
-{
-    std::map<const char*, json> o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j, j_reference);
-}
-
-// std::multimap<std::string, json>
-TEST_F(JsonConstructObjectImplicitTest, StdMultiMapStringJson)
-{
-    std::multimap<std::string, json> o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j, j_reference);
-}
-
-// std::unordered_map<std::string, json>
-TEST_F(JsonConstructObjectImplicitTest, StdUnorderedMapStringJson)
-{
-    std::unordered_map<std::string, json> o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j, j_reference);
-}
-
-// std::unordered_multimap<std::string, json>
-TEST_F(JsonConstructObjectImplicitTest, StdUnorderedMultiMapStringJson)
-{
-    std::unordered_multimap<std::string, json> o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
-    json j(o);
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j, j_reference);
-}
-
-// associative container literal
-TEST_F(JsonConstructObjectImplicitTest, AssociativeContainerLiteral)
-{
-    json j({{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}});
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j, j_reference);
-}
-
-TEST(JsonConstructArrayExplicitTest, Empty)
-{
-    json::array_t a;
-    json j(a);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructArrayExplicitTest, Filled)
-{
-    json::array_t a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j(a);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-template <typename T>
-class JsonConstructArrayTest : public ::testing::Test {
- public:
-    JsonConstructArrayTest() : j_reference(a_reference) {}
-
- protected:
-    json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j_reference;
-};
-
-typedef ::testing::Types<std::list<json>, std::forward_list<json>,
-                         std::array<json, 6>, std::vector<json>,
-                         std::deque<json>>
-    JsonConstructArrayTestTypes;
-TYPED_TEST_SUITE(JsonConstructArrayTest, JsonConstructArrayTestTypes, );
-
-// clang warns on missing braces on the TypeParam initializer line below.
-// Suppress this warning.
-#if defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmissing-braces"
-#endif
-TYPED_TEST(JsonConstructArrayTest, Implicit)
-{
-    TypeParam a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j(a);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, this->j_reference);
-}
-#if defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-// std::set<json>
-TEST(JsonConstructArraySetTest, StdSet)
-{
-    std::set<json> a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j(a);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    // we cannot really check for equality here
-}
-
-// std::unordered_set<json>
-TEST(JsonConstructArraySetTest, StdUnorderedSet)
-{
-    std::unordered_set<json> a {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j(a);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    // we cannot really check for equality here
-}
-
-// sequence container literal
-TEST(JsonConstructArrayContainerTest, Case)
-{
-    json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j_reference(a_reference);
-
-    json j({json(1), json(1u), json(2.2), json(false), json("string"), json()});
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, j_reference);
-}
-
-TEST(JsonConstructStringExplicitTest, Empty)
-{
-    std::string s;
-    json j(s);
-    EXPECT_EQ(j.type(), json::value_t::string);
-}
-
-TEST(JsonConstructStringExplicitTest, Filled)
-{
-    std::string s {"Hello world"};
-    json j(s);
-    EXPECT_EQ(j.type(), json::value_t::string);
-}
-
-class JsonConstructStringTest : public ::testing::Test {
- public:
-    JsonConstructStringTest() : j_reference(s_reference) {}
-
- protected:
-    std::string s_reference {"Hello world"};
-    json j_reference;
-};
-
-// std::string
-TEST_F(JsonConstructStringTest, StdString)
-{
-    std::string s {"Hello world"};
-    json j(s);
-    EXPECT_EQ(j.type(), json::value_t::string);
-    EXPECT_EQ(j, j_reference);
-}
-
-// char[]
-TEST_F(JsonConstructStringTest, CharArray)
-{
-    char s[] {"Hello world"};
-    json j(s);
-    EXPECT_EQ(j.type(), json::value_t::string);
-    EXPECT_EQ(j, j_reference);
-}
-
-// const char*
-TEST_F(JsonConstructStringTest, ConstCharPointer)
-{
-    const char* s {"Hello world"};
-    json j(s);
-    EXPECT_EQ(j.type(), json::value_t::string);
-    EXPECT_EQ(j, j_reference);
-}
-
-// string literal
-TEST_F(JsonConstructStringTest, StringLiteral)
-{
-    json j("Hello world");
-    EXPECT_EQ(j.type(), json::value_t::string);
-    EXPECT_EQ(j, j_reference);
-}
-
-TEST(JsonConstructBooleanExplicitTest, Empty)
-{
-    bool b{};
-    json j(b);
-    EXPECT_EQ(j.type(), json::value_t::boolean);
-}
-
-TEST(JsonConstructBooleanExplicitTest, True)
-{
-    json j(true);
-    EXPECT_EQ(j.type(), json::value_t::boolean);
-}
-
-TEST(JsonConstructBooleanExplicitTest, False)
-{
-    json j(false);
-    EXPECT_EQ(j.type(), json::value_t::boolean);
-}
-
-TEST(JsonConstructIntegerExplicitTest, Uninitialized)
-{
-    int64_t n{};
-    json j(n);
-    EXPECT_EQ(j.type(), json::value_t::number_integer);
-}
-
-TEST(JsonConstructIntegerExplicitTest, Initialized)
-{
-    int64_t n(42);
-    json j(n);
-    EXPECT_EQ(j.type(), json::value_t::number_integer);
-}
-
-template <typename T>
-class JsonConstructIntegerTest : public ::testing::Test {
- public:
-    JsonConstructIntegerTest()
-        : j_reference(n_reference), j_unsigned_reference(n_unsigned_reference) {}
-
- protected:
-    int64_t n_reference = 42;
-    json j_reference;
-    uint64_t n_unsigned_reference = 42u;
-    json j_unsigned_reference;
-};
-
-typedef ::testing::Types<
-      short
-    , unsigned short
-    , int
-    , unsigned int
-    , long
-    , unsigned long
-    , long long
-    , unsigned long long
-    , int8_t
-    , int16_t
-    , int32_t
-    , int64_t
-#if 0
-    , int8_fast_t
-    , int16_fast_t
-    , int32_fast_t
-    , int64_fast_t
-    , int8_least_t
-    , int16_least_t
-    , int32_least_t
-    , int64_least_t
-#endif
-    , uint8_t
-    , uint16_t
-    , uint32_t
-    , uint64_t
-#if 0
-    , uint8_fast_t
-    , uint16_fast_t
-    , uint32_fast_t
-    , uint64_fast_t
-    , uint8_least_t
-    , uint16_least_t
-    , uint32_least_t
-    , uint64_least_t
-#endif
-    > JsonConstructIntegerTestTypes;
-
-TYPED_TEST_SUITE(JsonConstructIntegerTest, JsonConstructIntegerTestTypes, );
-
-TYPED_TEST(JsonConstructIntegerTest, Implicit)
-{
-    TypeParam n = 42;
-    json j(n);
-    if (std::is_unsigned<TypeParam>::value)
-    {
-        EXPECT_EQ(j.type(), json::value_t::number_unsigned);
-        EXPECT_EQ(j, this->j_unsigned_reference);
-    }
-    else
-    {
-        EXPECT_EQ(j.type(), json::value_t::number_integer);
-        EXPECT_EQ(j, this->j_reference);
-    }
-}
-
-class JsonConstructIntegerLiteralTest : public ::testing::Test {
- public:
-    JsonConstructIntegerLiteralTest()
-        : j_reference(n_reference), j_unsigned_reference(n_unsigned_reference) {}
-
- protected:
-    int64_t n_reference = 42;
-    json j_reference;
-    uint64_t n_unsigned_reference = 42u;
-    json j_unsigned_reference;
-};
-
-TEST_F(JsonConstructIntegerLiteralTest, None)
-{
-    json j(42);
-    EXPECT_EQ(j.type(), json::value_t::number_integer);
-    EXPECT_EQ(j, j_reference);
-}
-
-TEST_F(JsonConstructIntegerLiteralTest, U)
-{
-    json j(42u);
-    EXPECT_EQ(j.type(), json::value_t::number_unsigned);
-    EXPECT_EQ(j, j_unsigned_reference);
-}
-
-TEST_F(JsonConstructIntegerLiteralTest, L)
-{
-    json j(42l);
-    EXPECT_EQ(j.type(), json::value_t::number_integer);
-    EXPECT_EQ(j, j_reference);
-}
-
-TEST_F(JsonConstructIntegerLiteralTest, UL)
-{
-    json j(42ul);
-    EXPECT_EQ(j.type(), json::value_t::number_unsigned);
-    EXPECT_EQ(j, j_unsigned_reference);
-}
-
-TEST_F(JsonConstructIntegerLiteralTest, LL)
-{
-    json j(42ll);
-    EXPECT_EQ(j.type(), json::value_t::number_integer);
-    EXPECT_EQ(j, j_reference);
-}
-
-TEST_F(JsonConstructIntegerLiteralTest, ULL)
-{
-    json j(42ull);
-    EXPECT_EQ(j.type(), json::value_t::number_unsigned);
-    EXPECT_EQ(j, j_unsigned_reference);
-}
-
-TEST(JsonConstructFloatExplicitTest, Uninitialized)
-{
-    double n{};
-    json j(n);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-}
-
-TEST(JsonConstructFloatExplicitTest, Initialized)
-{
-    double n(42.23);
-    json j(n);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-}
-
-TEST(JsonConstructFloatExplicitTest, Infinity)
-{
-    // infinity is stored properly, but serialized to null
-    double n(std::numeric_limits<double>::infinity());
-    json j(n);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-
-    // check round trip of infinity
-    double d = j;
-    EXPECT_EQ(d, n);
-
-    // check that inf is serialized to null
-    EXPECT_EQ(j.dump(), "null");
-}
-
-template <typename T>
-class JsonConstructFloatTest : public ::testing::Test {
- public:
-    JsonConstructFloatTest() : j_reference(n_reference) {}
-
- protected:
-    double n_reference {42.23};
-    json j_reference;
-};
-
-typedef ::testing::Types<float, double
-#if 0
-                         , long double
-#endif
-                         >
-    JsonConstructFloatTestTypes;
-
-TYPED_TEST_SUITE(JsonConstructFloatTest, JsonConstructFloatTestTypes, );
-
-TYPED_TEST(JsonConstructFloatTest, Implicit)
-{
-    TypeParam n = 42.23f;
-    json j(n);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-    EXPECT_LT(std::fabs(JsonTest::GetValue(j).number_float -
-                        JsonTest::GetValue(this->j_reference).number_float),
-              0.001);
-}
-
-class JsonConstructFloatLiteralTest : public ::testing::Test {
- public:
-    JsonConstructFloatLiteralTest() : j_reference(n_reference) {}
-
- protected:
-    double n_reference {42.23};
-    json j_reference;
-};
-
-TEST_F(JsonConstructFloatLiteralTest, None)
-{
-    json j(42.23);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-    EXPECT_LT(std::fabs(JsonTest::GetValue(j).number_float -
-                        JsonTest::GetValue(this->j_reference).number_float),
-              0.001);
-}
-
-TEST_F(JsonConstructFloatLiteralTest, F)
-{
-    json j(42.23f);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-    EXPECT_LT(std::fabs(JsonTest::GetValue(j).number_float -
-                        JsonTest::GetValue(this->j_reference).number_float),
-              0.001);
-}
-
-#if 0
-TEST_F(JsonConstructFloatLiteralTest, L)
-{
-    json j(42.23l);
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-    EXPECT_LT(std::fabs(JsonTest::GetValue(j).number_float -
-                        JsonTest::GetValue(this->j_reference).number_float),
-              0.001);
-}
-#endif
-
-TEST(JsonConstructInitializerEmptyTest, Explicit)
-{
-    json j(json::initializer_list_t{});
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-TEST(JsonConstructInitializerEmptyTest, Implicit)
-{
-    json j {};
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitArray)
-{
-    std::initializer_list<json> l = {json(json::array_t())};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitArray)
-{
-    json j {json::array_t()};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitObject)
-{
-    std::initializer_list<json> l = {json(json::object_t())};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitObject)
-{
-    json j {json::object_t()};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitString)
-{
-    std::initializer_list<json> l = {json("Hello world")};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitString)
-{
-    json j {"Hello world"};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitBoolean)
-{
-    std::initializer_list<json> l = {json(true)};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitBoolean)
-{
-    json j {true};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitInteger)
-{
-    std::initializer_list<json> l = {json(1)};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitInteger)
-{
-    json j {1};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitUnsigned)
-{
-    std::initializer_list<json> l = {json(1u)};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitUnsigned)
-{
-    json j {1u};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ExplicitFloat)
-{
-    std::initializer_list<json> l = {json(42.23)};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerOneTest, ImplicitFloat)
-{
-    json j {42.23};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerManyTest, Explicit)
-{
-    std::initializer_list<json> l = {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()};
-    json j(l);
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerManyTest, Implicit)
-{
-    json j {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerImplicitTest, Object)
-{
-    json j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} };
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-TEST(JsonConstructInitializerImplicitTest, Array)
-{
-    json j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 };
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerExplicitTest, EmptyObject)
-{
-    json j = json::object();
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-TEST(JsonConstructInitializerExplicitTest, Object)
-{
-    json j = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} });
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-TEST(JsonConstructInitializerExplicitTest, ObjectError)
-{
-    EXPECT_THROW_MSG(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }),
-    json::type_error,
-    "[json.exception.type_error.301] cannot create object from initializer list");
-}
-
-// std::pair<CompatibleString, T> with error
-TEST(JsonConstructInitializerPairErrorTest, WrongFieldNumber)
-{
-    json j{{"too", "much"}, {"string", "fields"}};
-    EXPECT_THROW_MSG((j.get<std::pair<std::string, std::string>>()), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with object");
-}
-
-TEST(JsonConstructInitializerPairErrorTest, WrongJsonType)
-{
-    json j(42);
-    EXPECT_THROW_MSG((j.get<std::pair<std::string, std::string>>()), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST(JsonConstructInitializerTest, EmptyArray)
-{
-    json j = json::array();
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConstructInitializerTest, Array)
-{
-    json j = json::array({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} });
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-// create an array of n copies of a given value
-TEST(JsonConstructArrayCopyTest, Case)
-{
-    json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}};
-    json arr(3, v);
-    EXPECT_EQ(arr.size(), 3u);
-    for (auto& x : arr)
-    {
-        EXPECT_EQ(x, v);
-    }
-}
-
-// create a JSON container from an iterator range
-TEST(JsonConstructIteratorTest, ObjectBeginEnd)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json j_new(jobject.begin(), jobject.end());
-    EXPECT_EQ(j_new, jobject);
-#else
-    EXPECT_THROW(json(jobject.begin(), jobject.end()), json::invalid_iterator);
-#endif
-}
-
-TEST(JsonConstructIteratorTest, ObjectBeginEndConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json j_new(jobject.cbegin(), jobject.cend());
-    EXPECT_EQ(j_new, jobject);
-#else
-    EXPECT_THROW(json(jobject.cbegin(), jobject.cend()), json::invalid_iterator);
-#endif
-}
-
-TEST(JsonConstructIteratorTest, ObjectBeginBegin)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json j_new(jobject.begin(), jobject.begin());
-    EXPECT_EQ(j_new, json::object());
-#else
-    EXPECT_THROW(json(jobject.begin(), jobject.end()), json::invalid_iterator);
-#endif
-}
-
-TEST(JsonConstructIteratorTest, ObjectBeginBeginConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json j_new(jobject.cbegin(), jobject.cbegin());
-    EXPECT_EQ(j_new, json::object());
-#else
-    EXPECT_THROW(json(jobject.cbegin(), jobject.cend()), json::invalid_iterator);
-#endif
-}
-#if 0
-TEST(JsonConstructIteratorTest, ObjectSubrange)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-    json j_new(jobject.find("b"), jobject.find("e"));
-    EXPECT_EQ(j_new, json({{"b", 1}, {"c", 17u}, {"d", false}}));
-}
-#endif
-TEST(JsonConstructIteratorTest, ObjectIncompatibleIterators)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    EXPECT_THROW_MSG(json(jobject.begin(), jobject2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-    EXPECT_THROW_MSG(json(jobject2.begin(), jobject.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-}
-
-TEST(JsonConstructIteratorTest, ObjectIncompatibleIteratorsConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    EXPECT_THROW_MSG(json(jobject.cbegin(), jobject2.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-    EXPECT_THROW_MSG(json(jobject2.cbegin(), jobject.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-}
-
-TEST(JsonConstructIteratorTest, ArrayBeginEnd)
-{
-    json jarray = {1, 2, 3, 4, 5};
-    json j_new(jarray.begin(), jarray.end());
-    EXPECT_EQ(j_new, jarray);
-}
-
-TEST(JsonConstructIteratorTest, ArrayBeginEndConst)
-{
-    json jarray = {1, 2, 3, 4, 5};
-    json j_new(jarray.cbegin(), jarray.cend());
-    EXPECT_EQ(j_new, jarray);
-}
-
-TEST(JsonConstructIteratorTest, ArrayBeginBegin)
-{
-    json jarray = {1, 2, 3, 4, 5};
-    json j_new(jarray.begin(), jarray.begin());
-    EXPECT_EQ(j_new, json::array());
-}
-
-TEST(JsonConstructIteratorTest, ArrayBeginBeginConst)
-{
-    json jarray = {1, 2, 3, 4, 5};
-    json j_new(jarray.cbegin(), jarray.cbegin());
-    EXPECT_EQ(j_new, json::array());
-}
-
-TEST(JsonConstructIteratorTest, ArraySubrange)
-{
-    json jarray = {1, 2, 3, 4, 5};
-    json j_new(jarray.begin() + 1, jarray.begin() + 3);
-    EXPECT_EQ(j_new, json({2, 3}));
-}
-
-TEST(JsonConstructIteratorTest, ArraySubrangeConst)
-{
-    json jarray = {1, 2, 3, 4, 5};
-    json j_new(jarray.cbegin() + 1, jarray.cbegin() + 3);
-    EXPECT_EQ(j_new, json({2, 3}));
-}
-
-TEST(JsonConstructIteratorTest, ArrayIncompatibleIterators)
-{
-    json jarray = {1, 2, 3, 4};
-    json jarray2 = {2, 3, 4, 5};
-    EXPECT_THROW_MSG(json(jarray.begin(), jarray2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-    EXPECT_THROW_MSG(json(jarray2.begin(), jarray.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-}
-
-TEST(JsonConstructIteratorTest, ArrayIncompatibleIteratorsConst)
-{
-    json jarray = {1, 2, 3, 4};
-    json jarray2 = {2, 3, 4, 5};
-    EXPECT_THROW_MSG(json(jarray.cbegin(), jarray2.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-    EXPECT_THROW_MSG(json(jarray2.cbegin(), jarray.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.201] iterators are not compatible");
-}
-
-TEST(JsonConstructTwoValidIteratorTest, Null)
-{
-    json j;
-    EXPECT_THROW_MSG(json(j.begin(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.206] cannot construct with iterators from null");
-}
-
-TEST(JsonConstructTwoValidIteratorTest, NullConst)
-{
-    json j;
-    EXPECT_THROW_MSG(json(j.cbegin(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.206] cannot construct with iterators from null");
-}
-
-TEST(JsonConstructTwoValidIteratorTest, String)
-{
-    json j = "foo";
-    json j_new(j.begin(), j.end());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, StringConst)
-{
-    json j = "bar";
-    json j_new(j.cbegin(), j.cend());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, Boolean)
-{
-    json j = false;
-    json j_new(j.begin(), j.end());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, BooleanConst)
-{
-    json j = true;
-    json j_new(j.cbegin(), j.cend());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, Integer)
-{
-    json j = 17;
-    json j_new(j.begin(), j.end());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, IntegerConst)
-{
-    json j = 17;
-    json j_new(j.cbegin(), j.cend());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, Unsigned)
-{
-    json j = 17u;
-    json j_new(j.begin(), j.end());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, UnsignedConst)
-{
-    json j = 17u;
-    json j_new(j.cbegin(), j.cend());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, Float)
-{
-    json j = 23.42;
-    json j_new(j.begin(), j.end());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoValidIteratorTest, FloatConst)
-{
-    json j = 23.42;
-    json j_new(j.cbegin(), j.cend());
-    EXPECT_EQ(j, j_new);
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, String)
-{
-    json j = "foo";
-    EXPECT_THROW_MSG(json(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, StringConst)
-{
-    json j = "bar";
-    EXPECT_THROW_MSG(json(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, Boolean)
-{
-    json j = false;
-    EXPECT_THROW_MSG(json(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, BooleanConst)
-{
-    json j = true;
-    EXPECT_THROW_MSG(json(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, Integer)
-{
-    json j = 17;
-    EXPECT_THROW_MSG(json(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, IntegerConst)
-{
-    json j = 17;
-    EXPECT_THROW_MSG(json(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, Unsigned)
-{
-    json j = 17u;
-    EXPECT_THROW_MSG(json(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, UnsignedConst)
-{
-    json j = 17u;
-    EXPECT_THROW_MSG(json(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, Float)
-{
-    json j = 23.42;
-    EXPECT_THROW_MSG(json(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonConstructTwoInvalidIteratorTest, FloatConst)
-{
-    json j = 23.42;
-    EXPECT_THROW_MSG(json(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(json(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-constructor2.cpp b/wpiutil/src/test/native/cpp/json/unit-constructor2.cpp
deleted file mode 100644
index 39f1301..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-constructor2.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonCopyConstructorTest, Object)
-{
-    json j {{"foo", 1}, {"bar", false}};
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, Array)
-{
-    json j {"foo", 1, 42.23, false};
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, Null)
-{
-    json j(nullptr);
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, Boolean)
-{
-    json j(true);
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, String)
-{
-    json j("Hello world");
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, Integer)
-{
-    json j(42);
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, Unsigned)
-{
-    json j(42u);
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyConstructorTest, Float)
-{
-    json j(42.23);
-    json k(j);
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonMoveConstructorTest, Case)
-{
-    json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}};
-    EXPECT_EQ(j.type(), json::value_t::object);
-    json k(std::move(j));
-    EXPECT_EQ(k.type(), json::value_t::object);
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonCopyAssignmentTest, Object)
-{
-    json j {{"foo", 1}, {"bar", false}};
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, Array)
-{
-    json j {"foo", 1, 42.23, false};
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, Null)
-{
-    json j(nullptr);
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, Boolean)
-{
-    json j(true);
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, String)
-{
-    json j("Hello world");
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, Integer)
-{
-    json j(42);
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, Unsigned)
-{
-    json j(42u);
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonCopyAssignmentTest, Float)
-{
-    json j(42.23);
-    json k;
-    k = j;
-    EXPECT_EQ(j, k);
-}
-
-TEST(JsonDestructorTest, Object)
-{
-    auto j = new json {{"foo", 1}, {"bar", false}};
-    delete j;
-}
-
-TEST(JsonDestructorTest, Array)
-{
-    auto j = new json {"foo", 1, 1u, false, 23.42};
-    delete j;
-}
-
-TEST(JsonDestructorTest, String)
-{
-    auto j = new json("Hello world");
-    delete j;
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-conversions.cpp b/wpiutil/src/test/native/cpp/json/unit-conversions.cpp
deleted file mode 100644
index 601055c..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-conversions.cpp
+++ /dev/null
@@ -1,561 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-using wpi::JsonTest;
-
-#include <cmath>
-#include <deque>
-//#include <forward_list>
-#include <list>
-#include <map>
-#include <unordered_map>
-#include <unordered_set>
-
-template <typename T>
-class JsonGetObjectTest : public ::testing::Test {
- public:
-    JsonGetObjectTest() : j(o_reference) {}
-
- protected:
-    json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
-    json j;
-};
-
-typedef ::testing::Types<
-      json::object_t
-    , std::map<std::string, json>
-    , std::multimap<std::string, json>
-    , std::unordered_map<std::string, json>
-    , std::unordered_multimap<std::string, json>
-    > JsonGetObjectTestTypes;
-TYPED_TEST_SUITE(JsonGetObjectTest, JsonGetObjectTestTypes, );
-
-TYPED_TEST(JsonGetObjectTest, Explicit)
-{
-    TypeParam o = (this->j).template get<TypeParam>();
-    EXPECT_EQ(json(o), this->j);
-}
-
-TYPED_TEST(JsonGetObjectTest, Implicit)
-{
-    TypeParam o = this->j;
-    EXPECT_EQ(json(o), this->j);
-}
-
-// exception in case of a non-object type
-TEST(JsonGetObjectExceptionTest, TypeError)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is null");
-    EXPECT_THROW_MSG(json(json::value_t::array).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is array");
-    EXPECT_THROW_MSG(json(json::value_t::string).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is string");
-    EXPECT_THROW_MSG(json(json::value_t::boolean).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is boolean");
-    EXPECT_THROW_MSG(json(json::value_t::number_integer).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_unsigned).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_float).get<json::object_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is number");
-}
-
-template <typename T>
-class JsonGetArrayTest : public ::testing::Test {
- public:
-    JsonGetArrayTest() : j(a_reference) {}
-
- protected:
-    json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j;
-};
-
-typedef ::testing::Types<json::array_t, std::list<json>,
-                         /*std::forward_list<json>,*/ std::vector<json>,
-                         std::deque<json>>
-    JsonGetArrayTestTypes;
-TYPED_TEST_SUITE(JsonGetArrayTest, JsonGetArrayTestTypes, );
-
-TYPED_TEST(JsonGetArrayTest, Explicit)
-{
-    TypeParam a = (this->j).template get<TypeParam>();
-    EXPECT_EQ(json(a), this->j);
-}
-
-TYPED_TEST(JsonGetArrayTest, Implicit)
-{
-    TypeParam a = this->j;
-    EXPECT_EQ(json(a), this->j);
-}
-
-#if !defined(JSON_NOEXCEPTION)
-// reserve is called on containers that supports it
-TEST(JsonGetArrayAdditionalTest, ExplicitStdVectorReserve)
-{
-    json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()};
-    json j(a_reference);
-
-    // making the call to from_json throw in order to check capacity
-    std::vector<float> v;
-    EXPECT_THROW(wpi::from_json(j, v), json::type_error);
-    EXPECT_EQ(v.capacity(), j.size());
-
-    // make sure all values are properly copied
-    std::vector<int> v2 = json({1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
-    EXPECT_EQ(v2.size(), 10u);
-}
-#endif
-
-// built-in arrays
-TEST(JsonGetArrayAdditionalTest, ExplicitBuiltinArray)
-{
-    const char str[] = "a string";
-    const int nbs[] = {0, 1, 2};
-
-    json j2 = nbs;
-    json j3 = str;
-
-    auto v = j2.get<std::vector<int>>();
-    auto s = j3.get<std::string>();
-    EXPECT_TRUE(std::equal(v.begin(), v.end(), std::begin(nbs)));
-    EXPECT_EQ(s, str);
-}
-#if 0
-TEST(JsonGetArrayExceptionTest, ForwardList)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<std::forward_list<json>>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-}
-#endif
-TEST(JsonGetArrayExceptionTest, StdVector)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<std::vector<json>>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-}
-
-// exception in case of a non-array type
-TEST(JsonGetArrayExceptionTest, TypeError)
-{
-    EXPECT_THROW_MSG(json(json::value_t::object).get<std::vector<int>>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is object");
-    EXPECT_THROW_MSG(json(json::value_t::null).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-    EXPECT_THROW_MSG(json(json::value_t::object).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is object");
-    EXPECT_THROW_MSG(json(json::value_t::string).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is string");
-    EXPECT_THROW_MSG(json(json::value_t::boolean).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is boolean");
-    EXPECT_THROW_MSG(json(json::value_t::number_integer).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_unsigned).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_float).get<json::array_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is number");
-}
-
-template <typename T>
-class JsonGetStringTest : public ::testing::Test {
- public:
-    JsonGetStringTest() : j(s_reference) {}
-
- protected:
-    std::string s_reference {"Hello world"};
-    json j;
-};
-
-typedef ::testing::Types<std::string, std::string> JsonGetStringTestTypes;
-TYPED_TEST_SUITE(JsonGetStringTest, JsonGetStringTestTypes, );
-
-TYPED_TEST(JsonGetStringTest, Explicit)
-{
-    TypeParam s = (this->j).template get<TypeParam>();
-    EXPECT_EQ(json(s), this->j);
-}
-
-TYPED_TEST(JsonGetStringTest, Implicit)
-{
-    TypeParam s = this->j;
-    EXPECT_EQ(json(s), this->j);
-}
-
-// exception in case of a non-string type
-TEST(JsonGetStringExceptionTest, TypeError)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is null");
-    EXPECT_THROW_MSG(json(json::value_t::object).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is object");
-    EXPECT_THROW_MSG(json(json::value_t::array).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is array");
-    EXPECT_THROW_MSG(json(json::value_t::boolean).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is boolean");
-    EXPECT_THROW_MSG(json(json::value_t::number_integer).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_unsigned).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_float).get<std::string>(), json::type_error,
-                     "[json.exception.type_error.302] type must be string, but is number");
-}
-
-template <typename T>
-class JsonGetBooleanTest : public ::testing::Test {
- public:
-    JsonGetBooleanTest() : j(b_reference) {}
-
- protected:
-    bool b_reference {true};
-    json j;
-};
-
-typedef ::testing::Types<bool, bool> JsonGetBooleanTestTypes;
-TYPED_TEST_SUITE(JsonGetBooleanTest, JsonGetBooleanTestTypes, );
-
-TYPED_TEST(JsonGetBooleanTest, Explicit)
-{
-    TypeParam b = (this->j).template get<TypeParam>();
-    EXPECT_EQ(json(b), this->j);
-}
-
-TYPED_TEST(JsonGetBooleanTest, Implicit)
-{
-    TypeParam b = this->j;
-    EXPECT_EQ(json(b), this->j);
-}
-
-// exception in case of a non-string type
-TEST(JsonGetBooleanExceptionTest, TypeError)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is null");
-    EXPECT_THROW_MSG(json(json::value_t::object).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is object");
-    EXPECT_THROW_MSG(json(json::value_t::array).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is array");
-    EXPECT_THROW_MSG(json(json::value_t::string).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is string");
-    EXPECT_THROW_MSG(json(json::value_t::number_integer).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_unsigned).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is number");
-    EXPECT_THROW_MSG(json(json::value_t::number_float).get<bool>(), json::type_error,
-                     "[json.exception.type_error.302] type must be boolean, but is number");
-}
-
-template <typename T>
-class JsonGetIntegerTest : public ::testing::Test {
- public:
-    JsonGetIntegerTest() : j(n_reference), j_unsigned(n_unsigned_reference) {}
-
- protected:
-    int64_t n_reference {42};
-    json j;
-    uint64_t n_unsigned_reference {42u};
-    json j_unsigned;
-};
-
-typedef ::testing::Types<
-      short
-    , unsigned short
-    , int
-    , unsigned int
-    , long
-    , unsigned long
-    , long long
-    , unsigned long long
-    , int8_t
-    , int16_t
-    , int32_t
-    , int64_t
-#if 0
-    , int8_fast_t
-    , int16_fast_t
-    , int32_fast_t
-    , int64_fast_t
-    , int8_least_t
-    , int16_least_t
-    , int32_least_t
-    , int64_least_t
-#endif
-    , uint8_t
-    , uint16_t
-    , uint32_t
-    , uint64_t
-#if 0
-    , uint8_fast_t
-    , uint16_fast_t
-    , uint32_fast_t
-    , uint64_fast_t
-    , uint8_least_t
-    , uint16_least_t
-    , uint32_least_t
-    , uint64_least_t
-#endif
-    > JsonGetIntegerTestTypes;
-
-TYPED_TEST_SUITE(JsonGetIntegerTest, JsonGetIntegerTestTypes, );
-
-TYPED_TEST(JsonGetIntegerTest, Explicit)
-{
-    TypeParam n = (this->j).template get<TypeParam>();
-    EXPECT_EQ(json(n), this->j);
-}
-
-TYPED_TEST(JsonGetIntegerTest, Implicit)
-{
-    if (std::is_unsigned<TypeParam>::value)
-    {
-        TypeParam n = this->j_unsigned;
-        EXPECT_EQ(json(n), this->j_unsigned);
-    }
-    else
-    {
-        TypeParam n = this->j;
-        EXPECT_EQ(json(n), this->j);
-    }
-}
-
-// exception in case of a non-number type
-TEST(JsonGetIntegerExceptionTest, TypeError)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<int64_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is null");
-    EXPECT_THROW_MSG(json(json::value_t::object).get<int64_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is object");
-    EXPECT_THROW_MSG(json(json::value_t::array).get<int64_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is array");
-    EXPECT_THROW_MSG(json(json::value_t::string).get<int64_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is string");
-    EXPECT_THROW_MSG(json(json::value_t::boolean).get<int64_t>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is boolean");
-
-    EXPECT_NO_THROW(json(json::value_t::number_float).get<int64_t>());
-    EXPECT_NO_THROW(json(json::value_t::number_float).get<uint64_t>());
-}
-
-template <typename T>
-class JsonGetFloatTest : public ::testing::Test {
- public:
-    JsonGetFloatTest() : j(n_reference) {}
-
- protected:
-    double n_reference {42.23};
-    json j;
-};
-
-typedef ::testing::Types<double, float, double>
-    JsonGetFloatTestTypes;
-
-TYPED_TEST_SUITE(JsonGetFloatTest, JsonGetFloatTestTypes, );
-
-TYPED_TEST(JsonGetFloatTest, Explicit)
-{
-    TypeParam n = (this->j).template get<TypeParam>();
-    EXPECT_LT(std::fabs(JsonTest::GetValue(json(n)).number_float -
-                        JsonTest::GetValue(this->j).number_float), 0.001);
-}
-
-TYPED_TEST(JsonGetFloatTest, Implicit)
-{
-    TypeParam n = this->j;
-    EXPECT_LT(std::fabs(JsonTest::GetValue(json(n)).number_float -
-                        JsonTest::GetValue(this->j).number_float), 0.001);
-}
-
-// exception in case of a non-string type
-TEST(JsonGetFloatExceptionTest, TypeError)
-{
-    EXPECT_THROW_MSG(json(json::value_t::null).get<double>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is null");
-    EXPECT_THROW_MSG(json(json::value_t::object).get<double>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is object");
-    EXPECT_THROW_MSG(json(json::value_t::array).get<double>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is array");
-    EXPECT_THROW_MSG(json(json::value_t::string).get<double>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is string");
-    EXPECT_THROW_MSG(json(json::value_t::boolean).get<double>(), json::type_error,
-                     "[json.exception.type_error.302] type must be number, but is boolean");
-
-    EXPECT_NO_THROW(json(json::value_t::number_integer).get<double>());
-    EXPECT_NO_THROW(json(json::value_t::number_unsigned).get<double>());
-}
-
-TEST(JsonGetEnumTest, Case)
-{
-    enum c_enum { value_1, value_2 };
-    enum class cpp_enum { value_1, value_2 };
-
-    EXPECT_EQ(json(value_1).get<c_enum>(), value_1);
-    EXPECT_EQ(json(cpp_enum::value_1).get<cpp_enum>(), cpp_enum::value_1);
-}
-
-class JsonObjectConversionTest : public ::testing::Test {
- protected:
-    json j1 = {{"one", 1}, {"two", 2}, {"three", 3}};
-    json j2 = {{"one", 1u}, {"two", 2u}, {"three", 3u}};
-    json j3 = {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}};
-    json j4 = {{"one", true}, {"two", false}, {"three", true}};
-    json j5 = {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}};
-};
-
-TEST_F(JsonObjectConversionTest, StdMap)
-{
-    auto m1 = j1.get<std::map<std::string, int>>();
-    auto m2 = j2.get<std::map<std::string, unsigned int>>();
-    auto m3 = j3.get<std::map<std::string, double>>();
-    auto m4 = j4.get<std::map<std::string, bool>>();
-    //auto m5 = j5.get<std::map<std::string, std::string>>();
-}
-
-TEST_F(JsonObjectConversionTest, StdUnorderedMap)
-{
-    auto m1 = j1.get<std::unordered_map<std::string, int>>();
-    auto m2 = j2.get<std::unordered_map<std::string, unsigned int>>();
-    auto m3 = j3.get<std::unordered_map<std::string, double>>();
-    auto m4 = j4.get<std::unordered_map<std::string, bool>>();
-    //auto m5 = j5.get<std::unordered_map<std::string, std::string>>();
-    //CHECK(m5["one"] == "eins");
-}
-
-TEST_F(JsonObjectConversionTest, StdMultiMap)
-{
-    auto m1 = j1.get<std::multimap<std::string, int>>();
-    auto m2 = j2.get<std::multimap<std::string, unsigned int>>();
-    auto m3 = j3.get<std::multimap<std::string, double>>();
-    auto m4 = j4.get<std::multimap<std::string, bool>>();
-    //auto m5 = j5.get<std::multimap<std::string, std::string>>();
-    //CHECK(m5["one"] == "eins");
-}
-
-TEST_F(JsonObjectConversionTest, StdUnorderedMultiMap)
-{
-    auto m1 = j1.get<std::unordered_multimap<std::string, int>>();
-    auto m2 = j2.get<std::unordered_multimap<std::string, unsigned int>>();
-    auto m3 = j3.get<std::unordered_multimap<std::string, double>>();
-    auto m4 = j4.get<std::unordered_multimap<std::string, bool>>();
-    //auto m5 = j5.get<std::unordered_multimap<std::string, std::string>>();
-    //CHECK(m5["one"] == "eins");
-}
-
-// exception in case of a non-object type
-TEST_F(JsonObjectConversionTest, Exception)
-{
-    EXPECT_THROW_MSG((json().get<std::map<std::string, int>>()), json::type_error,
-                     "[json.exception.type_error.302] type must be object, but is null");
-}
-
-class JsonArrayConversionTest : public ::testing::Test {
- protected:
-    json j1 = {1, 2, 3, 4};
-    json j2 = {1u, 2u, 3u, 4u};
-    json j3 = {1.2, 2.3, 3.4, 4.5};
-    json j4 = {true, false, true};
-    json j5 = {"one", "two", "three"};
-};
-
-TEST_F(JsonArrayConversionTest, StdList)
-{
-    auto m1 = j1.get<std::list<int>>();
-    auto m2 = j2.get<std::list<unsigned int>>();
-    auto m3 = j3.get<std::list<double>>();
-    auto m4 = j4.get<std::list<bool>>();
-    auto m5 = j5.get<std::list<std::string>>();
-}
-
-#if 0
-TEST_F(JsonArrayConversionTest, StdForwardList)
-{
-    auto m1 = j1.get<std::forward_list<int>>();
-    auto m2 = j2.get<std::forward_list<unsigned int>>();
-    auto m3 = j3.get<std::forward_list<double>>();
-    auto m4 = j4.get<std::forward_list<bool>>();
-    auto m5 = j5.get<std::forward_list<std::string>>();
-}
-#endif
-
-TEST_F(JsonArrayConversionTest, StdVector)
-{
-    auto m1 = j1.get<std::vector<int>>();
-    auto m2 = j2.get<std::vector<unsigned int>>();
-    auto m3 = j3.get<std::vector<double>>();
-    auto m4 = j4.get<std::vector<bool>>();
-    auto m5 = j5.get<std::vector<std::string>>();
-}
-
-TEST_F(JsonArrayConversionTest, StdDeque)
-{
-    auto m1 = j1.get<std::deque<int>>();
-    auto m2 = j2.get<std::deque<unsigned int>>();
-    auto m3 = j2.get<std::deque<double>>();
-    auto m4 = j4.get<std::deque<bool>>();
-    auto m5 = j5.get<std::deque<std::string>>();
-}
-
-TEST_F(JsonArrayConversionTest, StdSet)
-{
-    auto m1 = j1.get<std::set<int>>();
-    auto m2 = j2.get<std::set<unsigned int>>();
-    auto m3 = j3.get<std::set<double>>();
-    auto m4 = j4.get<std::set<bool>>();
-    auto m5 = j5.get<std::set<std::string>>();
-}
-
-TEST_F(JsonArrayConversionTest, StdUnorderedSet)
-{
-    auto m1 = j1.get<std::unordered_set<int>>();
-    auto m2 = j2.get<std::unordered_set<unsigned int>>();
-    auto m3 = j3.get<std::unordered_set<double>>();
-    auto m4 = j4.get<std::unordered_set<bool>>();
-    auto m5 = j5.get<std::unordered_set<std::string>>();
-}
-
-// exception in case of a non-object type
-TEST_F(JsonArrayConversionTest, Exception)
-{
-    EXPECT_THROW_MSG((json().get<std::list<int>>()), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-    EXPECT_THROW_MSG((json().get<std::vector<int>>()), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-    EXPECT_THROW_MSG((json().get<std::vector<json>>()), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-    EXPECT_THROW_MSG((json().get<std::list<json>>()), json::type_error,
-                     "[json.exception.type_error.302] type must be array, but is null");
-    // does type really must be an array? or it rather must not be null?
-    // that's what I thought when other test like this one broke
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-deserialization.cpp b/wpiutil/src/test/native/cpp/json/unit-deserialization.cpp
deleted file mode 100644
index 2505ef5..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-deserialization.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-#include "wpi/raw_istream.h"
-using wpi::json;
-
-#include <valarray>
-
-TEST(JsonDeserializationTest, SuccessfulStream)
-{
-    std::string s = "[\"foo\",1,2,3,false,{\"one\":1}]";
-    wpi::raw_mem_istream ss(s.data(), s.size());
-    json j = json::parse(ss);
-    ASSERT_EQ(j, json({"foo", 1, 2, 3, false, {{"one", 1}}}));
-}
-
-TEST(JsonDeserializationTest, SuccessfulStringLiteral)
-{
-    auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
-    json j = json::parse(s);
-    ASSERT_EQ(j, json({"foo", 1, 2, 3, false, {{"one", 1}}}));
-}
-
-TEST(JsonDeserializationTest, SuccessfulStdString)
-{
-    std::string s = "[\"foo\",1,2,3,false,{\"one\":1}]";
-    json j = json::parse(s);
-    ASSERT_EQ(j, json({"foo", 1, 2, 3, false, {{"one", 1}}}));
-}
-
-TEST(JsonDeserializationTest, SuccessfulStreamOperator)
-{
-    std::string s = "[\"foo\",1,2,3,false,{\"one\":1}]";
-    wpi::raw_mem_istream ss(s.data(), s.size());
-    json j;
-    ss >> j;
-    ASSERT_EQ(j, json({"foo", 1, 2, 3, false, {{"one", 1}}}));
-}
-
-TEST(JsonDeserializationTest, SuccessfulUserStringLiteral)
-{
-    ASSERT_EQ("[\"foo\",1,2,3,false,{\"one\":1}]"_json, json({"foo", 1, 2, 3, false, {{"one", 1}}}));
-}
-
-TEST(JsonDeserializationTest, UnsuccessfulStream)
-{
-    std::string s = "[\"foo\",1,2,3,false,{\"one\":1}";
-    wpi::raw_mem_istream ss(s.data(), s.size());
-    ASSERT_THROW_MSG(json::parse(ss), json::parse_error,
-                     "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'");
-}
-
-TEST(JsonDeserializationTest, UnsuccessfulStdString)
-{
-    std::string s = "[\"foo\",1,2,3,false,{\"one\":1}";
-    ASSERT_THROW_MSG(json::parse(s), json::parse_error,
-                     "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'");
-}
-
-TEST(JsonDeserializationTest, UnsuccessfulStreamOperator)
-{
-    std::string s = "[\"foo\",1,2,3,false,{\"one\":1}";
-    wpi::raw_mem_istream ss(s.data(), s.size());
-    json j;
-    ASSERT_THROW_MSG(ss >> j, json::parse_error,
-                     "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'");
-}
-
-TEST(JsonDeserializationTest, UnsuccessfulUserStringLiteral)
-{
-    ASSERT_THROW_MSG("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error,
-                     "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'");
-}
-
-// these cases are required for 100% line coverage
-class JsonDeserializationErrorTest
-    : public ::testing::TestWithParam<const char*> {};
-
-TEST_P(JsonDeserializationErrorTest, ErrorCase)
-{
-    ASSERT_THROW(json::parse(GetParam()), json::parse_error);
-}
-
-static const char* error_cases[] = {
-    "\"aaaaaa\\u",
-    "\"aaaaaa\\u1",
-    "\"aaaaaa\\u11111111",
-    "\"aaaaaau11111111\\",
-    "\"\x7F\xC1",
-    "\"\x7F\xDF\x7F",
-    "\"\x7F\xDF\xC0",
-    "\"\x7F\xE0\x9F",
-    "\"\x7F\xEF\xC0",
-    "\"\x7F\xED\x7F",
-    "\"\x7F\xF0\x8F",
-    "\"\x7F\xF0\xC0",
-    "\"\x7F\xF3\x7F",
-    "\"\x7F\xF3\xC0",
-    "\"\x7F\xF4\x7F",
-};
-
-INSTANTIATE_TEST_SUITE_P(JsonDeserializationErrorTests,
-                        JsonDeserializationErrorTest,
-                        ::testing::ValuesIn(error_cases));
diff --git a/wpiutil/src/test/native/cpp/json/unit-element_access1.cpp b/wpiutil/src/test/native/cpp/json/unit-element_access1.cpp
deleted file mode 100644
index a97d6b6..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-element_access1.cpp
+++ /dev/null
@@ -1,873 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-class JsonElementArrayAccessTestBase {
- public:
-    JsonElementArrayAccessTestBase() : j_const(j) {}
-
- protected:
-    json j = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
-    const json j_const;
-};
-
-class JsonElementArrayAccessTest : public ::testing::Test,
-                                   public JsonElementArrayAccessTestBase {};
-
-TEST_F(JsonElementArrayAccessTest, AtWithinBounds)
-{
-    EXPECT_EQ(j.at(0), json(1));
-    EXPECT_EQ(j.at(1), json(1u));
-    EXPECT_EQ(j.at(2), json(true));
-    EXPECT_EQ(j.at(3), json(nullptr));
-    EXPECT_EQ(j.at(4), json("string"));
-    EXPECT_EQ(j.at(5), json(42.23));
-    EXPECT_EQ(j.at(6), json::object());
-    EXPECT_EQ(j.at(7), json({1, 2, 3}));
-
-    EXPECT_EQ(j_const.at(0), json(1));
-    EXPECT_EQ(j_const.at(1), json(1u));
-    EXPECT_EQ(j_const.at(2), json(true));
-    EXPECT_EQ(j_const.at(3), json(nullptr));
-    EXPECT_EQ(j_const.at(4), json("string"));
-    EXPECT_EQ(j_const.at(5), json(42.23));
-    EXPECT_EQ(j_const.at(6), json::object());
-    EXPECT_EQ(j_const.at(7), json({1, 2, 3}));
-}
-
-TEST_F(JsonElementArrayAccessTest, AtOutsideBounds)
-{
-    EXPECT_THROW_MSG(j.at(8), json::out_of_range,
-                     "[json.exception.out_of_range.401] array index 8 is out of range");
-    EXPECT_THROW_MSG(j_const.at(8), json::out_of_range,
-                     "[json.exception.out_of_range.401] array index 8 is out of range");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, Null)
-{
-    json j_nonarray(json::value_t::null);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with null");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with null");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, Boolean)
-{
-    json j_nonarray(json::value_t::boolean);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with boolean");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with boolean");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, String)
-{
-    json j_nonarray(json::value_t::string);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with string");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with string");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, Object)
-{
-    json j_nonarray(json::value_t::object);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with object");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with object");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, Integer)
-{
-    json j_nonarray(json::value_t::number_integer);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, Unsigned)
-{
-    json j_nonarray(json::value_t::number_unsigned);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST(JsonElementNonArrayAtAccessTest, Float)
-{
-    json j_nonarray(json::value_t::number_float);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-    EXPECT_THROW_MSG(j_nonarray_const.at(0), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST_F(JsonElementArrayAccessTest, FrontAndBack)
-{
-    EXPECT_EQ(j.front(), json(1));
-    EXPECT_EQ(j_const.front(), json(1));
-    EXPECT_EQ(j.back(), json({1, 2, 3}));
-    EXPECT_EQ(j_const.back(), json({1, 2, 3}));
-}
-
-TEST_F(JsonElementArrayAccessTest, OperatorWithinBounds)
-{
-    EXPECT_EQ(j[0], json(1));
-    EXPECT_EQ(j[1], json(1u));
-    EXPECT_EQ(j[2], json(true));
-    EXPECT_EQ(j[3], json(nullptr));
-    EXPECT_EQ(j[4], json("string"));
-    EXPECT_EQ(j[5], json(42.23));
-    EXPECT_EQ(j[6], json::object());
-    EXPECT_EQ(j[7], json({1, 2, 3}));
-
-    EXPECT_EQ(j_const[0], json(1));
-    EXPECT_EQ(j_const[1], json(1u));
-    EXPECT_EQ(j_const[2], json(true));
-    EXPECT_EQ(j_const[3], json(nullptr));
-    EXPECT_EQ(j_const[4], json("string"));
-    EXPECT_EQ(j_const[5], json(42.23));
-    EXPECT_EQ(j_const[6], json::object());
-    EXPECT_EQ(j_const[7], json({1, 2, 3}));
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, NullStandard)
-{
-    json j_nonarray(json::value_t::null);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_NO_THROW(j_nonarray[0]);
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with null");
-}
-
-// implicit transformation to properly filled array
-TEST(JsonElementNonArrayOperatorAccessTest, NullImplicitFilled)
-{
-    json j_nonarray;
-    j_nonarray[3] = 42;
-    EXPECT_EQ(j_nonarray, json({nullptr, nullptr, nullptr, 42}));
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, Boolean)
-{
-    json j_nonarray(json::value_t::boolean);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with boolean");
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with boolean");
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, String)
-{
-    json j_nonarray(json::value_t::string);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with string");
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with string");
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, Object)
-{
-    json j_nonarray(json::value_t::object);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with object");
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with object");
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, Integer)
-{
-    json j_nonarray(json::value_t::number_integer);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, Unsigned)
-{
-    json j_nonarray(json::value_t::number_unsigned);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-}
-
-TEST(JsonElementNonArrayOperatorAccessTest, Float)
-{
-    json j_nonarray(json::value_t::number_float);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_THROW_MSG(j_nonarray[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_nonarray_const[0], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-}
-
-class JsonElementArrayRemoveTest : public ::testing::Test,
-                                   public JsonElementArrayAccessTestBase {};
-
-
-// remove element by index
-TEST_F(JsonElementArrayRemoveTest, Index0)
-{
-    j.erase(0);
-    EXPECT_EQ(j, json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index1)
-{
-    j.erase(1);
-    EXPECT_EQ(j, json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index2)
-{
-    j.erase(2);
-    EXPECT_EQ(j, json({1, 1u, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index3)
-{
-    j.erase(3);
-    EXPECT_EQ(j, json({1, 1u, true, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index4)
-{
-    j.erase(4);
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index5)
-{
-    j.erase(5);
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, "string", json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index6)
-{
-    j.erase(6);
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, "string", 42.23, {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index7)
-{
-    j.erase(7);
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, "string", 42.23, json::object()}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, Index8)
-{
-    EXPECT_THROW_MSG(j.erase(8), json::out_of_range,
-                     "[json.exception.out_of_range.401] array index 8 is out of range");
-}
-
-// erase(begin())
-TEST_F(JsonElementArrayRemoveTest, Begin)
-{
-    j.erase(j.begin());
-    EXPECT_EQ(j, json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, BeginConst)
-{
-    j.erase(j.cbegin());
-    EXPECT_EQ(j, json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-// erase(begin(), end())
-TEST_F(JsonElementArrayRemoveTest, BeginEnd)
-{
-    j.erase(j.begin(), j.end());
-    EXPECT_EQ(j, json::array());
-}
-TEST_F(JsonElementArrayRemoveTest, BeginEndConst)
-{
-    j.erase(j.cbegin(), j.cend());
-    EXPECT_EQ(j, json::array());
-}
-
-// erase(begin(), begin())
-TEST_F(JsonElementArrayRemoveTest, BeginBegin)
-{
-    j.erase(j.begin(), j.begin());
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, BeginBeginConst)
-{
-    j.erase(j.cbegin(), j.cbegin());
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
-}
-
-// erase at offset
-TEST_F(JsonElementArrayRemoveTest, Offset)
-{
-    json::iterator it = j.begin() + 4;
-    j.erase(it);
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, OffsetConst)
-{
-    json::const_iterator it = j.cbegin() + 4;
-    j.erase(it);
-    EXPECT_EQ(j, json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
-}
-
-// erase subrange
-TEST_F(JsonElementArrayRemoveTest, Subrange)
-{
-    j.erase(j.begin() + 3, j.begin() + 6);
-    EXPECT_EQ(j, json({1, 1u, true, json::object(), {1, 2, 3}}));
-}
-
-TEST_F(JsonElementArrayRemoveTest, SubrangeConst)
-{
-    j.erase(j.cbegin() + 3, j.cbegin() + 6);
-    EXPECT_EQ(j, json({1, 1u, true, json::object(), {1, 2, 3}}));
-}
-
-// different arrays
-TEST_F(JsonElementArrayRemoveTest, Different)
-{
-    json j2 = {"foo", "bar"};
-    EXPECT_THROW_MSG(j.erase(j2.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(j.erase(j.begin(), j2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(j.erase(j2.begin(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(j.erase(j2.begin(), j2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-}
-
-TEST_F(JsonElementArrayRemoveTest, DifferentConst)
-{
-    json j2 = {"foo", "bar"};
-    EXPECT_THROW_MSG(j.erase(j2.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j2.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(j.erase(j2.cbegin(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(j.erase(j2.cbegin(), j2.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-}
-
-// remove element by index in non-array type
-TEST(JsonElementNonArrayIndexRemoveTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with null");
-}
-
-TEST(JsonElementNonArrayIndexRemoveTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with boolean");
-}
-
-TEST(JsonElementNonArrayIndexRemoveTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with string");
-}
-
-TEST(JsonElementNonArrayIndexRemoveTest, Object)
-{
-    json j_nonobject(json::value_t::object);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with object");
-}
-
-TEST(JsonElementNonArrayIndexRemoveTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with number");
-}
-
-TEST(JsonElementNonArrayIndexRemoveTest, Unsigned)
-{
-    json j_nonobject(json::value_t::number_unsigned);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with number");
-}
-
-TEST(JsonElementNonArrayIndexRemoveTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    EXPECT_THROW_MSG(j_nonobject.erase(0), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with number");
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, Null)
-{
-    json j;
-    EXPECT_THROW_MSG(j.front(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(j.back(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, NullConst)
-{
-    const json j{};
-    EXPECT_THROW_MSG(j.front(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(j.back(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, String)
-{
-    json j = "foo";
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, StringConst)
-{
-    const json j = "bar";
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, Boolean)
-{
-    json j = false;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, BooleanConst)
-{
-    const json j = true;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, Integer)
-{
-    json j = 17;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, IntegerConst)
-{
-    const json j = 17;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, Unsigned)
-{
-    json j = 17u;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, UnsignedConst)
-{
-    const json j = 17u;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, Float)
-{
-    json j = 23.42;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayFrontBackAccessTest, FloatConst)
-{
-    const json j = 23.42;
-    EXPECT_EQ(j.front(), j);
-    EXPECT_EQ(j.back(), j);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, Null)
-{
-    json j;
-    EXPECT_THROW_MSG(j.erase(j.begin()), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with null");
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, NullConst)
-{
-    json j;
-    EXPECT_THROW_MSG(j.erase(j.cbegin()), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with null");
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, String)
-{
-    json j = "foo";
-    j.erase(j.begin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, StringConst)
-{
-    json j = "bar";
-    j.erase(j.cbegin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, Boolean)
-{
-    json j = false;
-    j.erase(j.begin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, BooleanConst)
-{
-    json j = true;
-    j.erase(j.cbegin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, Integer)
-{
-    json j = 17;
-    j.erase(j.begin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, IntegerConst)
-{
-    json j = 17;
-    j.erase(j.cbegin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, Unsigned)
-{
-    json j = 17u;
-    j.erase(j.begin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, UnsignedConst)
-{
-    json j = 17u;
-    j.erase(j.cbegin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, Float)
-{
-    json j = 23.42;
-    j.erase(j.begin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneValidIteratorRemoveTest, FloatConst)
-{
-    json j = 23.42;
-    j.erase(j.cbegin());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, String)
-{
-    json j = "foo";
-    EXPECT_THROW_MSG(j.erase(j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, StringConst)
-{
-    json j = "bar";
-    EXPECT_THROW_MSG(j.erase(j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, Boolean)
-{
-    json j = false;
-    EXPECT_THROW_MSG(j.erase(j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, BooleanConst)
-{
-    json j = true;
-    EXPECT_THROW_MSG(j.erase(j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, Integer)
-{
-    json j = 17;
-    EXPECT_THROW_MSG(j.erase(j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, IntegerConst)
-{
-    json j = 17;
-    EXPECT_THROW_MSG(j.erase(j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, Unsigned)
-{
-    json j = 17u;
-    EXPECT_THROW_MSG(j.erase(j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, UnsignedConst)
-{
-    json j = 17u;
-    EXPECT_THROW_MSG(j.erase(j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, Float)
-{
-    json j = 23.42;
-    EXPECT_THROW_MSG(j.erase(j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayOneInvalidIteratorRemoveTest, FloatConst)
-{
-    json j = 23.42;
-    EXPECT_THROW_MSG(j.erase(j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.205] iterator out of range");
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, Null)
-{
-    json j;
-    EXPECT_THROW_MSG(j.erase(j.begin(), j.end()), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with null");
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, NullConst)
-{
-    json j;
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j.cend()), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with null");
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, String)
-{
-    json j = "foo";
-    j.erase(j.begin(), j.end());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, StringConst)
-{
-    json j = "bar";
-    j.erase(j.cbegin(), j.cend());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, Boolean)
-{
-    json j = false;
-    j.erase(j.begin(), j.end());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, BooleanConst)
-{
-    json j = true;
-    j.erase(j.cbegin(), j.cend());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, Integer)
-{
-    json j = 17;
-    j.erase(j.begin(), j.end());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, IntegerConst)
-{
-    json j = 17;
-    j.erase(j.cbegin(), j.cend());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, Unsigned)
-{
-    json j = 17u;
-    j.erase(j.begin(), j.end());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, UnsignedConst)
-{
-    json j = 17u;
-    j.erase(j.cbegin(), j.cend());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, Float)
-{
-    json j = 23.42;
-    j.erase(j.begin(), j.end());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoValidIteratorRemoveTest, FloatConst)
-{
-    json j = 23.42;
-    j.erase(j.cbegin(), j.cend());
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, String)
-{
-    json j = "foo";
-    EXPECT_THROW_MSG(j.erase(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, StringConst)
-{
-    json j = "bar";
-    EXPECT_THROW_MSG(j.erase(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, Boolean)
-{
-    json j = false;
-    EXPECT_THROW_MSG(j.erase(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, BooleanConst)
-{
-    json j = true;
-    EXPECT_THROW_MSG(j.erase(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, Integer)
-{
-    json j = 17;
-    EXPECT_THROW_MSG(j.erase(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, IntegerConst)
-{
-    json j = 17;
-    EXPECT_THROW_MSG(j.erase(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, Unsigned)
-{
-    json j = 17u;
-    EXPECT_THROW_MSG(j.erase(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, UnsignedConst)
-{
-    json j = 17u;
-    EXPECT_THROW_MSG(j.erase(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, Float)
-{
-    json j = 23.42;
-    EXPECT_THROW_MSG(j.erase(j.end(), j.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.begin(), j.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
-
-TEST(JsonElementNonArrayTwoInvalidIteratorRemoveTest, FloatConst)
-{
-    json j = 23.42;
-    EXPECT_THROW_MSG(j.erase(j.cend(), j.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-    EXPECT_THROW_MSG(j.erase(j.cbegin(), j.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.204] iterators out of range");
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-element_access2.cpp b/wpiutil/src/test/native/cpp/json/unit-element_access2.cpp
deleted file mode 100644
index ab953bd..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-element_access2.cpp
+++ /dev/null
@@ -1,926 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-
-#include <cmath>
-
-using wpi::json;
-
-class JsonElementObjectAccessTestBase {
- public:
-    JsonElementObjectAccessTestBase() : j_const(j) {}
-
- protected:
-    json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}};
-    const json j_const;
-};
-
-class JsonElementObjectAccessTest : public ::testing::Test,
-                                    public JsonElementObjectAccessTestBase {};
-
-TEST_F(JsonElementObjectAccessTest, AtWithinBounds)
-{
-    EXPECT_EQ(j.at("integer"), json(1));
-    EXPECT_EQ(j.at("unsigned"), json(1u));
-    EXPECT_EQ(j.at("boolean"), json(true));
-    EXPECT_EQ(j.at("null"), json(nullptr));
-    EXPECT_EQ(j.at("string"), json("hello world"));
-    EXPECT_EQ(j.at("floating"), json(42.23));
-    EXPECT_EQ(j.at("object"), json::object());
-    EXPECT_EQ(j.at("array"), json({1, 2, 3}));
-
-    EXPECT_EQ(j_const.at("integer"), json(1));
-    EXPECT_EQ(j_const.at("unsigned"), json(1u));
-    EXPECT_EQ(j_const.at("boolean"), json(true));
-    EXPECT_EQ(j_const.at("null"), json(nullptr));
-    EXPECT_EQ(j_const.at("string"), json("hello world"));
-    EXPECT_EQ(j_const.at("floating"), json(42.23));
-    EXPECT_EQ(j_const.at("object"), json::object());
-    EXPECT_EQ(j_const.at("array"), json({1, 2, 3}));
-}
-
-TEST_F(JsonElementObjectAccessTest, AtOutsideBounds)
-{
-    EXPECT_THROW_MSG(j.at("foo"), json::out_of_range,
-                     "[json.exception.out_of_range.403] key 'foo' not found");
-    EXPECT_THROW_MSG(j_const.at("foo"), json::out_of_range,
-                     "[json.exception.out_of_range.403] key 'foo' not found");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with null");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with null");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with boolean");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with boolean");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with string");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with string");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, Array)
-{
-    json j_nonobject(json::value_t::array);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with array");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with array");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, Unsigned)
-{
-    json j_nonobject(json::value_t::number_unsigned);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST(JsonElementNonObjectAtAccessTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.at("foo"), json::type_error,
-                     "[json.exception.type_error.304] cannot use at() with number");
-}
-
-TEST_F(JsonElementObjectAccessTest, KeyValueExist)
-{
-    EXPECT_EQ(j.value("integer", 2), 1);
-    EXPECT_LT(std::fabs(j.value("integer", 1.0) - 1), 0.001);
-    EXPECT_EQ(j.value("unsigned", 2), 1);
-    EXPECT_LT(std::fabs(j.value("unsigned", 1.0) - 1), 0.001);
-    EXPECT_EQ(j.value("null", json(1)), json());
-    EXPECT_EQ(j.value("boolean", false), true);
-    EXPECT_EQ(j.value("string", "bar"), "hello world");
-    EXPECT_EQ(j.value("string", std::string("bar")), "hello world");
-    EXPECT_LT(std::fabs(j.value("floating", 12.34) - 42.23), 0.001);
-    EXPECT_EQ(j.value("floating", 12), 42);
-    EXPECT_EQ(j.value("object", json({{"foo", "bar"}})), json::object());
-    EXPECT_EQ(j.value("array", json({10, 100})), json({1, 2, 3}));
-
-    EXPECT_EQ(j_const.value("integer", 2), 1);
-    EXPECT_LT(std::fabs(j_const.value("integer", 1.0) - 1), 0.001);
-    EXPECT_EQ(j_const.value("unsigned", 2), 1);
-    EXPECT_LT(std::fabs(j_const.value("unsigned", 1.0) - 1), 0.001);
-    EXPECT_EQ(j_const.value("boolean", false), true);
-    EXPECT_EQ(j_const.value("string", "bar"), "hello world");
-    EXPECT_EQ(j_const.value("string", std::string("bar")), "hello world");
-    EXPECT_LT(std::fabs(j_const.value("floating", 12.34) - 42.23), 0.001);
-    EXPECT_EQ(j_const.value("floating", 12), 42);
-    EXPECT_EQ(j_const.value("object", json({{"foo", "bar"}})), json::object());
-    EXPECT_EQ(j_const.value("array", json({10, 100})), json({1, 2, 3}));
-}
-
-TEST_F(JsonElementObjectAccessTest, KeyValueNotExist)
-{
-    EXPECT_EQ(j.value("_", 2), 2);
-    EXPECT_EQ(j.value("_", 2u), 2u);
-    EXPECT_EQ(j.value("_", false), false);
-    EXPECT_EQ(j.value("_", "bar"), "bar");
-    EXPECT_LT(std::fabs(j.value("_", 12.34) - 12.34), 0.001);
-    EXPECT_EQ(j.value("_", json({{"foo", "bar"}})), json({{"foo", "bar"}}));
-    EXPECT_EQ(j.value("_", json({10, 100})), json({10, 100}));
-
-    EXPECT_EQ(j_const.value("_", 2), 2);
-    EXPECT_EQ(j_const.value("_", 2u), 2u);
-    EXPECT_EQ(j_const.value("_", false), false);
-    EXPECT_EQ(j_const.value("_", "bar"), "bar");
-    EXPECT_LT(std::fabs(j_const.value("_", 12.34) - 12.34), 0.001);
-    EXPECT_EQ(j_const.value("_", json({{"foo", "bar"}})), json({{"foo", "bar"}}));
-    EXPECT_EQ(j_const.value("_", json({10, 100})), json({10, 100}));
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with null");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with null");
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with boolean");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with boolean");
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with string");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with string");
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, Array)
-{
-    json j_nonobject(json::value_t::array);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with array");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with array");
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, Unsigned)
-{
-    json j_nonobject(json::value_t::number_unsigned);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-}
-
-TEST(JsonElementNonObjectKeyValueAccessTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.value("foo", 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-}
-
-TEST_F(JsonElementObjectAccessTest, PointerValueExist)
-{
-    EXPECT_EQ(j.value("/integer"_json_pointer, 2), 1);
-    EXPECT_LT(std::fabs(j.value("/integer"_json_pointer, 1.0) - 1), 0.001);
-    EXPECT_EQ(j.value("/unsigned"_json_pointer, 2), 1);
-    EXPECT_LT(std::fabs(j.value("/unsigned"_json_pointer, 1.0) - 1), 0.001);
-    EXPECT_EQ(j.value("/null"_json_pointer, json(1)), json());
-    EXPECT_EQ(j.value("/boolean"_json_pointer, false), true);
-    EXPECT_EQ(j.value("/string"_json_pointer, "bar"), "hello world");
-    EXPECT_EQ(j.value("/string"_json_pointer, std::string("bar")), "hello world");
-    EXPECT_LT(std::fabs(j.value("/floating"_json_pointer, 12.34) - 42.23), 0.001);
-    EXPECT_EQ(j.value("/floating"_json_pointer, 12), 42);
-    EXPECT_EQ(j.value("/object"_json_pointer, json({{"foo", "bar"}})), json::object());
-    EXPECT_EQ(j.value("/array"_json_pointer, json({10, 100})), json({1, 2, 3}));
-
-    EXPECT_EQ(j_const.value("/integer"_json_pointer, 2), 1);
-    EXPECT_LT(std::fabs(j_const.value("/integer"_json_pointer, 1.0) - 1), 0.001);
-    EXPECT_EQ(j_const.value("/unsigned"_json_pointer, 2), 1);
-    EXPECT_LT(std::fabs(j_const.value("/unsigned"_json_pointer, 1.0) - 1), 0.001);
-    EXPECT_EQ(j_const.value("/boolean"_json_pointer, false), true);
-    EXPECT_EQ(j_const.value("/string"_json_pointer, "bar"), "hello world");
-    EXPECT_EQ(j_const.value("/string"_json_pointer, std::string("bar")), "hello world");
-    EXPECT_LT(std::fabs(j_const.value("/floating"_json_pointer, 12.34) - 42.23), 0.001);
-    EXPECT_EQ(j_const.value("/floating"_json_pointer, 12), 42);
-    EXPECT_EQ(j_const.value("/object"_json_pointer, json({{"foo", "bar"}})), json::object());
-    EXPECT_EQ(j_const.value("/array"_json_pointer, json({10, 100})), json({1, 2, 3}));
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with null");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with null");
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with boolean");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with boolean");
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with string");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with string");
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, Array)
-{
-    json j_nonobject(json::value_t::array);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with array");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with array");
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, Unsigned)
-{
-    json j_nonobject(json::value_t::number_unsigned);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-}
-
-TEST(JsonElementNonObjectPointerValueAccessTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-    EXPECT_THROW_MSG(j_nonobject_const.value("/foo"_json_pointer, 1), json::type_error,
-                     "[json.exception.type_error.306] cannot use value() with number");
-}
-#if 0
-TEST_F(JsonElementObjectAccessTest, FrontAndBack)
-{
-    // "array" is the smallest key
-    EXPECT_EQ(j.front(), json({1, 2, 3}));
-    EXPECT_EQ(j_const.front(), json({1, 2, 3}));
-    // "unsigned" is the largest key
-    EXPECT_EQ(j.back(), json(1u));
-    EXPECT_EQ(j_const.back(), json(1u));
-}
-#endif
-TEST_F(JsonElementObjectAccessTest, OperatorWithinBounds)
-{
-    EXPECT_EQ(j["integer"], json(1));
-    EXPECT_EQ(j[json::object_t::key_type("integer")], j["integer"]);
-
-    EXPECT_EQ(j["unsigned"], json(1u));
-    EXPECT_EQ(j[json::object_t::key_type("unsigned")], j["unsigned"]);
-
-    EXPECT_EQ(j["boolean"], json(true));
-    EXPECT_EQ(j[json::object_t::key_type("boolean")], j["boolean"]);
-
-    EXPECT_EQ(j["null"], json(nullptr));
-    EXPECT_EQ(j[json::object_t::key_type("null")], j["null"]);
-
-    EXPECT_EQ(j["string"], json("hello world"));
-    EXPECT_EQ(j[json::object_t::key_type("string")], j["string"]);
-
-    EXPECT_EQ(j["floating"], json(42.23));
-    EXPECT_EQ(j[json::object_t::key_type("floating")], j["floating"]);
-
-    EXPECT_EQ(j["object"], json::object());
-    EXPECT_EQ(j[json::object_t::key_type("object")], j["object"]);
-
-    EXPECT_EQ(j["array"], json({1, 2, 3}));
-    EXPECT_EQ(j[json::object_t::key_type("array")], j["array"]);
-
-    EXPECT_EQ(j_const["integer"], json(1));
-    EXPECT_EQ(j_const[json::object_t::key_type("integer")], j["integer"]);
-
-    EXPECT_EQ(j_const["boolean"], json(true));
-    EXPECT_EQ(j_const[json::object_t::key_type("boolean")], j["boolean"]);
-
-    EXPECT_EQ(j_const["null"], json(nullptr));
-    EXPECT_EQ(j_const[json::object_t::key_type("null")], j["null"]);
-
-    EXPECT_EQ(j_const["string"], json("hello world"));
-    EXPECT_EQ(j_const[json::object_t::key_type("string")], j["string"]);
-
-    EXPECT_EQ(j_const["floating"], json(42.23));
-    EXPECT_EQ(j_const[json::object_t::key_type("floating")], j["floating"]);
-
-    EXPECT_EQ(j_const["object"], json::object());
-    EXPECT_EQ(j_const[json::object_t::key_type("object")], j["object"]);
-
-    EXPECT_EQ(j_const["array"], json({1, 2, 3}));
-    EXPECT_EQ(j_const[json::object_t::key_type("array")], j["array"]);
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    json j_nonobject2(json::value_t::null);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_NO_THROW(j_nonobject["foo"]);
-    EXPECT_NO_THROW(j_nonobject2[json::object_t::key_type("foo")]);
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with null");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with null");
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with boolean");
-    EXPECT_THROW_MSG(j_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with boolean");
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with boolean");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with boolean");
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with string");
-    EXPECT_THROW_MSG(j_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with string");
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with string");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with string");
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, Array)
-{
-    json j_nonobject(json::value_t::array);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with array");
-    EXPECT_THROW_MSG(j_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with array");
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with array");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with array");
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, Unsigned)
-{
-    json j_nonobject(json::value_t::number_unsigned);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-}
-
-TEST(JsonElementNonObjectOperatorAccessTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    const json j_const_nonobject(j_nonobject);
-    EXPECT_THROW_MSG(j_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_const_nonobject["foo"], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-    EXPECT_THROW_MSG(j_const_nonobject[json::object_t::key_type("foo")], json::type_error,
-                     "[json.exception.type_error.305] cannot use operator[] with number");
-}
-
-class JsonElementObjectRemoveTest : public ::testing::Test,
-                                    public JsonElementObjectAccessTestBase {};
-
-TEST_F(JsonElementObjectRemoveTest, Key)
-{
-    EXPECT_NE(j.find("integer"), j.end());
-    EXPECT_EQ(j.erase("integer"), 1u);
-    EXPECT_EQ(j.find("integer"), j.end());
-    EXPECT_EQ(j.erase("integer"), 0u);
-
-    EXPECT_NE(j.find("unsigned"), j.end());
-    EXPECT_EQ(j.erase("unsigned"), 1u);
-    EXPECT_EQ(j.find("unsigned"), j.end());
-    EXPECT_EQ(j.erase("unsigned"), 0u);
-
-    EXPECT_NE(j.find("boolean"), j.end());
-    EXPECT_EQ(j.erase("boolean"), 1u);
-    EXPECT_EQ(j.find("boolean"), j.end());
-    EXPECT_EQ(j.erase("boolean"), 0u);
-
-    EXPECT_NE(j.find("null"), j.end());
-    EXPECT_EQ(j.erase("null"), 1u);
-    EXPECT_EQ(j.find("null"), j.end());
-    EXPECT_EQ(j.erase("null"), 0u);
-
-    EXPECT_NE(j.find("string"), j.end());
-    EXPECT_EQ(j.erase("string"), 1u);
-    EXPECT_EQ(j.find("string"), j.end());
-    EXPECT_EQ(j.erase("string"), 0u);
-
-    EXPECT_NE(j.find("floating"), j.end());
-    EXPECT_EQ(j.erase("floating"), 1u);
-    EXPECT_EQ(j.find("floating"), j.end());
-    EXPECT_EQ(j.erase("floating"), 0u);
-
-    EXPECT_NE(j.find("object"), j.end());
-    EXPECT_EQ(j.erase("object"), 1u);
-    EXPECT_EQ(j.find("object"), j.end());
-    EXPECT_EQ(j.erase("object"), 0u);
-
-    EXPECT_NE(j.find("array"), j.end());
-    EXPECT_EQ(j.erase("array"), 1u);
-    EXPECT_EQ(j.find("array"), j.end());
-    EXPECT_EQ(j.erase("array"), 0u);
-}
-
-// erase(begin())
-TEST_F(JsonElementObjectRemoveTest, Begin)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    jobject.erase(jobject.begin());
-    EXPECT_EQ(jobject, json({{"b", 1}, {"c", 17u}}));
-}
-
-TEST_F(JsonElementObjectRemoveTest, BeginConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    jobject.erase(jobject.cbegin());
-    EXPECT_EQ(jobject, json({{"b", 1}, {"c", 17u}}));
-}
-
-// erase(begin(), end())
-TEST_F(JsonElementObjectRemoveTest, BeginEnd)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json::iterator it2 = jobject.erase(jobject.begin(), jobject.end());
-    EXPECT_EQ(jobject, json::object());
-    EXPECT_EQ(it2, jobject.end());
-#else
-    EXPECT_THROW(jobject.erase(jobject.begin(), jobject.end()), json::type_error);
-#endif
-}
-
-TEST_F(JsonElementObjectRemoveTest, BeginEndConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cend());
-    EXPECT_EQ(jobject, json::object());
-    EXPECT_EQ(it2, jobject.cend());
-#else
-    EXPECT_THROW(jobject.erase(jobject.cbegin(), jobject.cend()), json::type_error);
-#endif
-}
-
-TEST_F(JsonElementObjectRemoveTest, BeginBegin)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json::iterator it2 = jobject.erase(jobject.begin(), jobject.begin());
-    EXPECT_EQ(jobject, json({{"a", "a"}, {"b", 1}, {"c", 17u}}));
-    EXPECT_EQ(*it2, json("a"));
-#else
-    EXPECT_THROW(jobject.erase(jobject.begin(), jobject.end()), json::type_error);
-#endif
-}
-
-TEST_F(JsonElementObjectRemoveTest, BeginBeginConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-#if 0
-    json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cbegin());
-    EXPECT_EQ(jobject, json({{"a", "a"}, {"b", 1}, {"c", 17u}}));
-    EXPECT_EQ(*it2, json("a"));
-#else
-    EXPECT_THROW(jobject.erase(jobject.cbegin(), jobject.cbegin()), json::type_error);
-#endif
-}
-
-TEST_F(JsonElementObjectRemoveTest, Offset)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    json::iterator it = jobject.find("b");
-    jobject.erase(it);
-    EXPECT_EQ(jobject, json({{"a", "a"}, {"c", 17u}}));
-}
-
-TEST_F(JsonElementObjectRemoveTest, OffsetConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    json::const_iterator it = jobject.find("b");
-    jobject.erase(it);
-    EXPECT_EQ(jobject, json({{"a", "a"}, {"c", 17u}}));
-}
-
-TEST_F(JsonElementObjectRemoveTest, Subrange)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-#if 0
-    json::iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e"));
-    EXPECT_EQ(jobject, json({{"a", "a"}, {"e", true}}));
-    EXPECT_EQ(*it2, json(true));
-#else
-    EXPECT_THROW(jobject.erase(jobject.find("b"), jobject.find("e")), json::type_error);
-#endif
-}
-
-TEST_F(JsonElementObjectRemoveTest, SubrangeConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-#if 0
-    json::const_iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e"));
-    EXPECT_EQ(jobject, json({{"a", "a"}, {"e", true}}));
-    EXPECT_EQ(*it2, json(true));
-#else
-    EXPECT_THROW(jobject.erase(jobject.find("b"), jobject.find("e")), json::type_error);
-#endif
-}
-
-TEST_F(JsonElementObjectRemoveTest, Different)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    EXPECT_THROW_MSG(jobject.erase(jobject2.begin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(jobject.erase(jobject.begin(), jobject2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(jobject.erase(jobject2.begin(), jobject.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(jobject.erase(jobject2.begin(), jobject2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-}
-
-TEST_F(JsonElementObjectRemoveTest, DifferentConst)
-{
-    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
-    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
-    EXPECT_THROW_MSG(jobject.erase(jobject2.cbegin()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(jobject.erase(jobject.cbegin(), jobject2.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(jobject.erase(jobject2.cbegin(), jobject.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-    EXPECT_THROW_MSG(jobject.erase(jobject2.cbegin(), jobject2.cend()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.203] iterators do not fit current value");
-}
-
-// remove element by key in non-object type
-TEST(JsonElementNonObjectKeyRemoveTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    EXPECT_THROW_MSG(j_nonobject.erase("foo"), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with null");
-}
-
-TEST(JsonElementNonObjectKeyRemoveTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    EXPECT_THROW_MSG(j_nonobject.erase("foo"), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with boolean");
-}
-
-TEST(JsonElementNonObjectKeyRemoveTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    EXPECT_THROW_MSG(j_nonobject.erase("foo"), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with string");
-}
-
-TEST(JsonElementNonObjectKeyRemoveTest, Array)
-{
-    json j_nonobject(json::value_t::array);
-    EXPECT_THROW_MSG(j_nonobject.erase("foo"), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with array");
-}
-
-TEST(JsonElementNonObjectKeyRemoveTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    EXPECT_THROW_MSG(j_nonobject.erase("foo"), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with number");
-}
-
-TEST(JsonElementNonObjectKeyRemoveTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    EXPECT_THROW_MSG(j_nonobject.erase("foo"), json::type_error,
-                     "[json.exception.type_error.307] cannot use erase() with number");
-}
-
-TEST_F(JsonElementObjectAccessTest, FindExist)
-{
-    for (auto key :
-            {"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
-            })
-    {
-        EXPECT_NE(j.find(key), j.end());
-        EXPECT_EQ(*j.find(key), j.at(key));
-        EXPECT_NE(j_const.find(key), j_const.end());
-        EXPECT_EQ(*j_const.find(key), j_const.at(key));
-    }
-}
-
-TEST_F(JsonElementObjectAccessTest, FindNotExist)
-{
-    EXPECT_EQ(j.find("foo"), j.end());
-    EXPECT_EQ(j_const.find("foo"), j_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Null)
-{
-    json j_nonarray(json::value_t::null);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, String)
-{
-    json j_nonarray(json::value_t::string);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Object)
-{
-    json j_nonarray(json::value_t::object);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Array)
-{
-    json j_nonarray(json::value_t::array);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Boolean)
-{
-    json j_nonarray(json::value_t::boolean);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Integer)
-{
-    json j_nonarray(json::value_t::number_integer);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Unsigned)
-{
-    json j_nonarray(json::value_t::number_unsigned);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST(JsonElementNonObjectFindAccessTest, Float)
-{
-    json j_nonarray(json::value_t::number_float);
-    const json j_nonarray_const(j_nonarray);
-    EXPECT_EQ(j_nonarray.find("foo"), j_nonarray.end());
-    EXPECT_EQ(j_nonarray_const.find("foo"), j_nonarray_const.end());
-}
-
-TEST_F(JsonElementObjectAccessTest, CountExist)
-{
-    for (auto key :
-            {"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
-            })
-    {
-        EXPECT_EQ(j.count(key), 1u);
-        EXPECT_EQ(j_const.count(key), 1u);
-    }
-}
-
-TEST_F(JsonElementObjectAccessTest, CountNotExist)
-{
-    EXPECT_EQ(j.count("foo"), 0u);
-    EXPECT_EQ(j_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Null)
-{
-    json j_nonobject(json::value_t::null);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, String)
-{
-    json j_nonobject(json::value_t::string);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Object)
-{
-    json j_nonobject(json::value_t::object);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Array)
-{
-    json j_nonobject(json::value_t::array);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Boolean)
-{
-    json j_nonobject(json::value_t::boolean);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Integer)
-{
-    json j_nonobject(json::value_t::number_integer);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Unsigned)
-{
-    json j_nonobject(json::value_t::number_unsigned);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST(JsonElementNonObjectCountAccessTest, Float)
-{
-    json j_nonobject(json::value_t::number_float);
-    const json j_nonobject_const(j_nonobject);
-    EXPECT_EQ(j_nonobject.count("foo"), 0u);
-    EXPECT_EQ(j_nonobject_const.count("foo"), 0u);
-}
-
-TEST_F(JsonElementObjectAccessTest, PointerValueNotExist)
-{
-    EXPECT_EQ(j.value("/not/existing"_json_pointer, 2), 2);
-    EXPECT_EQ(j.value("/not/existing"_json_pointer, 2u), 2u);
-    EXPECT_EQ(j.value("/not/existing"_json_pointer, false), false);
-    EXPECT_EQ(j.value("/not/existing"_json_pointer, "bar"), "bar");
-    EXPECT_LT(std::fabs(j.value("/not/existing"_json_pointer, 12.34) - 12.34), 0.001);
-    EXPECT_EQ(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})), json({{"foo", "bar"}}));
-    EXPECT_EQ(j.value("/not/existing"_json_pointer, json({10, 100})), json({10, 100}));
-
-    EXPECT_EQ(j_const.value("/not/existing"_json_pointer, 2), 2);
-    EXPECT_EQ(j_const.value("/not/existing"_json_pointer, 2u), 2u);
-    EXPECT_EQ(j_const.value("/not/existing"_json_pointer, false), false);
-    EXPECT_EQ(j_const.value("/not/existing"_json_pointer, "bar"), "bar");
-    EXPECT_LT(std::fabs(j_const.value("/not/existing"_json_pointer, 12.34) - 12.34), 0.001);
-    EXPECT_EQ(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})), json({{"foo", "bar"}}));
-    EXPECT_EQ(j_const.value("/not/existing"_json_pointer, json({10, 100})), json({10, 100}));
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-inspection.cpp b/wpiutil/src/test/native/cpp/json/unit-inspection.cpp
deleted file mode 100644
index 79c63f0..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-inspection.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonConvTypeCheckTest, Object)
-{
-    json j {{"foo", 1}, {"bar", false}};
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_FALSE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_TRUE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_FALSE(j.is_primitive());
-    EXPECT_TRUE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Array)
-{
-    json j {"foo", 1, 1u, 42.23, false};
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_FALSE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_TRUE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_FALSE(j.is_primitive());
-    EXPECT_TRUE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Null)
-{
-    json j(nullptr);
-    EXPECT_TRUE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_FALSE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_TRUE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Boolean)
-{
-    json j(true);
-    EXPECT_FALSE(j.is_null());
-    EXPECT_TRUE(j.is_boolean());
-    EXPECT_FALSE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_TRUE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, String)
-{
-    json j("Hello world");
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_FALSE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_TRUE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_TRUE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Integer)
-{
-    json j(42);
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_TRUE(j.is_number());
-    EXPECT_TRUE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_TRUE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Unsigned)
-{
-    json j(42u);
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_TRUE(j.is_number());
-    EXPECT_TRUE(j.is_number_integer());
-    EXPECT_TRUE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_TRUE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Float)
-{
-    json j(42.23);
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_TRUE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_TRUE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_FALSE(j.is_discarded());
-    EXPECT_TRUE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-TEST(JsonConvTypeCheckTest, Discarded)
-{
-    json j(json::value_t::discarded);
-    EXPECT_FALSE(j.is_null());
-    EXPECT_FALSE(j.is_boolean());
-    EXPECT_FALSE(j.is_number());
-    EXPECT_FALSE(j.is_number_integer());
-    EXPECT_FALSE(j.is_number_unsigned());
-    EXPECT_FALSE(j.is_number_float());
-    EXPECT_FALSE(j.is_object());
-    EXPECT_FALSE(j.is_array());
-    EXPECT_FALSE(j.is_string());
-    EXPECT_TRUE(j.is_discarded());
-    EXPECT_FALSE(j.is_primitive());
-    EXPECT_FALSE(j.is_structured());
-}
-
-class JsonConvSerializationTest : public ::testing::Test {
- protected:
-    json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
-};
-#if 0
-// no indent / indent=-1
-TEST_F(JsonConvSerializationTest, NoIndent)
-{
-    EXPECT_EQ(j.dump(),
-          "{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
-
-    EXPECT_EQ(j.dump(), j.dump(-1));
-}
-
-// indent=0
-TEST_F(JsonConvSerializationTest, Indent0)
-{
-    EXPECT_EQ(j.dump(0),
-          "{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
-}
-
-// indent=1, space='\t'
-TEST_F(JsonConvSerializationTest, Indent1)
-{
-    EXPECT_EQ(j.dump(1, '\t'),
-          "{\n\t\"array\": [\n\t\t1,\n\t\t2,\n\t\t3,\n\t\t4\n\t],\n\t\"boolean\": false,\n\t\"null\": null,\n\t\"number\": 42,\n\t\"object\": {},\n\t\"string\": \"Hello world\"\n}");
-}
-
-// indent=4
-TEST_F(JsonConvSerializationTest, Indent4)
-{
-    EXPECT_EQ(j.dump(4),
-          "{\n    \"array\": [\n        1,\n        2,\n        3,\n        4\n    ],\n    \"boolean\": false,\n    \"null\": null,\n    \"number\": 42,\n    \"object\": {},\n    \"string\": \"Hello world\"\n}");
-}
-#endif
-// indent=x
-TEST_F(JsonConvSerializationTest, IndentX)
-{
-    EXPECT_EQ(j.dump().size(), 94u);
-    EXPECT_EQ(j.dump(1).size(), 127u);
-    EXPECT_EQ(j.dump(2).size(), 142u);
-    EXPECT_EQ(j.dump(512).size(), 7792u);
-}
-
-// dump and floating-point numbers
-TEST_F(JsonConvSerializationTest, Float)
-{
-    auto s = json(42.23).dump();
-    EXPECT_NE(s.find("42.23"), std::string::npos);
-}
-
-// dump and small floating-point numbers
-TEST_F(JsonConvSerializationTest, SmallFloat)
-{
-    auto s = json(1.23456e-78).dump();
-    EXPECT_NE(s.find("1.23456e-78"), std::string::npos);
-}
-
-// dump and non-ASCII characters
-TEST_F(JsonConvSerializationTest, NonAscii)
-{
-    EXPECT_EQ(json("ä").dump(), "\"ä\"");
-    EXPECT_EQ(json("Ö").dump(), "\"Ö\"");
-    EXPECT_EQ(json("❤️").dump(), "\"❤️\"");
-}
-
-// serialization of discarded element
-TEST_F(JsonConvSerializationTest, Discarded)
-{
-    json j_discarded(json::value_t::discarded);
-    EXPECT_EQ(j_discarded.dump(), "<discarded>");
-}
-
-TEST(JsonConvRoundTripTest, Case)
-{
-    for (const auto& s :
-{"3.141592653589793", "1000000000000000010E5"
-})
-    {
-        SCOPED_TRACE(s);
-        json j1 = json::parse(s);
-        std::string s1 = j1.dump();
-        json j2 = json::parse(s1);
-        std::string s2 = j2.dump();
-        EXPECT_EQ(s1, s2);
-    }
-}
-
-// return the type of the object (explicit)
-TEST(JsonConvTypeExplicitTest, Null)
-{
-    json j = nullptr;
-    EXPECT_EQ(j.type(), json::value_t::null);
-}
-
-TEST(JsonConvTypeExplicitTest, Object)
-{
-    json j = {{"foo", "bar"}};
-    EXPECT_EQ(j.type(), json::value_t::object);
-}
-
-TEST(JsonConvTypeExplicitTest, Array)
-{
-    json j = {1, 2, 3, 4};
-    EXPECT_EQ(j.type(), json::value_t::array);
-}
-
-TEST(JsonConvTypeExplicitTest, Boolean)
-{
-    json j = true;
-    EXPECT_EQ(j.type(), json::value_t::boolean);
-}
-
-TEST(JsonConvTypeExplicitTest, String)
-{
-    json j = "Hello world";
-    EXPECT_EQ(j.type(), json::value_t::string);
-}
-
-TEST(JsonConvTypeExplicitTest, Integer)
-{
-    json j = 23;
-    EXPECT_EQ(j.type(), json::value_t::number_integer);
-}
-
-TEST(JsonConvTypeExplicitTest, Unsigned)
-{
-    json j = 23u;
-    EXPECT_EQ(j.type(), json::value_t::number_unsigned);
-}
-
-TEST(JsonConvTypeExplicitTest, Float)
-{
-    json j = 42.23;
-    EXPECT_EQ(j.type(), json::value_t::number_float);
-}
-
-// return the type of the object (implicit)
-TEST(JsonConvTypeImplicitTest, Null)
-{
-    json j = nullptr;
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, Object)
-{
-    json j = {{"foo", "bar"}};
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, Array)
-{
-    json j = {1, 2, 3, 4};
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, Boolean)
-{
-    json j = true;
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, String)
-{
-    json j = "Hello world";
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, Integer)
-{
-    json j = 23;
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, Unsigned)
-{
-    json j = 23u;
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
-
-TEST(JsonConvTypeImplicitTest, Float)
-{
-    json j = 42.23;
-    json::value_t t = j;
-    EXPECT_EQ(t, j.type());
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-iterators1.cpp b/wpiutil/src/test/native/cpp/json/unit-iterators1.cpp
deleted file mode 100644
index bae3862..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-iterators1.cpp
+++ /dev/null
@@ -1,1617 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-using wpi::JsonTest;
-
-TEST(JsonIteratorBasicTest, Uninitialized)
-{
-    json::iterator it;
-    EXPECT_EQ(JsonTest::GetObject(it), nullptr);
-
-    json::const_iterator cit;
-    EXPECT_EQ(JsonTest::GetObject(cit), nullptr);
-}
-
-class JsonIteratorBooleanTest : public ::testing::Test {
- public:
-    JsonIteratorBooleanTest() : j_const(j) {}
-
- protected:
-    json j = true;
-    json j_const;
-};
-
-TEST_F(JsonIteratorBooleanTest, BeginEnd)
-{
-    json::iterator it = j.begin();
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    it--;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    --it;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorBooleanTest, ConstBeginEnd)
-{
-    json::const_iterator it = j_const.begin();
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    it--;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    --it;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-}
-
-TEST_F(JsonIteratorBooleanTest, CBeginEnd)
-{
-    json::const_iterator it = j.cbegin();
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    it--;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    --it;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorBooleanTest, ConstCBeginEnd)
-{
-    json::const_iterator it = j_const.cbegin();
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    it--;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    --it;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-}
-#if 0
-TEST_F(JsonIteratorBooleanTest, RBeginEnd)
-{
-    json::reverse_iterator it = j.rbegin();
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    it--;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    --it;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorBooleanTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it = j.crbegin();
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    it--;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    --it;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorBooleanTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it = j_const.crbegin();
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    it--;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    --it;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-}
-#endif
-TEST_F(JsonIteratorBooleanTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(it.value(), json(true));
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(cit.value(), json(true));
-#if 0
-    auto rit = j.rend();
-    auto crit = j.crend();
-    EXPECT_THROW_MSG(rit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(rit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(crit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(crit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#endif
-}
-
-class JsonIteratorStringTest : public ::testing::Test {
- public:
-    JsonIteratorStringTest() : j_const(j) {}
-
- protected:
-    json j = "hello world";
-    json j_const;
-};
-
-TEST_F(JsonIteratorStringTest, BeginEnd)
-{
-    json::iterator it = j.begin();
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    it--;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    --it;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorStringTest, ConstBeginEnd)
-{
-    json::const_iterator it = j_const.begin();
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    it--;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    --it;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-}
-
-TEST_F(JsonIteratorStringTest, CBeginEnd)
-{
-    json::const_iterator it = j.cbegin();
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    it--;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    --it;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorStringTest, ConstCBeginEnd)
-{
-    json::const_iterator it = j_const.cbegin();
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    it--;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    --it;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-}
-#if 0
-TEST_F(JsonIteratorStringTest, RBeginEnd)
-{
-    json::reverse_iterator it = j.rbegin();
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    it--;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    --it;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorStringTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it = j.crbegin();
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    it--;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    --it;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorStringTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it = j_const.crbegin();
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    it--;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    --it;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-}
-#endif
-TEST_F(JsonIteratorStringTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(it.value(), json("hello world"));
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(cit.value(), json("hello world"));
-#if 0
-    auto rit = j.rend();
-    auto crit = j.crend();
-    EXPECT_THROW_MSG(rit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(rit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(crit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(crit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#endif
-}
-
-class JsonIteratorArrayTest : public ::testing::Test {
- public:
-    JsonIteratorArrayTest() : j_const(j) {}
-
- protected:
-    json j = {1, 2, 3};
-    json j_const;
-};
-
-TEST_F(JsonIteratorArrayTest, BeginEnd)
-{
-    json::iterator it_begin = j.begin();
-    json::iterator it_end = j.end();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[0]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[2]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorArrayTest, ConstBeginEnd)
-{
-    json::const_iterator it_begin = j_const.begin();
-    json::const_iterator it_end = j_const.end();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const[0]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const[2]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorArrayTest, CBeginEnd)
-{
-    json::const_iterator it_begin = j.cbegin();
-    json::const_iterator it_end = j.cend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[0]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[2]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorArrayTest, ConstCBeginEnd)
-{
-    json::const_iterator it_begin = j_const.cbegin();
-    json::const_iterator it_end = j_const.cend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[0]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[2]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-#if 0
-TEST_F(JsonIteratorArrayTest, RBeginEnd)
-{
-    json::reverse_iterator it_begin = j.rbegin();
-    json::reverse_iterator it_end = j.rend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[2]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[0]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorArrayTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it_begin = j.crbegin();
-    json::const_reverse_iterator it_end = j.crend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[2]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[0]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorArrayTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it_begin = j_const.crbegin();
-    json::const_reverse_iterator it_end = j_const.crend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[2]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[1]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j[0]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-#endif
-TEST_F(JsonIteratorArrayTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(it.value(), json(1));
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(cit.value(), json(1));
-}
-
-class JsonIteratorObjectTest : public ::testing::Test {
- public:
-    JsonIteratorObjectTest() : j_const(j) {}
-
- protected:
-    json j = {{"A", 1}, {"B", 2}, {"C", 3}};
-    json j_const;
-};
-
-TEST_F(JsonIteratorObjectTest, BeginEnd)
-{
-    json::iterator it_begin = j.begin();
-    json::iterator it_end = j.end();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["A"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["C"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorObjectTest, ConstBeginEnd)
-{
-    json::const_iterator it_begin = j_const.begin();
-    json::const_iterator it_end = j_const.end();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const["A"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const["C"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorObjectTest, CBeginEnd)
-{
-    json::const_iterator it_begin = j.cbegin();
-    json::const_iterator it_end = j.cend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["A"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["C"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorObjectTest, ConstCBeginEnd)
-{
-    json::const_iterator it_begin = j_const.cbegin();
-    json::const_iterator it_end = j_const.cend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const["A"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j_const["C"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-#if 0
-TEST_F(JsonIteratorObjectTest, RBeginEnd)
-{
-    json::reverse_iterator it_begin = j.rbegin();
-    json::reverse_iterator it_end = j.rend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["C"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["A"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorObjectTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it_begin = j.crbegin();
-    json::const_reverse_iterator it_end = j.crend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["C"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["A"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-
-TEST_F(JsonIteratorObjectTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it_begin = j_const.crbegin();
-    json::const_reverse_iterator it_end = j_const.crend();
-
-    auto it = it_begin;
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["C"]);
-
-    it++;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["B"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_NE(it, it_end);
-    EXPECT_EQ(*it, j["A"]);
-
-    ++it;
-    EXPECT_NE(it, it_begin);
-    EXPECT_EQ(it, it_end);
-}
-#endif
-
-TEST_F(JsonIteratorObjectTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_EQ(it.key(), "A");
-    EXPECT_EQ(it.value(), json(1));
-    EXPECT_EQ(cit.key(), "A");
-    EXPECT_EQ(cit.value(), json(1));
-}
-
-class JsonIteratorIntegerTest : public ::testing::Test {
- public:
-    JsonIteratorIntegerTest() : j_const(j) {}
-
- protected:
-    json j = 23;
-    json j_const;
-};
-
-TEST_F(JsonIteratorIntegerTest, BeginEnd)
-{
-    json::iterator it = j.begin();
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    it--;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    --it;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorIntegerTest, ConstBeginEnd)
-{
-    json::const_iterator it = j_const.begin();
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    it--;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    --it;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-}
-
-TEST_F(JsonIteratorIntegerTest, CBeginEnd)
-{
-    json::const_iterator it = j.cbegin();
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    it--;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    --it;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorIntegerTest, ConstCBeginEnd)
-{
-    json::const_iterator it = j_const.cbegin();
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    it--;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    --it;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-}
-#if 0
-TEST_F(JsonIteratorIntegerTest, RBeginEnd)
-{
-    json::reverse_iterator it = j.rbegin();
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    it--;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    --it;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorIntegerTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it = j.crbegin();
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    it--;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    --it;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorIntegerTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it = j_const.crbegin();
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    it--;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    --it;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-}
-#endif
-TEST_F(JsonIteratorIntegerTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(it.value(), json(23));
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(cit.value(), json(23));
-#if 0
-    auto rit = j.rend();
-    auto crit = j.crend();
-    EXPECT_THROW_MSG(rit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(rit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(crit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(crit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#endif
-}
-
-class JsonIteratorUnsignedTest : public ::testing::Test {
- public:
-    JsonIteratorUnsignedTest() : j_const(j) {}
-
- protected:
-    json j = 23u;
-    json j_const;
-};
-
-TEST_F(JsonIteratorUnsignedTest, BeginEnd)
-{
-    json::iterator it = j.begin();
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    it--;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    --it;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorUnsignedTest, ConstBeginEnd)
-{
-    json::const_iterator it = j_const.begin();
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    it--;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    --it;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-}
-
-TEST_F(JsonIteratorUnsignedTest, CBeginEnd)
-{
-    json::const_iterator it = j.cbegin();
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    it--;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    --it;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorUnsignedTest, ConstCBeginEnd)
-{
-    json::const_iterator it = j_const.cbegin();
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    it--;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    --it;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-}
-#if 0
-TEST_F(JsonIteratorUnsignedTest, RBeginEnd)
-{
-    json::reverse_iterator it = j.rbegin();
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    it--;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    --it;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorUnsignedTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it = j.crbegin();
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    it--;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    --it;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorUnsignedTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it = j_const.crbegin();
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    it--;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    --it;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-}
-#endif
-TEST_F(JsonIteratorUnsignedTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(it.value(), json(23));
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(cit.value(), json(23));
-#if 0
-    auto rit = j.rend();
-    auto crit = j.crend();
-    EXPECT_THROW_MSG(rit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(rit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(crit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(crit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#endif
-}
-
-class JsonIteratorFloatTest : public ::testing::Test {
- public:
-    JsonIteratorFloatTest() : j_const(j) {}
-
- protected:
-    json j = 23.42;
-    json j_const;
-};
-
-TEST_F(JsonIteratorFloatTest, BeginEnd)
-{
-    json::iterator it = j.begin();
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    it--;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.begin());
-    EXPECT_EQ(it, j.end());
-
-    --it;
-    EXPECT_EQ(it, j.begin());
-    EXPECT_NE(it, j.end());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorFloatTest, ConstBeginEnd)
-{
-    json::const_iterator it = j_const.begin();
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    it--;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.begin());
-    EXPECT_EQ(it, j_const.end());
-
-    --it;
-    EXPECT_EQ(it, j_const.begin());
-    EXPECT_NE(it, j_const.end());
-    EXPECT_EQ(*it, j_const);
-}
-
-TEST_F(JsonIteratorFloatTest, CBeginEnd)
-{
-    json::const_iterator it = j.cbegin();
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    it--;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.cbegin());
-    EXPECT_EQ(it, j.cend());
-
-    --it;
-    EXPECT_EQ(it, j.cbegin());
-    EXPECT_NE(it, j.cend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorFloatTest, ConstCBeginEnd)
-{
-    json::const_iterator it = j_const.cbegin();
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    it--;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.cbegin());
-    EXPECT_EQ(it, j_const.cend());
-
-    --it;
-    EXPECT_EQ(it, j_const.cbegin());
-    EXPECT_NE(it, j_const.cend());
-    EXPECT_EQ(*it, j_const);
-}
-#if 0
-TEST_F(JsonIteratorFloatTest, RBeginEnd)
-{
-    json::reverse_iterator it = j.rbegin();
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    it--;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.rbegin());
-    EXPECT_EQ(it, j.rend());
-
-    --it;
-    EXPECT_EQ(it, j.rbegin());
-    EXPECT_NE(it, j.rend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorFloatTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it = j.crbegin();
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    it++;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    it--;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-
-    ++it;
-    EXPECT_NE(it, j.crbegin());
-    EXPECT_EQ(it, j.crend());
-
-    --it;
-    EXPECT_EQ(it, j.crbegin());
-    EXPECT_NE(it, j.crend());
-    EXPECT_EQ(*it, j);
-}
-
-TEST_F(JsonIteratorFloatTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it = j_const.crbegin();
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    it++;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    it--;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-
-    ++it;
-    EXPECT_NE(it, j_const.crbegin());
-    EXPECT_EQ(it, j_const.crend());
-
-    --it;
-    EXPECT_EQ(it, j_const.crbegin());
-    EXPECT_NE(it, j_const.crend());
-    EXPECT_EQ(*it, j_const);
-}
-#endif
-TEST_F(JsonIteratorFloatTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(it.value(), json(23.42));
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_EQ(cit.value(), json(23.42));
-#if 0
-    auto rit = j.rend();
-    auto crit = j.crend();
-    EXPECT_THROW_MSG(rit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(rit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(crit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(crit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#endif
-}
-
-class JsonIteratorNullTest : public ::testing::Test {
- public:
-    JsonIteratorNullTest() : j_const(j) {}
-
- protected:
-    json j = nullptr;
-    json j_const;
-};
-
-TEST_F(JsonIteratorNullTest, BeginEnd)
-{
-    json::iterator it = j.begin();
-    EXPECT_EQ(it, j.end());
-}
-
-TEST_F(JsonIteratorNullTest, ConstBeginEnd)
-{
-    json::const_iterator it_begin = j_const.begin();
-    json::const_iterator it_end = j_const.end();
-    EXPECT_EQ(it_begin, it_end);
-}
-
-TEST_F(JsonIteratorNullTest, CBeginEnd)
-{
-    json::const_iterator it_begin = j.cbegin();
-    json::const_iterator it_end = j.cend();
-    EXPECT_EQ(it_begin, it_end);
-}
-
-TEST_F(JsonIteratorNullTest, ConstCBeginEnd)
-{
-    json::const_iterator it_begin = j_const.cbegin();
-    json::const_iterator it_end = j_const.cend();
-    EXPECT_EQ(it_begin, it_end);
-}
-#if 0
-TEST_F(JsonIteratorNullTest, RBeginEnd)
-{
-    json::reverse_iterator it = j.rbegin();
-    EXPECT_EQ(it, j.rend());
-}
-
-TEST_F(JsonIteratorNullTest, CRBeginEnd)
-{
-    json::const_reverse_iterator it = j.crbegin();
-    EXPECT_EQ(it, j.crend());
-}
-
-TEST_F(JsonIteratorNullTest, ConstCRBeginEnd)
-{
-    json::const_reverse_iterator it = j_const.crbegin();
-    EXPECT_EQ(it, j_const.crend());
-}
-#endif
-TEST_F(JsonIteratorNullTest, KeyValue)
-{
-    auto it = j.begin();
-    auto cit = j_const.cbegin();
-    EXPECT_THROW_MSG(it.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(it.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(cit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(cit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#if 0
-    auto rit = j.rend();
-    auto crit = j.crend();
-    EXPECT_THROW_MSG(rit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(rit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(crit.key(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.207] cannot use key() for non-object iterators");
-    EXPECT_THROW_MSG(crit.value(), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-#endif
-}
-
-TEST(JsonIteratorConstConversionTest, Boolean)
-{
-    json j = true;
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, String)
-{
-    json j = "hello world";
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, Array)
-{
-    json j = {1, 2, 3};
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, Object)
-{
-    json j = {{"A", 1}, {"B", 2}, {"C", 3}};
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, Integer)
-{
-    json j = 23;
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, Unsigned)
-{
-    json j = 23u;
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, Float)
-{
-    json j = 23.42;
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
-
-TEST(JsonIteratorConstConversionTest, Null)
-{
-    json j = nullptr;
-    json::const_iterator it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-    it = j.begin();
-    EXPECT_EQ(it, j.cbegin());
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-iterators2.cpp b/wpiutil/src/test/native/cpp/json/unit-iterators2.cpp
deleted file mode 100644
index 69a4dac..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-iterators2.cpp
+++ /dev/null
@@ -1,899 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonIteratorTest, Comparisons)
-{
-    json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
-
-    for (json& j : j_values)
-    {
-        SCOPED_TRACE(j.dump());
-        auto it1 = j.begin();
-        auto it2 = j.begin();
-        auto it3 = j.begin();
-        ++it2;
-        ++it3;
-        ++it3;
-        auto it1_c = j.cbegin();
-        auto it2_c = j.cbegin();
-        auto it3_c = j.cbegin();
-        ++it2_c;
-        ++it3_c;
-        ++it3_c;
-
-        // comparison: equal
-        {
-            EXPECT_TRUE(it1 == it1);
-            EXPECT_FALSE(it1 == it2);
-            EXPECT_FALSE(it1 == it3);
-            EXPECT_FALSE(it2 == it3);
-            EXPECT_TRUE(it1_c == it1_c);
-            EXPECT_FALSE(it1_c == it2_c);
-            EXPECT_FALSE(it1_c == it3_c);
-            EXPECT_FALSE(it2_c == it3_c);
-        }
-
-        // comparison: not equal
-        {
-            // check definition
-            EXPECT_EQ( (it1 != it1), !(it1 == it1) );
-            EXPECT_EQ( (it1 != it2), !(it1 == it2) );
-            EXPECT_EQ( (it1 != it3), !(it1 == it3) );
-            EXPECT_EQ( (it2 != it3), !(it2 == it3) );
-            EXPECT_EQ( (it1_c != it1_c), !(it1_c == it1_c) );
-            EXPECT_EQ( (it1_c != it2_c), !(it1_c == it2_c) );
-            EXPECT_EQ( (it1_c != it3_c), !(it1_c == it3_c) );
-            EXPECT_EQ( (it2_c != it3_c), !(it2_c == it3_c) );
-        }
-
-        // comparison: smaller
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 < it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 < it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 < it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 < it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c < it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c < it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c < it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c < it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                EXPECT_FALSE(it1 < it1);
-                EXPECT_TRUE(it1 < it2);
-                EXPECT_TRUE(it1 < it3);
-                EXPECT_TRUE(it2 < it3);
-                EXPECT_FALSE(it1_c < it1_c);
-                EXPECT_TRUE(it1_c < it2_c);
-                EXPECT_TRUE(it1_c < it3_c);
-                EXPECT_TRUE(it2_c < it3_c);
-            }
-        }
-
-        // comparison: less than or equal
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 <= it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 <= it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 <= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 <= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c <= it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c <= it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c <= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c <= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                // check definition
-                EXPECT_EQ( (it1 <= it1), !(it1 < it1) );
-                EXPECT_EQ( (it1 <= it2), !(it2 < it1) );
-                EXPECT_EQ( (it1 <= it3), !(it3 < it1) );
-                EXPECT_EQ( (it2 <= it3), !(it3 < it2) );
-                EXPECT_EQ( (it1_c <= it1_c), !(it1_c < it1_c) );
-                EXPECT_EQ( (it1_c <= it2_c), !(it2_c < it1_c) );
-                EXPECT_EQ( (it1_c <= it3_c), !(it3_c < it1_c) );
-                EXPECT_EQ( (it2_c <= it3_c), !(it3_c < it2_c) );
-            }
-        }
-
-        // comparison: greater than
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 > it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 > it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 > it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 > it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c > it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c > it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c > it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c > it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                // check definition
-                EXPECT_EQ( (it1 > it1), (it1 < it1) );
-                EXPECT_EQ( (it1 > it2), (it2 < it1) );
-                EXPECT_EQ( (it1 > it3), (it3 < it1) );
-                EXPECT_EQ( (it2 > it3), (it3 < it2) );
-                EXPECT_EQ( (it1_c > it1_c), (it1_c < it1_c) );
-                EXPECT_EQ( (it1_c > it2_c), (it2_c < it1_c) );
-                EXPECT_EQ( (it1_c > it3_c), (it3_c < it1_c) );
-                EXPECT_EQ( (it2_c > it3_c), (it3_c < it2_c) );
-            }
-        }
-
-        // comparison: greater than or equal
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 >= it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 >= it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 >= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 >= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c >= it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c >= it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c >= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c >= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                // check definition
-                EXPECT_EQ( (it1 >= it1), !(it1 < it1) );
-                EXPECT_EQ( (it1 >= it2), !(it1 < it2) );
-                EXPECT_EQ( (it1 >= it3), !(it1 < it3) );
-                EXPECT_EQ( (it2 >= it3), !(it2 < it3) );
-                EXPECT_EQ( (it1_c >= it1_c), !(it1_c < it1_c) );
-                EXPECT_EQ( (it1_c >= it2_c), !(it1_c < it2_c) );
-                EXPECT_EQ( (it1_c >= it3_c), !(it1_c < it3_c) );
-                EXPECT_EQ( (it2_c >= it3_c), !(it2_c < it3_c) );
-            }
-        }
-    }
-
-    // check exceptions if different objects are compared
-    for (auto j : j_values)
-    {
-        for (auto k : j_values)
-        {
-            if (j != k)
-            {
-                EXPECT_THROW_MSG(j.begin() == k.begin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-                EXPECT_THROW_MSG(j.cbegin() == k.cbegin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-
-                EXPECT_THROW_MSG(j.begin() < k.begin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-                EXPECT_THROW_MSG(j.cbegin() < k.cbegin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-            }
-        }
-    }
-}
-
-class JsonIteratorArithmeticTest : public ::testing::Test {
- protected:
-    json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
-    json j_array = {1, 2, 3, 4, 5, 6};
-    json j_null = nullptr;
-    json j_value = 42;
-};
-
-TEST_F(JsonIteratorArithmeticTest, AddSubObject)
-{
-    {
-        auto it = j_object.begin();
-        EXPECT_THROW_MSG(it += 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.cbegin();
-        EXPECT_THROW_MSG(it += 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.begin();
-        EXPECT_THROW_MSG(it + 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.cbegin();
-        EXPECT_THROW_MSG(it + 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.begin();
-        EXPECT_THROW_MSG(1 + it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.cbegin();
-        EXPECT_THROW_MSG(1 + it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.begin();
-        EXPECT_THROW_MSG(it -= 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.cbegin();
-        EXPECT_THROW_MSG(it -= 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.begin();
-        EXPECT_THROW_MSG(it - 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.cbegin();
-        EXPECT_THROW_MSG(it - 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.begin();
-        EXPECT_THROW_MSG(it - it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.cbegin();
-        EXPECT_THROW_MSG(it - it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-}
-
-TEST_F(JsonIteratorArithmeticTest, AddSubArray)
-{
-    auto it = j_array.begin();
-    it += 3;
-    EXPECT_EQ((j_array.begin() + 3), it);
-    EXPECT_EQ(json::iterator(3 + j_array.begin()), it);
-    EXPECT_EQ((it - 3), j_array.begin());
-    EXPECT_EQ((it - j_array.begin()), 3);
-    EXPECT_EQ(*it, json(4));
-    it -= 2;
-    EXPECT_EQ(*it, json(2));
-}
-
-TEST_F(JsonIteratorArithmeticTest, AddSubArrayConst)
-{
-    auto it = j_array.cbegin();
-    it += 3;
-    EXPECT_EQ((j_array.cbegin() + 3), it);
-    EXPECT_EQ(json::const_iterator(3 + j_array.cbegin()), it);
-    EXPECT_EQ((it - 3), j_array.cbegin());
-    EXPECT_EQ((it - j_array.cbegin()), 3);
-    EXPECT_EQ(*it, json(4));
-    it -= 2;
-    EXPECT_EQ(*it, json(2));
-}
-
-TEST_F(JsonIteratorArithmeticTest, AddSubNull)
-{
-    auto it = j_null.begin();
-    it += 3;
-    EXPECT_EQ((j_null.begin() + 3), it);
-    EXPECT_EQ(json::iterator(3 + j_null.begin()), it);
-    EXPECT_EQ((it - 3), j_null.begin());
-    EXPECT_EQ((it - j_null.begin()), 3);
-    EXPECT_NE(it, j_null.end());
-    it -= 3;
-    EXPECT_EQ(it, j_null.end());
-}
-
-TEST_F(JsonIteratorArithmeticTest, AddSubNullConst)
-{
-    auto it = j_null.cbegin();
-    it += 3;
-    EXPECT_EQ((j_null.cbegin() + 3), it);
-    EXPECT_EQ(json::const_iterator(3 + j_null.cbegin()), it);
-    EXPECT_EQ((it - 3), j_null.cbegin());
-    EXPECT_EQ((it - j_null.cbegin()), 3);
-    EXPECT_NE(it, j_null.cend());
-    it -= 3;
-    EXPECT_EQ(it, j_null.cend());
-}
-
-TEST_F(JsonIteratorArithmeticTest, AddSubValue)
-{
-    auto it = j_value.begin();
-    it += 3;
-    EXPECT_EQ((j_value.begin() + 3), it);
-    EXPECT_EQ(json::iterator(3 + j_value.begin()), it);
-    EXPECT_EQ((it - 3), j_value.begin());
-    EXPECT_EQ((it - j_value.begin()), 3);
-    EXPECT_NE(it, j_value.end());
-    it -= 3;
-    EXPECT_EQ(*it, json(42));
-}
-
-TEST_F(JsonIteratorArithmeticTest, AddSubValueConst)
-{
-    auto it = j_value.cbegin();
-    it += 3;
-    EXPECT_EQ((j_value.cbegin() + 3), it);
-    EXPECT_EQ(json::const_iterator(3 + j_value.cbegin()), it);
-    EXPECT_EQ((it - 3), j_value.cbegin());
-    EXPECT_EQ((it - j_value.cbegin()), 3);
-    EXPECT_NE(it, j_value.cend());
-    it -= 3;
-    EXPECT_EQ(*it, json(42));
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptObject)
-{
-    auto it = j_object.begin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators");
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptObjectConst)
-{
-    auto it = j_object.cbegin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators");
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptArray)
-{
-    auto it = j_array.begin();
-    EXPECT_EQ(it[0], json(1));
-    EXPECT_EQ(it[1], json(2));
-    EXPECT_EQ(it[2], json(3));
-    EXPECT_EQ(it[3], json(4));
-    EXPECT_EQ(it[4], json(5));
-    EXPECT_EQ(it[5], json(6));
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptArrayConst)
-{
-    auto it = j_array.cbegin();
-    EXPECT_EQ(it[0], json(1));
-    EXPECT_EQ(it[1], json(2));
-    EXPECT_EQ(it[2], json(3));
-    EXPECT_EQ(it[3], json(4));
-    EXPECT_EQ(it[4], json(5));
-    EXPECT_EQ(it[5], json(6));
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptNull)
-{
-    auto it = j_null.begin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptNullConst)
-{
-    auto it = j_null.cbegin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptValue)
-{
-    auto it = j_value.begin();
-    EXPECT_EQ(it[0], json(42));
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST_F(JsonIteratorArithmeticTest, SubscriptValueConst)
-{
-    auto it = j_value.cbegin();
-    EXPECT_EQ(it[0], json(42));
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-#if 0
-TEST(JsonReverseIteratorTest, Comparisons)
-{
-    json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
-
-    for (json& j : j_values)
-    {
-        SCOPED_TRACE(j.dump());
-        auto it1 = j.rbegin();
-        auto it2 = j.rbegin();
-        auto it3 = j.rbegin();
-        ++it2;
-        ++it3;
-        ++it3;
-        auto it1_c = j.crbegin();
-        auto it2_c = j.crbegin();
-        auto it3_c = j.crbegin();
-        ++it2_c;
-        ++it3_c;
-        ++it3_c;
-
-        // comparison: equal
-        {
-            EXPECT_TRUE(it1 == it1);
-            EXPECT_FALSE(it1 == it2);
-            EXPECT_FALSE(it1 == it3);
-            EXPECT_FALSE(it2 == it3);
-            EXPECT_TRUE(it1_c == it1_c);
-            EXPECT_FALSE(it1_c == it2_c);
-            EXPECT_FALSE(it1_c == it3_c);
-            EXPECT_FALSE(it2_c == it3_c);
-        }
-
-        // comparison: not equal
-        {
-            // check definition
-            EXPECT_EQ( (it1 != it1), !(it1 == it1) );
-            EXPECT_EQ( (it1 != it2), !(it1 == it2) );
-            EXPECT_EQ( (it1 != it3), !(it1 == it3) );
-            EXPECT_EQ( (it2 != it3), !(it2 == it3) );
-            EXPECT_EQ( (it1_c != it1_c), !(it1_c == it1_c) );
-            EXPECT_EQ( (it1_c != it2_c), !(it1_c == it2_c) );
-            EXPECT_EQ( (it1_c != it3_c), !(it1_c == it3_c) );
-            EXPECT_EQ( (it2_c != it3_c), !(it2_c == it3_c) );
-        }
-
-        // comparison: smaller
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 < it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 < it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 < it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 < it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c < it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c < it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c < it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c < it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                EXPECT_FALSE(it1 < it1);
-                EXPECT_TRUE(it1 < it2);
-                EXPECT_TRUE(it1 < it3);
-                EXPECT_TRUE(it2 < it3);
-                EXPECT_FALSE(it1_c < it1_c);
-                EXPECT_TRUE(it1_c < it2_c);
-                EXPECT_TRUE(it1_c < it3_c);
-                EXPECT_TRUE(it2_c < it3_c);
-            }
-        }
-
-        // comparison: less than or equal
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 <= it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 <= it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 <= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 <= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c <= it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c <= it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c <= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c <= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                // check definition
-                EXPECT_EQ( (it1 <= it1), !(it1 < it1) );
-                EXPECT_EQ( (it1 <= it2), !(it2 < it1) );
-                EXPECT_EQ( (it1 <= it3), !(it3 < it1) );
-                EXPECT_EQ( (it2 <= it3), !(it3 < it2) );
-                EXPECT_EQ( (it1_c <= it1_c), !(it1_c < it1_c) );
-                EXPECT_EQ( (it1_c <= it2_c), !(it2_c < it1_c) );
-                EXPECT_EQ( (it1_c <= it3_c), !(it3_c < it1_c) );
-                EXPECT_EQ( (it2_c <= it3_c), !(it3_c < it2_c) );
-            }
-        }
-
-        // comparison: greater than
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 > it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 > it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 > it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 > it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c > it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c > it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c > it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c > it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                // check definition
-                EXPECT_EQ( (it1 > it1), (it1 < it1) );
-                EXPECT_EQ( (it1 > it2), (it2 < it1) );
-                EXPECT_EQ( (it1 > it3), (it3 < it1) );
-                EXPECT_EQ( (it2 > it3), (it3 < it2) );
-                EXPECT_EQ( (it1_c > it1_c), (it1_c < it1_c) );
-                EXPECT_EQ( (it1_c > it2_c), (it2_c < it1_c) );
-                EXPECT_EQ( (it1_c > it3_c), (it3_c < it1_c) );
-                EXPECT_EQ( (it2_c > it3_c), (it3_c < it2_c) );
-            }
-        }
-
-        // comparison: greater than or equal
-        {
-            if (j.type() == json::value_t::object)
-            {
-                EXPECT_THROW_MSG(it1 >= it1, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 >= it2, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2 >= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1 >= it3, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c >= it1_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c >= it2_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it2_c >= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-                EXPECT_THROW_MSG(it1_c >= it3_c, json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.213] cannot compare order of object iterators");
-            }
-            else
-            {
-                // check definition
-                EXPECT_EQ( (it1 >= it1), !(it1 < it1) );
-                EXPECT_EQ( (it1 >= it2), !(it1 < it2) );
-                EXPECT_EQ( (it1 >= it3), !(it1 < it3) );
-                EXPECT_EQ( (it2 >= it3), !(it2 < it3) );
-                EXPECT_EQ( (it1_c >= it1_c), !(it1_c < it1_c) );
-                EXPECT_EQ( (it1_c >= it2_c), !(it1_c < it2_c) );
-                EXPECT_EQ( (it1_c >= it3_c), !(it1_c < it3_c) );
-                EXPECT_EQ( (it2_c >= it3_c), !(it2_c < it3_c) );
-            }
-        }
-    }
-
-    // check exceptions if different objects are compared
-    for (auto j : j_values)
-    {
-        for (auto k : j_values)
-        {
-            if (j != k)
-            {
-                EXPECT_THROW_MSG(j.rbegin() == k.rbegin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-                EXPECT_THROW_MSG(j.crbegin() == k.crbegin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-
-                EXPECT_THROW_MSG(j.rbegin() < k.rbegin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-                EXPECT_THROW_MSG(j.crbegin() < k.crbegin(), json::invalid_iterator,
-                                 "[json.exception.invalid_iterator.212] cannot compare iterators of different containers");
-            }
-        }
-    }
-}
-
-class JsonReverseIteratorArithmeticTest : public ::testing::Test {
- protected:
-    json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
-    json j_array = {1, 2, 3, 4, 5, 6};
-    json j_null = nullptr;
-    json j_value = 42;
-};
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubObject)
-{
-    {
-        auto it = j_object.rbegin();
-        EXPECT_THROW_MSG(it += 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.crbegin();
-        EXPECT_THROW_MSG(it += 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.rbegin();
-        EXPECT_THROW_MSG(it + 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.crbegin();
-        EXPECT_THROW_MSG(it + 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.rbegin();
-        EXPECT_THROW_MSG(1 + it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.crbegin();
-        EXPECT_THROW_MSG(1 + it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.rbegin();
-        EXPECT_THROW_MSG(it -= 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.crbegin();
-        EXPECT_THROW_MSG(it -= 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.rbegin();
-        EXPECT_THROW_MSG(it - 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.crbegin();
-        EXPECT_THROW_MSG(it - 1, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.rbegin();
-        EXPECT_THROW_MSG(it - it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-    {
-        auto it = j_object.crbegin();
-        EXPECT_THROW_MSG(it - it, json::invalid_iterator,
-                         "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    }
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubArray)
-{
-    auto it = j_array.rbegin();
-    it += 3;
-    EXPECT_EQ((j_array.rbegin() + 3), it);
-    EXPECT_EQ(json::reverse_iterator(3 + j_array.rbegin()), it);
-    EXPECT_EQ((it - 3), j_array.rbegin());
-    EXPECT_EQ((it - j_array.rbegin()), 3);
-    EXPECT_EQ(*it, json(3));
-    it -= 2;
-    EXPECT_EQ(*it, json(5));
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubArrayConst)
-{
-    auto it = j_array.crbegin();
-    it += 3;
-    EXPECT_EQ((j_array.crbegin() + 3), it);
-    EXPECT_EQ(json::const_reverse_iterator(3 + j_array.crbegin()), it);
-    EXPECT_EQ((it - 3), j_array.crbegin());
-    EXPECT_EQ((it - j_array.crbegin()), 3);
-    EXPECT_EQ(*it, json(3));
-    it -= 2;
-    EXPECT_EQ(*it, json(5));
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubNull)
-{
-    auto it = j_null.rbegin();
-    it += 3;
-    EXPECT_EQ((j_null.rbegin() + 3), it);
-    EXPECT_EQ(json::reverse_iterator(3 + j_null.rbegin()), it);
-    EXPECT_EQ((it - 3), j_null.rbegin());
-    EXPECT_EQ((it - j_null.rbegin()), 3);
-    EXPECT_NE(it, j_null.rend());
-    it -= 3;
-    EXPECT_EQ(it, j_null.rend());
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubNullConst)
-{
-    auto it = j_null.crbegin();
-    it += 3;
-    EXPECT_EQ((j_null.crbegin() + 3), it);
-    EXPECT_EQ(json::const_reverse_iterator(3 + j_null.crbegin()), it);
-    EXPECT_EQ((it - 3), j_null.crbegin());
-    EXPECT_EQ((it - j_null.crbegin()), 3);
-    EXPECT_NE(it, j_null.crend());
-    it -= 3;
-    EXPECT_EQ(it, j_null.crend());
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubValue)
-{
-    auto it = j_value.rbegin();
-    it += 3;
-    EXPECT_EQ((j_value.rbegin() + 3), it);
-    EXPECT_EQ(json::reverse_iterator(3 + j_value.rbegin()), it);
-    EXPECT_EQ((it - 3), j_value.rbegin());
-    EXPECT_EQ((it - j_value.rbegin()), 3);
-    EXPECT_NE(it, j_value.rend());
-    it -= 3;
-    EXPECT_EQ(*it, json(42));
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, AddSubValueConst)
-{
-    auto it = j_value.crbegin();
-    it += 3;
-    EXPECT_EQ((j_value.crbegin() + 3), it);
-    EXPECT_EQ(json::const_reverse_iterator(3 + j_value.crbegin()), it);
-    EXPECT_EQ((it - 3), j_value.crbegin());
-    EXPECT_EQ((it - j_value.crbegin()), 3);
-    EXPECT_NE(it, j_value.crend());
-    it -= 3;
-    EXPECT_EQ(*it, json(42));
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptObject)
-{
-    auto it = j_object.rbegin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptObjectConst)
-{
-    auto it = j_object.crbegin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptArray)
-{
-    auto it = j_array.rbegin();
-    EXPECT_EQ(it[0], json(6));
-    EXPECT_EQ(it[1], json(5));
-    EXPECT_EQ(it[2], json(4));
-    EXPECT_EQ(it[3], json(3));
-    EXPECT_EQ(it[4], json(2));
-    EXPECT_EQ(it[5], json(1));
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptArrayConst)
-{
-    auto it = j_array.crbegin();
-    EXPECT_EQ(it[0], json(6));
-    EXPECT_EQ(it[1], json(5));
-    EXPECT_EQ(it[2], json(4));
-    EXPECT_EQ(it[3], json(3));
-    EXPECT_EQ(it[4], json(2));
-    EXPECT_EQ(it[5], json(1));
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptNull)
-{
-    auto it = j_null.rbegin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptNullConst)
-{
-    auto it = j_null.crbegin();
-    EXPECT_THROW_MSG(it[0], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptValue)
-{
-    auto it = j_value.rbegin();
-    EXPECT_EQ(it[0], json(42));
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-
-TEST_F(JsonReverseIteratorArithmeticTest, SubscriptValueConst)
-{
-    auto it = j_value.crbegin();
-    EXPECT_EQ(it[0], json(42));
-    EXPECT_THROW_MSG(it[1], json::invalid_iterator,
-                     "[json.exception.invalid_iterator.214] cannot get value");
-}
-#endif
diff --git a/wpiutil/src/test/native/cpp/json/unit-json.h b/wpiutil/src/test/native/cpp/json/unit-json.h
deleted file mode 100644
index 5a764b7..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-json.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) FIRST 2017. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/#ifndef UNIT_JSON_H_
-#define UNIT_JSON_H_
-
-#include <ostream>
-
-#include "wpi/json.h"
-
-namespace wpi {
-
-inline
-void PrintTo(const json& j, std::ostream* os) {
-  *os << j.dump();
-}
-
-class JsonTest {
- public:
-  static const json::json_value& GetValue(const json& j) {
-    return j.m_value;
-  }
-  static json::pointer GetObject(json::iterator it) {
-    return it.m_object;
-  }
-  static json::const_pointer GetObject(json::const_iterator it) {
-    return it.m_object;
-  }
-  static std::string pop_back(json::json_pointer& p) {
-    return p.pop_back();
-  }
-  static json::json_pointer top(const json::json_pointer& p) {
-    return p.top();
-  }
-};
-
-}  // namespace wpi
-
-// clang warns on TEST_THROW_MSG(x == y, ...) saying the result is unused.
-// suppress this warning.
-#if defined(__clang__)
-#pragma GCC diagnostic ignored "-Wunused-comparison"
-#endif
-
-// variant of GTEST_TEST_THROW_ that also checks the exception's message.
-#define TEST_THROW_MSG(statement, expected_exception, expected_msg, fail) \
-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
-  if (::testing::internal::ConstCharPtr gtest_msg = "") { \
-    bool gtest_caught_expected = false; \
-    try { \
-      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
-    } \
-    catch (expected_exception const& gtest_ex) { \
-      gtest_caught_expected = true; \
-      if (::std::string(gtest_ex.what()) != expected_msg) { \
-        ::testing::AssertionResult gtest_ar = ::testing::AssertionFailure(); \
-        gtest_ar \
-            << "Expected: " #statement " throws an exception with message \"" \
-            << expected_msg "\".\n  Actual: it throws message \"" \
-            << gtest_ex.what() << "\"."; \
-        fail(gtest_ar.failure_message()); \
-      } \
-    } \
-    catch (...) { \
-      gtest_msg.value = \
-          "Expected: " #statement " throws an exception of type " \
-          #expected_exception ".\n  Actual: it throws a different type."; \
-      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
-    } \
-    if (!gtest_caught_expected) { \
-      gtest_msg.value = \
-          "Expected: " #statement " throws an exception of type " \
-          #expected_exception ".\n  Actual: it throws nothing."; \
-      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
-    } \
-  } else \
-    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
-      fail(gtest_msg.value)
-
-#define EXPECT_THROW_MSG(statement, expected_exception, expected_msg) \
-  TEST_THROW_MSG(statement, expected_exception, expected_msg, GTEST_NONFATAL_FAILURE_)
-
-#define ASSERT_THROW_MSG(statement, expected_exception, expected_msg) \
-  TEST_THROW_MSG(statement, expected_exception, expected_msg, GTEST_FATAL_FAILURE_)
-
-#endif
diff --git a/wpiutil/src/test/native/cpp/json/unit-json_pointer.cpp b/wpiutil/src/test/native/cpp/json/unit-json_pointer.cpp
deleted file mode 100644
index d54fd6a..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-json_pointer.cpp
+++ /dev/null
@@ -1,402 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) FIRST 2017. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-using wpi::JsonTest;
-
-TEST(JsonPointerTest, Errors)
-{
-    EXPECT_THROW_MSG(json::json_pointer("foo"), json::parse_error,
-                     "[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo'");
-
-    EXPECT_THROW_MSG(json::json_pointer("/~~"), json::parse_error,
-                     "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'");
-
-    EXPECT_THROW_MSG(json::json_pointer("/~"), json::parse_error,
-                     "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'");
-
-    json::json_pointer p;
-    EXPECT_THROW_MSG(JsonTest::top(p), json::out_of_range,
-                     "[json.exception.out_of_range.405] JSON pointer has no parent");
-    EXPECT_THROW_MSG(JsonTest::pop_back(p), json::out_of_range,
-                     "[json.exception.out_of_range.405] JSON pointer has no parent");
-}
-
-// examples from RFC 6901
-TEST(JsonPointerTest, AccessNonConst)
-{
-    json j = R"(
-    {
-        "foo": ["bar", "baz"],
-        "": 0,
-        "a/b": 1,
-        "c%d": 2,
-        "e^f": 3,
-        "g|h": 4,
-        "i\\j": 5,
-        "k\"l": 6,
-        " ": 7,
-        "m~n": 8
-    }
-    )"_json;
-
-    // the whole document
-    EXPECT_EQ(j[json::json_pointer()], j);
-    EXPECT_EQ(j[json::json_pointer("")], j);
-
-    // array access
-    EXPECT_EQ(j[json::json_pointer("/foo")], j["foo"]);
-    EXPECT_EQ(j[json::json_pointer("/foo/0")], j["foo"][0]);
-    EXPECT_EQ(j[json::json_pointer("/foo/1")], j["foo"][1]);
-    EXPECT_EQ(j["/foo/1"_json_pointer], j["foo"][1]);
-
-    // checked array access
-    EXPECT_EQ(j.at(json::json_pointer("/foo/0")), j["foo"][0]);
-    EXPECT_EQ(j.at(json::json_pointer("/foo/1")), j["foo"][1]);
-
-    // empty string access
-    EXPECT_EQ(j[json::json_pointer("/")], j[""]);
-
-    // other cases
-    EXPECT_EQ(j[json::json_pointer("/ ")], j[" "]);
-    EXPECT_EQ(j[json::json_pointer("/c%d")], j["c%d"]);
-    EXPECT_EQ(j[json::json_pointer("/e^f")], j["e^f"]);
-    EXPECT_EQ(j[json::json_pointer("/g|h")], j["g|h"]);
-    EXPECT_EQ(j[json::json_pointer("/i\\j")], j["i\\j"]);
-    EXPECT_EQ(j[json::json_pointer("/k\"l")], j["k\"l"]);
-
-    // checked access
-    EXPECT_EQ(j.at(json::json_pointer("/ ")), j[" "]);
-    EXPECT_EQ(j.at(json::json_pointer("/c%d")), j["c%d"]);
-    EXPECT_EQ(j.at(json::json_pointer("/e^f")), j["e^f"]);
-    EXPECT_EQ(j.at(json::json_pointer("/g|h")), j["g|h"]);
-    EXPECT_EQ(j.at(json::json_pointer("/i\\j")), j["i\\j"]);
-    EXPECT_EQ(j.at(json::json_pointer("/k\"l")), j["k\"l"]);
-
-    // escaped access
-    EXPECT_EQ(j[json::json_pointer("/a~1b")], j["a/b"]);
-    EXPECT_EQ(j[json::json_pointer("/m~0n")], j["m~n"]);
-
-    // unescaped access
-    // access to nonexisting values yield object creation
-    EXPECT_NO_THROW(j[json::json_pointer("/a/b")] = 42);
-    EXPECT_EQ(j["a"]["b"], json(42));
-    EXPECT_NO_THROW(j[json::json_pointer("/a/c/1")] = 42);
-    EXPECT_EQ(j["a"]["c"], json({nullptr, 42}));
-    EXPECT_NO_THROW(j[json::json_pointer("/a/d/-")] = 42);
-    EXPECT_EQ(j["a"]["d"], json::array({42}));
-    // "/a/b" works for JSON {"a": {"b": 42}}
-    EXPECT_EQ(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")], json(42));
-
-    // unresolved access
-    json j_primitive = 1;
-    EXPECT_THROW_MSG(j_primitive["/foo"_json_pointer], json::out_of_range,
-                     "[json.exception.out_of_range.404] unresolved reference token 'foo'");
-    EXPECT_THROW_MSG(j_primitive.at("/foo"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.404] unresolved reference token 'foo'");
-}
-
-TEST(JsonPointerTest, AccessConst)
-{
-    const json j = R"(
-    {
-        "foo": ["bar", "baz"],
-        "": 0,
-        "a/b": 1,
-        "c%d": 2,
-        "e^f": 3,
-        "g|h": 4,
-        "i\\j": 5,
-        "k\"l": 6,
-        " ": 7,
-        "m~n": 8
-    }
-    )"_json;
-
-    // the whole document
-    EXPECT_EQ(j[json::json_pointer()], j);
-    EXPECT_EQ(j[json::json_pointer("")], j);
-
-    // array access
-    EXPECT_EQ(j[json::json_pointer("/foo")], j["foo"]);
-    EXPECT_EQ(j[json::json_pointer("/foo/0")], j["foo"][0]);
-    EXPECT_EQ(j[json::json_pointer("/foo/1")], j["foo"][1]);
-    EXPECT_EQ(j["/foo/1"_json_pointer], j["foo"][1]);
-
-    // checked array access
-    EXPECT_EQ(j.at(json::json_pointer("/foo/0")), j["foo"][0]);
-    EXPECT_EQ(j.at(json::json_pointer("/foo/1")), j["foo"][1]);
-
-    // empty string access
-    EXPECT_EQ(j[json::json_pointer("/")], j[""]);
-
-    // other cases
-    EXPECT_EQ(j[json::json_pointer("/ ")], j[" "]);
-    EXPECT_EQ(j[json::json_pointer("/c%d")], j["c%d"]);
-    EXPECT_EQ(j[json::json_pointer("/e^f")], j["e^f"]);
-    EXPECT_EQ(j[json::json_pointer("/g|h")], j["g|h"]);
-    EXPECT_EQ(j[json::json_pointer("/i\\j")], j["i\\j"]);
-    EXPECT_EQ(j[json::json_pointer("/k\"l")], j["k\"l"]);
-
-    // checked access
-    EXPECT_EQ(j.at(json::json_pointer("/ ")), j[" "]);
-    EXPECT_EQ(j.at(json::json_pointer("/c%d")), j["c%d"]);
-    EXPECT_EQ(j.at(json::json_pointer("/e^f")), j["e^f"]);
-    EXPECT_EQ(j.at(json::json_pointer("/g|h")), j["g|h"]);
-    EXPECT_EQ(j.at(json::json_pointer("/i\\j")), j["i\\j"]);
-    EXPECT_EQ(j.at(json::json_pointer("/k\"l")), j["k\"l"]);
-
-    // escaped access
-    EXPECT_EQ(j[json::json_pointer("/a~1b")], j["a/b"]);
-    EXPECT_EQ(j[json::json_pointer("/m~0n")], j["m~n"]);
-
-    // unescaped access
-    EXPECT_THROW_MSG(j.at(json::json_pointer("/a/b")), json::out_of_range,
-                     "[json.exception.out_of_range.403] key 'a' not found");
-
-    // unresolved access
-    const json j_primitive = 1;
-    EXPECT_THROW_MSG(j_primitive["/foo"_json_pointer], json::out_of_range,
-                     "[json.exception.out_of_range.404] unresolved reference token 'foo'");
-    EXPECT_THROW_MSG(j_primitive.at("/foo"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.404] unresolved reference token 'foo'");
-}
-
-TEST(JsonPointerTest, UserStringLiteral)
-{
-    json j = R"(
-    {
-        "foo": ["bar", "baz"],
-        "": 0,
-        "a/b": 1,
-        "c%d": 2,
-        "e^f": 3,
-        "g|h": 4,
-        "i\\j": 5,
-        "k\"l": 6,
-        " ": 7,
-        "m~n": 8
-    }
-    )"_json;
-
-    // the whole document
-    EXPECT_EQ(j[""_json_pointer], j);
-
-    // array access
-    EXPECT_EQ(j["/foo"_json_pointer], j["foo"]);
-    EXPECT_EQ(j["/foo/0"_json_pointer], j["foo"][0]);
-    EXPECT_EQ(j["/foo/1"_json_pointer], j["foo"][1]);
-}
-
-TEST(JsonPointerTest, ArrayNonConst)
-{
-    json j = {1, 2, 3};
-    const json j_const = j;
-
-    // check reading access
-    EXPECT_EQ(j["/0"_json_pointer], j[0]);
-    EXPECT_EQ(j["/1"_json_pointer], j[1]);
-    EXPECT_EQ(j["/2"_json_pointer], j[2]);
-
-    // assign to existing index
-    j["/1"_json_pointer] = 13;
-    EXPECT_EQ(j[1], json(13));
-
-    // assign to nonexisting index
-    j["/3"_json_pointer] = 33;
-    EXPECT_EQ(j[3], json(33));
-
-    // assign to nonexisting index (with gap)
-    j["/5"_json_pointer] = 55;
-    EXPECT_EQ(j, json({1, 13, 3, 33, nullptr, 55}));
-
-    // error with leading 0
-    EXPECT_THROW_MSG(j["/01"_json_pointer], json::parse_error,
-                     "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
-    EXPECT_THROW_MSG(j_const["/01"_json_pointer], json::parse_error,
-                     "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
-    EXPECT_THROW_MSG(j.at("/01"_json_pointer), json::parse_error,
-                     "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
-    EXPECT_THROW_MSG(j_const.at("/01"_json_pointer), json::parse_error,
-                     "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
-
-    // error with incorrect numbers
-    EXPECT_THROW_MSG(j["/one"_json_pointer] = 1, json::parse_error,
-                     "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
-    EXPECT_THROW_MSG(j_const["/one"_json_pointer] == 1, json::parse_error,
-                     "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
-
-    EXPECT_THROW_MSG(j.at("/one"_json_pointer) = 1, json::parse_error,
-                     "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
-    EXPECT_THROW_MSG(j_const.at("/one"_json_pointer) == 1, json::parse_error,
-                     "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
-
-    EXPECT_THROW_MSG(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error,
-                     "[json.exception.parse_error.109] parse error: array index 'three' is not a number");
-
-    // assign to "-"
-    j["/-"_json_pointer] = 99;
-    EXPECT_EQ(j, json({1, 13, 3, 33, nullptr, 55, 99}));
-
-    // error when using "-" in const object
-    EXPECT_THROW_MSG(j_const["/-"_json_pointer], json::out_of_range,
-                     "[json.exception.out_of_range.402] array index '-' (3) is out of range");
-
-    // error when using "-" with at
-    EXPECT_THROW_MSG(j.at("/-"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.402] array index '-' (7) is out of range");
-    EXPECT_THROW_MSG(j_const.at("/-"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.402] array index '-' (3) is out of range");
-}
-
-TEST(JsonPointerTest, ArrayConst)
-{
-    const json j = {1, 2, 3};
-
-    // check reading access
-    EXPECT_EQ(j["/0"_json_pointer], j[0]);
-    EXPECT_EQ(j["/1"_json_pointer], j[1]);
-    EXPECT_EQ(j["/2"_json_pointer], j[2]);
-
-    // assign to nonexisting index
-    EXPECT_THROW_MSG(j.at("/3"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.401] array index 3 is out of range");
-
-    // assign to nonexisting index (with gap)
-    EXPECT_THROW_MSG(j.at("/5"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.401] array index 5 is out of range");
-
-    // assign to "-"
-    EXPECT_THROW_MSG(j["/-"_json_pointer], json::out_of_range,
-                     "[json.exception.out_of_range.402] array index '-' (3) is out of range");
-    EXPECT_THROW_MSG(j.at("/-"_json_pointer), json::out_of_range,
-                     "[json.exception.out_of_range.402] array index '-' (3) is out of range");
-}
-
-TEST(JsonPointerTest, Flatten)
-{
-    json j =
-    {
-        {"pi", 3.141},
-        {"happy", true},
-        {"name", "Niels"},
-        {"nothing", nullptr},
-        {
-            "answer", {
-                {"everything", 42}
-            }
-        },
-        {"list", {1, 0, 2}},
-        {
-            "object", {
-                {"currency", "USD"},
-                {"value", 42.99},
-                {"", "empty string"},
-                {"/", "slash"},
-                {"~", "tilde"},
-                {"~1", "tilde1"}
-            }
-        }
-    };
-
-    json j_flatten =
-    {
-        {"/pi", 3.141},
-        {"/happy", true},
-        {"/name", "Niels"},
-        {"/nothing", nullptr},
-        {"/answer/everything", 42},
-        {"/list/0", 1},
-        {"/list/1", 0},
-        {"/list/2", 2},
-        {"/object/currency", "USD"},
-        {"/object/value", 42.99},
-        {"/object/", "empty string"},
-        {"/object/~1", "slash"},
-        {"/object/~0", "tilde"},
-        {"/object/~01", "tilde1"}
-    };
-
-    // check if flattened result is as expected
-    EXPECT_EQ(j.flatten(), j_flatten);
-
-    // check if unflattened result is as expected
-    EXPECT_EQ(j_flatten.unflatten(), j);
-
-    // error for nonobjects
-    EXPECT_THROW_MSG(json(1).unflatten(), json::type_error,
-                     "[json.exception.type_error.314] only objects can be unflattened");
-
-    // error for nonprimitve values
-    EXPECT_THROW_MSG(json({{"/1", {1, 2, 3}}}).unflatten(), json::type_error,
-                     "[json.exception.type_error.315] values in object must be primitive");
-
-    // error for conflicting values
-    json j_error = {{"", 42}, {"/foo", 17}};
-    EXPECT_THROW_MSG(j_error.unflatten(), json::type_error,
-                     "[json.exception.type_error.313] invalid value to unflatten");
-
-    // explicit roundtrip check
-    EXPECT_EQ(j.flatten().unflatten(), j);
-
-    // roundtrip for primitive values
-    json j_null;
-    EXPECT_EQ(j_null.flatten().unflatten(), j_null);
-    json j_number = 42;
-    EXPECT_EQ(j_number.flatten().unflatten(), j_number);
-    json j_boolean = false;
-    EXPECT_EQ(j_boolean.flatten().unflatten(), j_boolean);
-    json j_string = "foo";
-    EXPECT_EQ(j_string.flatten().unflatten(), j_string);
-
-    // roundtrip for empty structured values (will be unflattened to null)
-    json j_array(json::value_t::array);
-    EXPECT_EQ(j_array.flatten().unflatten(), json());
-    json j_object(json::value_t::object);
-    EXPECT_EQ(j_object.flatten().unflatten(), json());
-}
-
-TEST(JsonPointerTest, StringRepresentation)
-{
-    for (auto ptr :
-            {"", "/foo", "/foo/0", "/", "/a~1b", "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n"
-            })
-    {
-        SCOPED_TRACE(ptr);
-        EXPECT_EQ(json::json_pointer(ptr).to_string(), ptr);
-    }
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-meta.cpp b/wpiutil/src/test/native/cpp/json/unit-meta.cpp
deleted file mode 100644
index 45daf8f..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-meta.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) FIRST 2017. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonVersionTest, Meta)
-{
-    json j = json::meta();
-
-    EXPECT_EQ(j["name"], "WPI version of JSON for Modern C++");
-    EXPECT_EQ(j["copyright"], "(C) 2013-2017 Niels Lohmann, (C) 2017-2018 FIRST");
-    EXPECT_EQ(j["url"], "https://github.com/wpilibsuite/allwpilib");
-    EXPECT_EQ(j["version"], json(
-    {
-        {"string", "3.1.2"},
-        {"major", 3},
-        {"minor", 1},
-        {"patch", 2}
-    }));
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-modifiers.cpp b/wpiutil/src/test/native/cpp/json/unit-modifiers.cpp
deleted file mode 100644
index 4125858..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-modifiers.cpp
+++ /dev/null
@@ -1,739 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) FIRST 2017. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-TEST(JsonClearTest, Boolean)
-{
-    json j = true;
-
-    j.clear();
-    EXPECT_EQ(j, json(json::value_t::boolean));
-}
-
-TEST(JsonClearTest, String)
-{
-    json j = "hello world";
-
-    j.clear();
-    EXPECT_EQ(j, json(json::value_t::string));
-}
-
-TEST(JsonClearTest, ArrayEmpty)
-{
-    json j = json::array();
-
-    j.clear();
-    EXPECT_TRUE(j.empty());
-    EXPECT_EQ(j, json(json::value_t::array));
-}
-
-TEST(JsonClearTest, ArrayFilled)
-{
-    json j = {1, 2, 3};
-
-    j.clear();
-    EXPECT_TRUE(j.empty());
-    EXPECT_EQ(j, json(json::value_t::array));
-}
-
-TEST(JsonClearTest, ObjectEmpty)
-{
-    json j = json::object();
-
-    j.clear();
-    EXPECT_TRUE(j.empty());
-    EXPECT_EQ(j, json(json::value_t::object));
-}
-
-TEST(JsonClearTest, ObjectFilled)
-{
-    json j = {{"one", 1}, {"two", 2}, {"three", 3}};
-
-    j.clear();
-    EXPECT_TRUE(j.empty());
-    EXPECT_EQ(j, json(json::value_t::object));
-}
-
-TEST(JsonClearTest, Integer)
-{
-    json j = 23;
-
-    j.clear();
-    EXPECT_EQ(j, json(json::value_t::number_integer));
-}
-
-TEST(JsonClearTest, Unsigned)
-{
-    json j = 23u;
-
-    j.clear();
-    EXPECT_EQ(j, json(json::value_t::number_integer));
-}
-
-TEST(JsonClearTest, Float)
-{
-    json j = 23.42;
-
-    j.clear();
-    EXPECT_EQ(j, json(json::value_t::number_float));
-}
-
-TEST(JsonClearTest, Null)
-{
-    json j = nullptr;
-
-    j.clear();
-    EXPECT_EQ(j, json(json::value_t::null));
-}
-
-TEST(JsonPushBackArrayTest, RRefNull)
-{
-    json j;
-    j.push_back(1);
-    j.push_back(2);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2}));
-}
-
-TEST(JsonPushBackArrayTest, RRefArray)
-{
-    json j = {1, 2, 3};
-    j.push_back("Hello");
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2, 3, "Hello"}));
-}
-
-TEST(JsonPushBackArrayTest, RRefOther)
-{
-    json j = 1;
-    EXPECT_THROW_MSG(j.push_back("Hello"), json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with number");
-}
-
-TEST(JsonPushBackArrayTest, LRefNull)
-{
-    json j;
-    json k(1);
-    j.push_back(k);
-    j.push_back(k);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 1}));
-}
-
-TEST(JsonPushBackArrayTest, LRefArray)
-{
-    json j = {1, 2, 3};
-    json k("Hello");
-    j.push_back(k);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2, 3, "Hello"}));
-}
-
-TEST(JsonPushBackArrayTest, LRefOther)
-{
-    json j = 1;
-    json k("Hello");
-    EXPECT_THROW_MSG(j.push_back(k), json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with number");
-}
-#if 0
-TEST(JsonPushBackObjectTest, Null)
-{
-    json j;
-    j.push_back(json::object_t::value_type({"one", 1}));
-    j.push_back(json::object_t::value_type({"two", 2}));
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j.size(), 2u);
-    EXPECT_EQ(j["one"], json(1));
-    EXPECT_EQ(j["two"], json(2));
-}
-
-TEST(JsonPushBackObjectTest, Object)
-{
-    json j(json::value_t::object);
-    j.push_back(json::object_t::value_type({"one", 1}));
-    j.push_back(json::object_t::value_type({"two", 2}));
-    EXPECT_EQ(j.size(), 2u);
-    EXPECT_EQ(j["one"], json(1));
-    EXPECT_EQ(j["two"], json(2));
-}
-
-TEST(JsonPushBackObjectTest, Other)
-{
-    json j = 1;
-    json k("Hello");
-    EXPECT_THROW_MSG(j.push_back(json::object_t::value_type({"one", 1})), json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with number");
-}
-#endif
-TEST(JsonPushBackInitListTest, Null)
-{
-    json j;
-    j.push_back({"foo", "bar"});
-    EXPECT_EQ(j, json::array({{"foo", "bar"}}));
-
-    json k;
-    k.push_back({1, 2, 3});
-    EXPECT_EQ(k, json::array({{1, 2, 3}}));
-}
-
-TEST(JsonPushBackInitListTest, Array)
-{
-    json j = {1, 2, 3};
-    j.push_back({"foo", "bar"});
-    EXPECT_EQ(j, json({1, 2, 3, {"foo", "bar"}}));
-
-    json k = {1, 2, 3};
-    k.push_back({1, 2, 3});
-    EXPECT_EQ(k, json({1, 2, 3, {1, 2, 3}}));
-}
-
-TEST(JsonPushBackInitListTest, Object)
-{
-    json j = {{"key1", 1}};
-    j.push_back({"key2", "bar"});
-    EXPECT_EQ(j, json({{"key1", 1}, {"key2", "bar"}}));
-
-    json k = {{"key1", 1}};
-    EXPECT_THROW_MSG(k.push_back({1, 2, 3, 4}), json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with object");
-}
-
-TEST(JsonEmplaceBackArrayTest, Null)
-{
-    json j;
-    j.emplace_back(1);
-    j.emplace_back(2);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2}));
-}
-
-TEST(JsonEmplaceBackArrayTest, Array)
-{
-    json j = {1, 2, 3};
-    j.emplace_back("Hello");
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2, 3, "Hello"}));
-}
-
-TEST(JsonEmplaceBackArrayTest, MultipleValues)
-{
-    json j;
-    j.emplace_back(3, "foo");
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({{"foo", "foo", "foo"}}));
-}
-
-TEST(JsonEmplaceBackArrayTest, Other)
-{
-    json j = 1;
-    EXPECT_THROW_MSG(j.emplace_back("Hello"), json::type_error,
-                     "[json.exception.type_error.311] cannot use emplace_back() with number");
-}
-
-TEST(JsonEmplaceObjectTest, Null)
-{
-    // start with a null value
-    json j;
-
-    // add a new key
-    auto res1 = j.emplace("foo", "bar");
-    EXPECT_EQ(res1.second, true);
-    EXPECT_EQ(*res1.first, "bar");
-
-    // the null value is changed to an object
-    EXPECT_EQ(j.type(), json::value_t::object);
-
-    // add a new key
-    auto res2 = j.emplace("baz", "bam");
-    EXPECT_EQ(res2.second, true);
-    EXPECT_EQ(*res2.first, "bam");
-
-    // we try to insert at given key - no change
-    auto res3 = j.emplace("baz", "bad");
-    EXPECT_EQ(res3.second, false);
-    EXPECT_EQ(*res3.first, "bam");
-
-    // the final object
-    EXPECT_EQ(j, json({{"baz", "bam"}, {"foo", "bar"}}));
-}
-
-TEST(JsonEmplaceObjectTest, Object)
-{
-    // start with an object
-    json j = {{"foo", "bar"}};
-
-    // add a new key
-    auto res1 = j.emplace("baz", "bam");
-    EXPECT_EQ(res1.second, true);
-    EXPECT_EQ(*res1.first, "bam");
-
-    // add an existing key
-    auto res2 = j.emplace("foo", "bad");
-    EXPECT_EQ(res2.second, false);
-    EXPECT_EQ(*res2.first, "bar");
-
-    // check final object
-    EXPECT_EQ(j, json({{"baz", "bam"}, {"foo", "bar"}}));
-}
-
-TEST(JsonEmplaceObjectTest, Other)
-{
-    json j = 1;
-    EXPECT_THROW_MSG(j.emplace("foo", "bar"), json::type_error,
-                     "[json.exception.type_error.311] cannot use emplace() with number");
-}
-
-TEST(JsonPlusEqualArrayTest, RRefNull)
-{
-    json j;
-    j += 1;
-    j += 2;
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2}));
-}
-
-TEST(JsonPlusEqualArrayTest, RRefArray)
-{
-    json j = {1, 2, 3};
-    j += "Hello";
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2, 3, "Hello"}));
-}
-
-TEST(JsonPlusEqualArrayTest, RRefOther)
-{
-    json j = 1;
-    EXPECT_THROW_MSG(j += "Hello", json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with number");
-}
-
-TEST(JsonPlusEqualArrayTest, LRefNull)
-{
-    json j;
-    json k(1);
-    j += k;
-    j += k;
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 1}));
-}
-
-TEST(JsonPlusEqualArrayTest, LRefArray)
-{
-    json j = {1, 2, 3};
-    json k("Hello");
-    j += k;
-    EXPECT_EQ(j.type(), json::value_t::array);
-    EXPECT_EQ(j, json({1, 2, 3, "Hello"}));
-}
-
-TEST(JsonPlusEqualArrayTest, LRefOther)
-{
-    json j = 1;
-    json k("Hello");
-    EXPECT_THROW_MSG(j += k, json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with number");
-}
-#if 0
-TEST(JsonPlusEqualObjectTest, Null)
-{
-    json j;
-    j += json::object_t::value_type({"one", 1});
-    j += json::object_t::value_type({"two", 2});
-    EXPECT_EQ(j.type(), json::value_t::object);
-    EXPECT_EQ(j.size(), 2u);
-    EXPECT_EQ(j["one"], json(1));
-    EXPECT_EQ(j["two"], json(2));
-}
-
-TEST(JsonPlusEqualObjectTest, Object)
-{
-    json j(json::value_t::object);
-    j += json::object_t::value_type({"one", 1});
-    j += json::object_t::value_type({"two", 2});
-    EXPECT_EQ(j.size(), 2u);
-    EXPECT_EQ(j["one"], json(1));
-    EXPECT_EQ(j["two"], json(2));
-}
-
-TEST(JsonPlusEqualObjectTest, Other)
-{
-    json j = 1;
-    json k("Hello");
-    EXPECT_THROW_MSG(j += json::object_t::value_type({"one", 1}), json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with number");
-}
-#endif
-TEST(JsonPlusEqualInitListTest, Null)
-{
-    json j;
-    j += {"foo", "bar"};
-    EXPECT_EQ(j, json::array({{"foo", "bar"}}));
-
-    json k;
-    k += {1, 2, 3};
-    EXPECT_EQ(k, json::array({{1, 2, 3}}));
-}
-
-TEST(JsonPlusEqualInitListTest, Array)
-{
-    json j = {1, 2, 3};
-    j += {"foo", "bar"};
-    EXPECT_EQ(j, json({1, 2, 3, {"foo", "bar"}}));
-
-    json k = {1, 2, 3};
-    k += {1, 2, 3};
-    EXPECT_EQ(k, json({1, 2, 3, {1, 2, 3}}));
-}
-
-TEST(JsonPlusEqualInitListTest, Object)
-{
-    json j = {{"key1", 1}};
-    j += {"key2", "bar"};
-    EXPECT_EQ(j, json({{"key1", 1}, {"key2", "bar"}}));
-
-    json k = {{"key1", 1}};
-    EXPECT_THROW_MSG((k += {1, 2, 3, 4}), json::type_error,
-                     "[json.exception.type_error.308] cannot use push_back() with object");
-}
-
-class JsonInsertTest : public ::testing::Test {
- protected:
-    json j_array = {1, 2, 3, 4};
-    json j_value = 5;
-    json j_other_array = {"first", "second"};
-    json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
-    json j_object2 = {{"eleven", "elf"}, {"seventeen", "siebzehn"}};
-};
-
-TEST_F(JsonInsertTest, ValueBegin)
-{
-    auto it = j_array.insert(j_array.begin(), j_value);
-    EXPECT_EQ(j_array.size(), 5u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ(j_array.begin(), it);
-    EXPECT_EQ(j_array, json({5, 1, 2, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, ValueMiddle)
-{
-    auto it = j_array.insert(j_array.begin() + 2, j_value);
-    EXPECT_EQ(j_array.size(), 5u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ((it - j_array.begin()), 2);
-    EXPECT_EQ(j_array, json({1, 2, 5, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, ValueEnd)
-{
-    auto it = j_array.insert(j_array.end(), j_value);
-    EXPECT_EQ(j_array.size(), 5u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ((j_array.end() - it), 1);
-    EXPECT_EQ(j_array, json({1, 2, 3, 4, 5}));
-}
-
-TEST_F(JsonInsertTest, RvalueBegin)
-{
-    auto it = j_array.insert(j_array.begin(), 5);
-    EXPECT_EQ(j_array.size(), 5u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ(j_array.begin(), it);
-    EXPECT_EQ(j_array, json({5, 1, 2, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, RvalueMiddle)
-{
-    auto it = j_array.insert(j_array.begin() + 2, 5);
-    EXPECT_EQ(j_array.size(), 5u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ((it - j_array.begin()), 2);
-    EXPECT_EQ(j_array, json({1, 2, 5, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, RvalueEnd)
-{
-    auto it = j_array.insert(j_array.end(), 5);
-    EXPECT_EQ(j_array.size(), 5u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ((j_array.end() - it), 1);
-    EXPECT_EQ(j_array, json({1, 2, 3, 4, 5}));
-}
-
-TEST_F(JsonInsertTest, CopyBegin)
-{
-    auto it = j_array.insert(j_array.begin(), 3, 5);
-    EXPECT_EQ(j_array.size(), 7u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ(j_array.begin(), it);
-    EXPECT_EQ(j_array, json({5, 5, 5, 1, 2, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, CopyMiddle)
-{
-    auto it = j_array.insert(j_array.begin() + 2, 3, 5);
-    EXPECT_EQ(j_array.size(), 7u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ((it - j_array.begin()), 2);
-    EXPECT_EQ(j_array, json({1, 2, 5, 5, 5, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, CopyEnd)
-{
-    auto it = j_array.insert(j_array.end(), 3, 5);
-    EXPECT_EQ(j_array.size(), 7u);
-    EXPECT_EQ(*it, j_value);
-    EXPECT_EQ((j_array.end() - it), 3);
-    EXPECT_EQ(j_array, json({1, 2, 3, 4, 5, 5, 5}));
-}
-
-TEST_F(JsonInsertTest, CopyNothing)
-{
-    auto it = j_array.insert(j_array.end(), 0, 5);
-    EXPECT_EQ(j_array.size(), 4u);
-    // the returned iterator points to the first inserted element;
-    // there were 4 elements, so it should point to the 5th
-    EXPECT_EQ(it, j_array.begin() + 4);
-    EXPECT_EQ(j_array, json({1, 2, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, RangeForArrayProper)
-{
-    auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.end());
-    EXPECT_EQ(j_array.size(), 6u);
-    EXPECT_EQ(*it, *j_other_array.begin());
-    EXPECT_EQ((j_array.end() - it), 2);
-    EXPECT_EQ(j_array, json({1, 2, 3, 4, "first", "second"}));
-}
-
-TEST_F(JsonInsertTest, RangeForArrayEmpty)
-{
-    auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.begin());
-    EXPECT_EQ(j_array.size(), 4u);
-    EXPECT_EQ(it, j_array.end());
-    EXPECT_EQ(j_array, json({1, 2, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, RangeForArrayInvalid)
-{
-    json j_other_array2 = {"first", "second"};
-
-    EXPECT_THROW_MSG(j_array.insert(j_array.end(), j_array.begin(), j_array.end()),
-                    json::invalid_iterator,
-                    "[json.exception.invalid_iterator.211] passed iterators may not belong to container");
-    EXPECT_THROW_MSG(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()),
-                    json::invalid_iterator,
-                    "[json.exception.invalid_iterator.210] iterators do not fit");
-}
-
-TEST_F(JsonInsertTest, RangeForObjectProper)
-{
-    j_object1.insert(j_object2.begin(), j_object2.end());
-    EXPECT_EQ(j_object1.size(), 4u);
-}
-
-TEST_F(JsonInsertTest, RangeForObjectEmpty)
-{
-    j_object1.insert(j_object2.begin(), j_object2.begin());
-    EXPECT_EQ(j_object1.size(), 2u);
-}
-
-TEST_F(JsonInsertTest, RangeForObjectInvalid)
-{
-    json j_other_array2 = {"first", "second"};
-
-    EXPECT_THROW_MSG(j_array.insert(j_object2.begin(), j_object2.end()), json::type_error,
-                     "[json.exception.type_error.309] cannot use insert() with array");
-    EXPECT_THROW_MSG(j_object1.insert(j_object1.begin(), j_object2.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.210] iterators do not fit");
-    EXPECT_THROW_MSG(j_object1.insert(j_array.begin(), j_array.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterators first and last must point to objects");
-}
-
-TEST_F(JsonInsertTest, InitListBegin)
-{
-    auto it = j_array.insert(j_array.begin(), {7, 8, 9});
-    EXPECT_EQ(j_array.size(), 7u);
-    EXPECT_EQ(*it, json(7));
-    EXPECT_EQ(j_array.begin(), it);
-    EXPECT_EQ(j_array, json({7, 8, 9, 1, 2, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, InitListMiddle)
-{
-    auto it = j_array.insert(j_array.begin() + 2, {7, 8, 9});
-    EXPECT_EQ(j_array.size(), 7u);
-    EXPECT_EQ(*it, json(7));
-    EXPECT_EQ((it - j_array.begin()), 2);
-    EXPECT_EQ(j_array, json({1, 2, 7, 8, 9, 3, 4}));
-}
-
-TEST_F(JsonInsertTest, InitListEnd)
-{
-    auto it = j_array.insert(j_array.end(), {7, 8, 9});
-    EXPECT_EQ(j_array.size(), 7u);
-    EXPECT_EQ(*it, json(7));
-    EXPECT_EQ((j_array.end() - it), 3);
-    EXPECT_EQ(j_array, json({1, 2, 3, 4, 7, 8, 9}));
-}
-
-TEST_F(JsonInsertTest, InvalidIterator)
-{
-    // pass iterator to a different array
-    json j_another_array = {1, 2};
-    json j_yet_another_array = {"first", "second"};
-    EXPECT_THROW_MSG(j_array.insert(j_another_array.end(), 10), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(j_array.insert(j_another_array.end(), j_value), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(j_array.insert(j_another_array.end(), 10, 11), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-    EXPECT_THROW_MSG(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), json::invalid_iterator,
-                     "[json.exception.invalid_iterator.202] iterator does not fit current value");
-}
-
-TEST_F(JsonInsertTest, NonArray)
-{
-    // call insert on a non-array type
-    json j_nonarray = 3;
-    json j_yet_another_array = {"first", "second"};
-    EXPECT_THROW_MSG(j_nonarray.insert(j_nonarray.end(), 10), json::type_error,
-                     "[json.exception.type_error.309] cannot use insert() with number");
-    EXPECT_THROW_MSG(j_nonarray.insert(j_nonarray.end(), j_value), json::type_error,
-                     "[json.exception.type_error.309] cannot use insert() with number");
-    EXPECT_THROW_MSG(j_nonarray.insert(j_nonarray.end(), 10, 11), json::type_error,
-                     "[json.exception.type_error.309] cannot use insert() with number");
-    EXPECT_THROW_MSG(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(),
-                                       j_yet_another_array.end()), json::type_error,
-                     "[json.exception.type_error.309] cannot use insert() with number");
-    EXPECT_THROW_MSG(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), json::type_error,
-                     "[json.exception.type_error.309] cannot use insert() with number");
-}
-
-TEST(JsonSwapTest, JsonMember)
-{
-    json j("hello world");
-    json k(42.23);
-
-    j.swap(k);
-
-    EXPECT_EQ(j, json(42.23));
-    EXPECT_EQ(k, json("hello world"));
-}
-
-TEST(JsonSwapTest, JsonNonMember)
-{
-    json j("hello world");
-    json k(42.23);
-
-    std::swap(j, k);
-
-    EXPECT_EQ(j, json(42.23));
-    EXPECT_EQ(k, json("hello world"));
-}
-
-TEST(JsonSwapTest, ArrayT)
-{
-    json j = {1, 2, 3, 4};
-    json::array_t a = {"foo", "bar", "baz"};
-
-    j.swap(a);
-
-    EXPECT_EQ(j, json({"foo", "bar", "baz"}));
-
-    j.swap(a);
-
-    EXPECT_EQ(j, json({1, 2, 3, 4}));
-}
-
-TEST(JsonSwapTest, NonArrayT)
-{
-    json j = 17;
-    json::array_t a = {"foo", "bar", "baz"};
-
-    EXPECT_THROW_MSG(j.swap(a), json::type_error,
-                     "[json.exception.type_error.310] cannot use swap() with number");
-}
-
-TEST(JsonSwapTest, ObjectT)
-{
-    json j = {{"one", 1}, {"two", 2}};
-    json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
-
-    j.swap(o);
-
-    EXPECT_EQ(j, json({{"cow", "Kuh"}, {"chicken", "Huhn"}}));
-
-    j.swap(o);
-
-    EXPECT_EQ(j, json({{"one", 1}, {"two", 2}}));
-}
-
-TEST(JsonSwapTest, NonObjectT)
-{
-    json j = 17;
-    json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
-
-    EXPECT_THROW_MSG(j.swap(o), json::type_error,
-                     "[json.exception.type_error.310] cannot use swap() with number");
-}
-
-TEST(JsonSwapTest, StringT)
-{
-    json j = "Hello world";
-    std::string s = "Hallo Welt";
-
-    j.swap(s);
-
-    EXPECT_EQ(j, json("Hallo Welt"));
-
-    j.swap(s);
-
-    EXPECT_EQ(j, json("Hello world"));
-}
-
-TEST(JsonSwapTest, NonStringT)
-{
-    json j = 17;
-    std::string s = "Hallo Welt";
-
-    EXPECT_THROW_MSG(j.swap(s), json::type_error,
-                     "[json.exception.type_error.310] cannot use swap() with number");
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-msgpack.cpp b/wpiutil/src/test/native/cpp/json/unit-msgpack.cpp
deleted file mode 100644
index 73665ea..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-msgpack.cpp
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) FIRST 2017. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-#include <cmath>
-#include <fstream>
-
-TEST(MessagePackDiscardedTest, Case)
-{
-    // discarded values are not serialized
-    json j = json::value_t::discarded;
-    const auto result = json::to_msgpack(j);
-    EXPECT_TRUE(result.empty());
-}
-
-TEST(MessagePackNullTest, Case)
-{
-    json j = nullptr;
-    std::vector<uint8_t> expected = {0xc0};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-TEST(MessagePackBooleanTest, True)
-{
-    json j = true;
-    std::vector<uint8_t> expected = {0xc3};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-TEST(MessagePackBooleanTest, False)
-{
-    json j = false;
-    std::vector<uint8_t> expected = {0xc2};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// -32..-1 (negative fixnum)
-TEST(MessagePackSignedTest, Neg0)
-{
-    for (auto i = -32; i <= -1; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        EXPECT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 1u);
-
-        // check individual bytes
-        EXPECT_EQ(static_cast<int8_t>(result[0]), i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 0..127 (positive fixnum)
-TEST(MessagePackSignedTest, Pos0)
-{
-    for (size_t i = 0; i <= 127; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = -1;
-        j.get_ref<int64_t&>() = static_cast<int64_t>(i);
-
-        // check type
-        EXPECT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 1u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(i));
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 128..255 (int 8)
-TEST(MessagePackSignedTest, Pos1)
-{
-    for (size_t i = 128; i <= 255; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = -1;
-        j.get_ref<int64_t&>() = static_cast<int64_t>(i);
-
-        // check type
-        EXPECT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xcc));
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 2u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(0xcc));
-        uint8_t restored = static_cast<uint8_t>(result[1]);
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 256..65535 (int 16)
-TEST(MessagePackSignedTest, Pos2)
-{
-    for (size_t i = 256; i <= 65535; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = -1;
-        j.get_ref<int64_t&>() = static_cast<int64_t>(i);
-
-        // check type
-        EXPECT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xcd));
-        expected.push_back(static_cast<uint8_t>((i >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(i & 0xff));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(0xcd));
-        uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 65536..4294967295 (int 32)
-class MessagePackSignedPos4Test : public ::testing::TestWithParam<uint32_t> {};
-TEST_P(MessagePackSignedPos4Test, Case)
-{
-    // create JSON value with integer number
-    json j = -1;
-    j.get_ref<int64_t&>() = static_cast<int64_t>(GetParam());
-
-    // check type
-    EXPECT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xce));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), 5u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xce));
-    uint32_t restored = (static_cast<uint32_t>(static_cast<uint8_t>(result[1])) << 030) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[2])) << 020) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[3])) << 010) +
-                        static_cast<uint32_t>(static_cast<uint8_t>(result[4]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-static const uint32_t pos4_numbers[] = {
-    65536u,
-    77777u,
-    1048576u,
-    4294967295u,
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackSignedPos4Tests, MessagePackSignedPos4Test,
-                        ::testing::ValuesIn(pos4_numbers));
-
-// 4294967296..9223372036854775807 (int 64)
-class MessagePackSignedPos8Test : public ::testing::TestWithParam<uint64_t> {};
-TEST_P(MessagePackSignedPos8Test, Case)
-{
-    // create JSON value with integer number
-    json j = -1;
-    j.get_ref<int64_t&>() =
-        static_cast<int64_t>(GetParam());
-
-    // check type
-    EXPECT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xcf));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 070) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 060) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 050) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 040) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 030) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 020) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 010) & 0xff));
-    expected.push_back(static_cast<char>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), 9u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xcf));
-    uint64_t restored = (static_cast<uint64_t>(static_cast<uint8_t>(result[1])) << 070) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[2])) << 060) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[3])) << 050) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[4])) << 040) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[5])) << 030) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[6])) << 020) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[7])) << 010) +
-                        static_cast<uint64_t>(static_cast<uint8_t>(result[8]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-static const uint64_t pos8_numbers[] = {
-    4294967296lu,
-    9223372036854775807lu,
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackSignedPos8Tests, MessagePackSignedPos8Test,
-                        ::testing::ValuesIn(pos8_numbers));
-
-// -128..-33 (int 8)
-TEST(MessagePackSignedTest, Neg1)
-{
-    for (auto i = -128; i <= -33; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        EXPECT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xd0));
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 2u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(0xd0));
-        EXPECT_EQ(static_cast<int8_t>(result[1]), i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// -32768..-129 (int 16)
-TEST(MessagePackSignedTest, Neg2)
-{
-    for (int16_t i = -32768; i <= -129; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with integer number
-        json j = i;
-
-        // check type
-        EXPECT_TRUE(j.is_number_integer());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xd1));
-        expected.push_back(static_cast<uint8_t>((i >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(i & 0xff));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(0xd1));
-        int16_t restored = static_cast<int16_t>((static_cast<uint8_t>(result[1]) << 8) +
-                                                static_cast<uint8_t>(result[2]));
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// -32769..-2147483648
-class MessagePackSignedNeg4Test : public ::testing::TestWithParam<int32_t> {};
-TEST_P(MessagePackSignedNeg4Test, Case)
-{
-    // create JSON value with integer number
-    json j = GetParam();
-
-    // check type
-    EXPECT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xd2));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), 5u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xd2));
-    uint32_t restored = (static_cast<uint32_t>(static_cast<uint8_t>(result[1])) << 030) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[2])) << 020) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[3])) << 010) +
-                        static_cast<uint32_t>(static_cast<uint8_t>(result[4]));
-    EXPECT_EQ(static_cast<int32_t>(restored), GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-static const int32_t neg4_numbers[] = {
-    -32769,
-    -65536,
-    -77777,
-    -1048576,
-    -2147483648ll,
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackSignedNeg4Tests, MessagePackSignedNeg4Test,
-                        ::testing::ValuesIn(neg4_numbers));
-
-// -9223372036854775808..-2147483649 (int 64)
-class MessagePackSignedNeg8Test : public ::testing::TestWithParam<int64_t> {};
-TEST_P(MessagePackSignedNeg8Test, Case)
-{
-    // create JSON value with unsigned integer number
-    json j = GetParam();
-
-    // check type
-    EXPECT_TRUE(j.is_number_integer());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xd3));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 070) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 060) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 050) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 040) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 030) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 020) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 010) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), 9u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xd3));
-    int64_t restored = (static_cast<int64_t>(static_cast<uint8_t>(result[1])) << 070) +
-                       (static_cast<int64_t>(static_cast<uint8_t>(result[2])) << 060) +
-                       (static_cast<int64_t>(static_cast<uint8_t>(result[3])) << 050) +
-                       (static_cast<int64_t>(static_cast<uint8_t>(result[4])) << 040) +
-                       (static_cast<int64_t>(static_cast<uint8_t>(result[5])) << 030) +
-                       (static_cast<int64_t>(static_cast<uint8_t>(result[6])) << 020) +
-                       (static_cast<int64_t>(static_cast<uint8_t>(result[7])) << 010) +
-                       static_cast<int64_t>(static_cast<uint8_t>(result[8]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-static const int64_t neg8_numbers[] = {
-    INT64_MIN,
-    -2147483649ll,
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackSignedNeg8Tests, MessagePackSignedNeg8Test,
-                        ::testing::ValuesIn(neg8_numbers));
-
-// 0..127 (positive fixnum)
-TEST(MessagePackUnsignedTest, Pos0)
-{
-    for (size_t i = 0; i <= 127; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with unsigned integer number
-        json j = i;
-
-        // check type
-        EXPECT_TRUE(j.is_number_unsigned());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 1u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(i));
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 128..255 (uint 8)
-TEST(MessagePackUnsignedTest, Pos1)
-{
-    for (size_t i = 128; i <= 255; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with unsigned integer number
-        json j = i;
-
-        // check type
-        EXPECT_TRUE(j.is_number_unsigned());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xcc));
-        expected.push_back(static_cast<uint8_t>(i));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 2u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(0xcc));
-        uint8_t restored = static_cast<uint8_t>(result[1]);
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 256..65535 (uint 16)
-TEST(MessagePackUnsignedTest, Pos2)
-{
-    for (size_t i = 256; i <= 65535; ++i)
-    {
-        SCOPED_TRACE(i);
-
-        // create JSON value with unsigned integer number
-        json j = i;
-
-        // check type
-        EXPECT_TRUE(j.is_number_unsigned());
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xcd));
-        expected.push_back(static_cast<uint8_t>((i >> 8) & 0xff));
-        expected.push_back(static_cast<uint8_t>(i & 0xff));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), 3u);
-
-        // check individual bytes
-        EXPECT_EQ(result[0], static_cast<uint8_t>(0xcd));
-        uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
-        EXPECT_EQ(restored, i);
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// 65536..4294967295 (uint 32)
-class MessagePackUnsignedPos4Test : public ::testing::TestWithParam<uint32_t> {};
-TEST_P(MessagePackUnsignedPos4Test, Case)
-{
-    // create JSON value with unsigned integer number
-    json j = GetParam();
-
-    // check type
-    EXPECT_TRUE(j.is_number_unsigned());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xce));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), 5u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xce));
-    uint32_t restored = (static_cast<uint32_t>(static_cast<uint8_t>(result[1])) << 030) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[2])) << 020) +
-                        (static_cast<uint32_t>(static_cast<uint8_t>(result[3])) << 010) +
-                        static_cast<uint32_t>(static_cast<uint8_t>(result[4]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-INSTANTIATE_TEST_SUITE_P(MessagePackUnsignedPos4Tests,
-                        MessagePackUnsignedPos4Test,
-                        ::testing::ValuesIn(pos4_numbers));
-
-// 4294967296..18446744073709551615 (uint 64)
-class MessagePackUnsignedPos8Test : public ::testing::TestWithParam<uint64_t> {};
-TEST_P(MessagePackUnsignedPos8Test, Case)
-{
-    // create JSON value with unsigned integer number
-    json j = GetParam();
-
-    // check type
-    EXPECT_TRUE(j.is_number_unsigned());
-
-    // create expected byte vector
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xcf));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 070) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 060) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 050) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 040) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 030) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 020) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 010) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), 9u);
-
-    // check individual bytes
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xcf));
-    uint64_t restored = (static_cast<uint64_t>(static_cast<uint8_t>(result[1])) << 070) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[2])) << 060) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[3])) << 050) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[4])) << 040) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[5])) << 030) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[6])) << 020) +
-                        (static_cast<uint64_t>(static_cast<uint8_t>(result[7])) << 010) +
-                        static_cast<uint64_t>(static_cast<uint8_t>(result[8]));
-    EXPECT_EQ(restored, GetParam());
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-INSTANTIATE_TEST_SUITE_P(MessagePackUnsignedPos8Tests,
-                        MessagePackUnsignedPos8Test,
-                        ::testing::ValuesIn(pos8_numbers));
-
-// 3.1415925
-TEST(MessagePackFloatTest, Number)
-{
-    double v = 3.1415925;
-    json j = v;
-    std::vector<uint8_t> expected = {0xcb,0x40,0x09,0x21,0xfb,0x3f,0xa6,0xde,0xfc};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-    EXPECT_EQ(json::from_msgpack(result), v);
-}
-
-// N = 0..31
-TEST(MessagePackStringTest, String1)
-{
-    // explicitly enumerate the first byte for all 32 strings
-    const std::vector<uint8_t> first_bytes =
-    {
-        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
-        0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1,
-        0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
-        0xbb, 0xbc, 0xbd, 0xbe, 0xbf
-    };
-
-    for (size_t N = 0; N < first_bytes.size(); ++N)
-    {
-        SCOPED_TRACE(N);
-
-        // create JSON value with string containing of N * 'x'
-        const auto s = std::string(N, 'x');
-        json j = s;
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(first_bytes[N]));
-        for (size_t i = 0; i < N; ++i)
-        {
-            expected.push_back('x');
-        }
-
-        // check first byte
-        EXPECT_EQ((first_bytes[N] & 0x1f), static_cast<uint8_t>(N));
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), N + 1);
-        // check that no null byte is appended
-        if (N > 0)
-        {
-            EXPECT_NE(result.back(), '\x00');
-        }
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// N = 32..255
-TEST(MessagePackStringTest, String2)
-{
-    for (size_t N = 32; N <= 255; ++N)
-    {
-        SCOPED_TRACE(N);
-
-        // create JSON value with string containing of N * 'x'
-        const auto s = std::string(N, 'x');
-        json j = s;
-
-        // create expected byte vector
-        std::vector<uint8_t> expected;
-        expected.push_back(static_cast<uint8_t>(0xd9));
-        expected.push_back(static_cast<uint8_t>(N));
-        for (size_t i = 0; i < N; ++i)
-        {
-            expected.push_back('x');
-        }
-
-        // compare result + size
-        const auto result = json::to_msgpack(j);
-        EXPECT_EQ(result, expected);
-        EXPECT_EQ(result.size(), N + 2);
-        // check that no null byte is appended
-        EXPECT_NE(result.back(), '\x00');
-
-        // roundtrip
-        EXPECT_EQ(json::from_msgpack(result), j);
-    }
-}
-
-// N = 256..65535
-class MessagePackString3Test : public ::testing::TestWithParam<size_t> {};
-TEST_P(MessagePackString3Test, Case)
-{
-    // create JSON value with string containing of N * 'x'
-    const auto s = std::string(GetParam(), 'x');
-    json j = s;
-
-    // create expected byte vector (hack: create string first)
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xda));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-    for (size_t i = 0; i < GetParam(); ++i)
-    {
-        expected.push_back('x');
-    }
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), GetParam() + 3);
-    // check that no null byte is appended
-    EXPECT_NE(result.back(), '\x00');
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-static size_t string3_lens[] = {
-    256u,
-    999u,
-    1025u,
-    3333u,
-    2048u,
-    65535u
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackString3Tests, MessagePackString3Test,
-                        ::testing::ValuesIn(string3_lens));
-
-
-// N = 65536..4294967295
-class MessagePackString5Test : public ::testing::TestWithParam<size_t> {};
-TEST_P(MessagePackString5Test, Case)
-{
-    // create JSON value with string containing of N * 'x'
-    const auto s = std::string(GetParam(), 'x');
-    json j = s;
-
-    // create expected byte vector (hack: create string first)
-    std::vector<uint8_t> expected;
-    expected.push_back(static_cast<uint8_t>(0xdb));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 24) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 16) & 0xff));
-    expected.push_back(static_cast<uint8_t>((GetParam() >> 8) & 0xff));
-    expected.push_back(static_cast<uint8_t>(GetParam() & 0xff));
-    for (size_t i = 0; i < GetParam(); ++i)
-    {
-        expected.push_back('x');
-    }
-
-    // compare result + size
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-    EXPECT_EQ(result.size(), GetParam() + 5);
-    // check that no null byte is appended
-    EXPECT_NE(result.back(), '\x00');
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-static size_t string5_lens[] = {
-    65536u,
-    77777u,
-    1048576u
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackString5Tests, MessagePackString5Test,
-                        ::testing::ValuesIn(string5_lens));
-
-TEST(MessagePackArrayTest, Empty)
-{
-    json j = json::array();
-    std::vector<uint8_t> expected = {0x90};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// [null]
-TEST(MessagePackArrayTest, Null)
-{
-    json j = {nullptr};
-    std::vector<uint8_t> expected = {0x91,0xc0};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// [1,2,3,4,5]
-TEST(MessagePackArrayTest, Simple)
-{
-    json j = json::parse("[1,2,3,4,5]");
-    std::vector<uint8_t> expected = {0x95,0x01,0x02,0x03,0x04,0x05};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// [[[[]]]]
-TEST(MessagePackArrayTest, NestEmpty)
-{
-    json j = json::parse("[[[[]]]]");
-    std::vector<uint8_t> expected = {0x91,0x91,0x91,0x90};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// array 16
-TEST(MessagePackArrayTest, UInt16)
-{
-    json j(16, nullptr);
-    std::vector<uint8_t> expected(j.size() + 3, static_cast<uint8_t>(0xc0)); // all null
-    expected[0] = static_cast<uint8_t>(0xdc); // array 16
-    expected[1] = 0x00; // size (0x0010), byte 0
-    expected[2] = 0x10; // size (0x0010), byte 1
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// array 32
-TEST(MessagePackArrayTest, UInt32)
-{
-    json j(65536, nullptr);
-    std::vector<uint8_t> expected(j.size() + 5, static_cast<uint8_t>(0xc0)); // all null
-    expected[0] = static_cast<uint8_t>(0xdd); // array 32
-    expected[1] = 0x00; // size (0x00100000), byte 0
-    expected[2] = 0x01; // size (0x00100000), byte 1
-    expected[3] = 0x00; // size (0x00100000), byte 2
-    expected[4] = 0x00; // size (0x00100000), byte 3
-    const auto result = json::to_msgpack(j);
-    //EXPECT_EQ(result, expected);
-
-    EXPECT_EQ(result.size(), expected.size());
-    for (size_t i = 0; i < expected.size(); ++i)
-    {
-        SCOPED_TRACE(i);
-        EXPECT_EQ(result[i], expected[i]);
-    }
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-TEST(MessagePackObjectTest, Empty)
-{
-    json j = json::object();
-    std::vector<uint8_t> expected = {0x80};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// {"":null}
-TEST(MessagePackObjectTest, EmptyKey)
-{
-    json j = {{"", nullptr}};
-    std::vector<uint8_t> expected = {0x81,0xa0,0xc0};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// {"a": {"b": {"c": {}}}}
-TEST(MessagePackObjectTest, NestedEmpty)
-{
-    json j = json::parse("{\"a\": {\"b\": {\"c\": {}}}}");
-    std::vector<uint8_t> expected = {0x81,0xa1,0x61,0x81,0xa1,0x62,0x81,0xa1,0x63,0x80};
-    const auto result = json::to_msgpack(j);
-    EXPECT_EQ(result, expected);
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// map 16
-TEST(MessagePackObjectTest, UInt16)
-{
-    json j = R"({"00": null, "01": null, "02": null, "03": null,
-                 "04": null, "05": null, "06": null, "07": null,
-                 "08": null, "09": null, "10": null, "11": null,
-                 "12": null, "13": null, "14": null, "15": null})"_json;
-
-    const auto result = json::to_msgpack(j);
-
-    // Checking against an expected vector byte by byte is
-    // difficult, because no assumption on the order of key/value
-    // pairs are made. We therefore only check the prefix (type and
-    // size and the overall size. The rest is then handled in the
-    // roundtrip check.
-    EXPECT_EQ(result.size(), 67u); // 1 type, 2 size, 16*4 content
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xde)); // map 16
-    EXPECT_EQ(result[1], 0x00); // byte 0 of size (0x0010)
-    EXPECT_EQ(result[2], 0x10); // byte 1 of size (0x0010)
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// map 32
-TEST(MessagePackObjectTest, UInt32)
-{
-    json j;
-    for (auto i = 0; i < 65536; ++i)
-    {
-        // format i to a fixed width of 5
-        // each entry will need 7 bytes: 6 for fixstr, 1 for null
-        std::stringstream ss;
-        ss << std::setw(5) << std::setfill('0') << i;
-        j.emplace(ss.str(), nullptr);
-    }
-
-    const auto result = json::to_msgpack(j);
-
-    // Checking against an expected vector byte by byte is
-    // difficult, because no assumption on the order of key/value
-    // pairs are made. We therefore only check the prefix (type and
-    // size and the overall size. The rest is then handled in the
-    // roundtrip check.
-    EXPECT_EQ(result.size(), 458757u); // 1 type, 4 size, 65536*7 content
-    EXPECT_EQ(result[0], static_cast<uint8_t>(0xdf)); // map 32
-    EXPECT_EQ(result[1], 0x00); // byte 0 of size (0x00010000)
-    EXPECT_EQ(result[2], 0x01); // byte 1 of size (0x00010000)
-    EXPECT_EQ(result[3], 0x00); // byte 2 of size (0x00010000)
-    EXPECT_EQ(result[4], 0x00); // byte 3 of size (0x00010000)
-
-    // roundtrip
-    EXPECT_EQ(json::from_msgpack(result), j);
-}
-
-// from float32
-TEST(MessagePackFloat32Test, Case)
-{
-    auto given = std::vector<uint8_t>({0xca,0x41,0xc8,0x00,0x01});
-    json j = json::from_msgpack(given);
-    EXPECT_LT(std::fabs(j.get<double>() - 25), 0.001);
-}
-
-TEST(MessagePackErrorTest, TooShortByteVector)
-{
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcc})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcd})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcd,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 3: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xce})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xce,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 3: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xce,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 4: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xce,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 5: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 2: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 3: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 4: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 5: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 6: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 7: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00,0x00,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 8: unexpected end of input");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x00})), json::parse_error,
-                     "[json.exception.parse_error.110] parse error at 9: unexpected end of input");
-}
-
-TEST(MessagePackErrorTest, UnsupportedBytesConcrete)
-{
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xc1})), json::parse_error,
-                     "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xc1");
-    EXPECT_THROW_MSG(json::from_msgpack(std::vector<uint8_t>({0xc6})), json::parse_error,
-                     "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xc6");
-}
-
-TEST(MessagePackErrorTest, UnsupportedBytesAll)
-{
-    for (auto byte :
-            {
-                // never used
-                0xc1,
-                // bin
-                0xc4, 0xc5, 0xc6,
-                // ext
-                0xc7, 0xc8, 0xc9,
-                // fixext
-                0xd4, 0xd5, 0xd6, 0xd7, 0xd8
-            })
-    {
-        EXPECT_THROW(json::from_msgpack(std::vector<uint8_t>({static_cast<uint8_t>(byte)})), json::parse_error);
-    }
-}
-#if 0
-// use this testcase outside [hide] to run it with Valgrind
-TEST(MessagePackRoundtripTest, Sample)
-{
-    std::string filename = "test/data/json_testsuite/sample.json";
-
-    // parse JSON file
-    std::ifstream f_json(filename);
-    json j1 = json::parse(f_json);
-
-    // parse MessagePack file
-    std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
-    std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_msgpack)),
-                                std::istreambuf_iterator<char>());
-    json j2;
-    EXPECT_NO_THROW(j2 = json::from_msgpack(packed));
-
-    // compare parsed JSON values
-    EXPECT_EQ(j1, j2);
-
-    // check with different start index
-    packed.insert(packed.begin(), 5, 0xff);
-    EXPECT_EQ(j1, json::from_msgpack(packed, 5));
-}
-
-class MessagePackRegressionTest : public ::testing::TestWithParam<const char*> {};
-TEST_P(MessagePackRegressionTest, Case)
-{
-    // parse JSON file
-    std::ifstream f_json(GetParam());
-    json j1 = json::parse(f_json);
-
-    // parse MessagePack file
-    std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
-    std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_msgpack)),
-                                std::istreambuf_iterator<char>());
-    json j2;
-    EXPECT_NO_THROW(j2 = json::from_msgpack(packed));
-
-    // compare parsed JSON values
-    EXPECT_EQ(j1, j2);
-}
-
-static const char* regression_test_cases[] = {
-    "test/data/json_nlohmann_tests/all_unicode.json",
-    "test/data/json.org/1.json",
-    "test/data/json.org/2.json",
-    "test/data/json.org/3.json",
-    "test/data/json.org/4.json",
-    "test/data/json.org/5.json",
-    "test/data/json_roundtrip/roundtrip01.json",
-    "test/data/json_roundtrip/roundtrip02.json",
-    "test/data/json_roundtrip/roundtrip03.json",
-    "test/data/json_roundtrip/roundtrip04.json",
-    "test/data/json_roundtrip/roundtrip05.json",
-    "test/data/json_roundtrip/roundtrip06.json",
-    "test/data/json_roundtrip/roundtrip07.json",
-    "test/data/json_roundtrip/roundtrip08.json",
-    "test/data/json_roundtrip/roundtrip09.json",
-    "test/data/json_roundtrip/roundtrip10.json",
-    "test/data/json_roundtrip/roundtrip11.json",
-    "test/data/json_roundtrip/roundtrip12.json",
-    "test/data/json_roundtrip/roundtrip13.json",
-    "test/data/json_roundtrip/roundtrip14.json",
-    "test/data/json_roundtrip/roundtrip15.json",
-    "test/data/json_roundtrip/roundtrip16.json",
-    "test/data/json_roundtrip/roundtrip17.json",
-    "test/data/json_roundtrip/roundtrip18.json",
-    "test/data/json_roundtrip/roundtrip19.json",
-    "test/data/json_roundtrip/roundtrip20.json",
-    "test/data/json_roundtrip/roundtrip21.json",
-    "test/data/json_roundtrip/roundtrip22.json",
-    "test/data/json_roundtrip/roundtrip23.json",
-    "test/data/json_roundtrip/roundtrip24.json",
-    "test/data/json_roundtrip/roundtrip25.json",
-    "test/data/json_roundtrip/roundtrip26.json",
-    "test/data/json_roundtrip/roundtrip27.json",
-    "test/data/json_roundtrip/roundtrip28.json",
-    "test/data/json_roundtrip/roundtrip29.json",
-    "test/data/json_roundtrip/roundtrip30.json",
-    "test/data/json_roundtrip/roundtrip31.json",
-    "test/data/json_roundtrip/roundtrip32.json",
-    "test/data/json_testsuite/sample.json", // kills AppVeyor
-    "test/data/json_tests/pass1.json",
-    "test/data/json_tests/pass2.json",
-    "test/data/json_tests/pass3.json",
-    "test/data/regression/floats.json",
-    "test/data/regression/signed_ints.json",
-    "test/data/regression/unsigned_ints.json",
-    "test/data/regression/working_file.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_arraysWithSpaces.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_empty-string.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_empty.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_ending_with_newline.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_false.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_heterogeneous.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_null.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_1_and_newline.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_leading_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_several_null.json",
-    "test/data/nst_json_testsuite/test_parsing/y_array_with_trailing_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_0e+1.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_0e1.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_after_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_double_close_to_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_double_huge_neg_exp.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_huge_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_int_with_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_minus_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_negative_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_negative_one.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_negative_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_capital_e.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_capital_e_neg_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_capital_e_pos_exp.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_exponent.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_fraction_exponent.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_neg_exp.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_real_neg_overflow.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_pos_exponent.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_real_pos_overflow.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_real_underflow.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_simple_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_number_simple_real.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_too_big_neg_int.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_too_big_pos_int.json",
-    //"test/data/nst_json_testsuite/test_parsing/y_number_very_big_negative_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_basic.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_duplicated_key.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_duplicated_key_and_value.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_empty.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_empty_key.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_escaped_null_in_key.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_extreme_numbers.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_long_strings.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_simple.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_string_unicode.json",
-    "test/data/nst_json_testsuite/test_parsing/y_object_with_newlines.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_UTF-16_Surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_accepted_surrogate_pair.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_accepted_surrogate_pairs.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_allowed_escapes.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_backslash_and_u_escaped_zero.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_backslash_doublequotes.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_comments.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_double_escape_a.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_double_escape_n.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_escaped_control_character.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_escaped_noncharacter.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_in_array.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_in_array_with_leading_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_last_surrogates_1_and_2.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_newline_uescaped.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_nonCharacterInUTF-8_U+1FFFF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_null_escape.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_one-byte-utf-8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_pi.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_simple_ascii.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_space.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_three-byte-utf-8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_two-byte-utf-8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_u+2028_line_sep.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_u+2029_par_sep.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_uEscape.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unescaped_char_delete.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicodeEscapedBackslash.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_2.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_U+2064_invisible_plus.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_unicode_escaped_double_quote.json",
-    // "test/data/nst_json_testsuite/test_parsing/y_string_utf16.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_utf8.json",
-    "test/data/nst_json_testsuite/test_parsing/y_string_with_del_character.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_false.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_int.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_negative_real.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_null.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_string.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_lonely_true.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_string_empty.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_trailing_newline.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_true_in_array.json",
-    "test/data/nst_json_testsuite/test_parsing/y_structure_whitespace_array.json",
-};
-
-INSTANTIATE_TEST_SUITE_P(MessagePackRegressionTests, MessagePackRegressionTest,
-                        ::testing::ValuesIn(regression_test_cases));
-#endif
diff --git a/wpiutil/src/test/native/cpp/json/unit-pointer_access.cpp b/wpiutil/src/test/native/cpp/json/unit-pointer_access.cpp
deleted file mode 100644
index 3224b05..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-pointer_access.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-
-#include <cmath>
-
-using wpi::json;
-
-TEST(JsonPointerTest, TypesCreate)
-{
-    // create a JSON value with different types
-    json json_types =
-    {
-        {"boolean", true},
-        {
-            "number", {
-                {"integer", 42},
-                {"unsigned", 42u},
-                {"floating-point", 17.23}
-            }
-        },
-        {"string", "Hello, world!"},
-        {"array", {1, 2, 3, 4, 5}},
-        {"null", nullptr}
-    };
-}
-
-// pointer access to object_t
-TEST(JsonPointerTest, ObjectT)
-{
-    using test_type = json::object_t;
-    json value = {{"one", 1}, {"two", 2}};
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_NE(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const object_t
-TEST(JsonPointerTest, ConstObjectT)
-{
-    using test_type = const json::object_t;
-    const json value = {{"one", 1}, {"two", 2}};
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_NE(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const double*>(), nullptr);
-}
-
-// pointer access to array_t
-TEST(JsonPointerTest, ArrayT)
-{
-    using test_type = json::array_t;
-    json value = {1, 2, 3, 4};
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const array_t
-TEST(JsonPointerTest, ConstArrayT)
-{
-    using test_type = const json::array_t;
-    const json value = {1, 2, 3, 4};
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const double*>(), nullptr);
-}
-
-// pointer access to string_t
-TEST(JsonPointerTest, StringT)
-{
-    using test_type = std::string;
-    json value = "hello";
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const string_t
-TEST(JsonPointerTest, ConstStringT)
-{
-    using test_type = const std::string;
-    const json value = "hello";
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const double*>(), nullptr);
-}
-
-// pointer access to boolean_t
-TEST(JsonPointerTest, BooleanT)
-{
-    using test_type = bool;
-    json value = false;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_NE(value.get_ptr<bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const boolean_t
-TEST(JsonPointerTest, ConstBooleanT)
-{
-    using test_type = const bool;
-    const json value = false;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    //EXPECT_EQ(*p1, value.get<test_type>());
-
-    //const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    //EXPECT_EQ(*p2, value.get<test_type>());
-
-    //const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    //EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const double*>(), nullptr);
-}
-
-// pointer access to number_integer_t
-TEST(JsonPointerTest, IntegerT)
-{
-    using test_type = int64_t;
-    json value = 23;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<bool*>(), nullptr);
-    EXPECT_NE(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const number_integer_t
-TEST(JsonPointerTest, ConstIntegerT)
-{
-    using test_type = const int64_t;
-    const json value = 23;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const double*>(), nullptr);
-}
-
-// pointer access to number_unsigned_t
-TEST(JsonPointerTest, UnsignedT)
-{
-    using test_type = uint64_t;
-    json value = 23u;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<bool*>(), nullptr);
-    EXPECT_NE(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const number_unsigned_t
-TEST(JsonPointerTest, ConstUnsignedT)
-{
-    using test_type = const uint64_t;
-    const json value = 23u;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(*p1, value.get<test_type>());
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_EQ(*p2, value.get<test_type>());
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_EQ(*p3, value.get<test_type>());
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const double*>(), nullptr);
-}
-
-// pointer access to number_float_t
-TEST(JsonPointerTest, FloatT)
-{
-    using test_type = double;
-    json value = 42.23;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_LT(std::fabs(*p1 - value.get<test_type>()), 0.001);
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_LT(std::fabs(*p2 - value.get<test_type>()), 0.001);
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_LT(std::fabs(*p3 - value.get<test_type>()), 0.001);
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<uint64_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<double*>(), nullptr);
-}
-
-// pointer access to const number_float_t
-TEST(JsonPointerTest, ConstFloatT)
-{
-    using test_type = const double;
-    const json value = 42.23;
-
-    // check if pointers are returned correctly
-    test_type* p1 = value.get_ptr<test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<test_type*>());
-    EXPECT_LT(std::fabs(*p1 - value.get<test_type>()), 0.001);
-
-    const test_type* p2 = value.get_ptr<const test_type*>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type*>());
-    EXPECT_LT(std::fabs(*p2 - value.get<test_type>()), 0.001);
-
-    const test_type* const p3 = value.get_ptr<const test_type* const>();
-    EXPECT_EQ(p1, value.get_ptr<const test_type* const>());
-    EXPECT_LT(std::fabs(*p3 - value.get<test_type>()), 0.001);
-
-    // check if null pointers are returned correctly
-    EXPECT_EQ(value.get_ptr<const json::object_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const json::array_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const std::string*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const bool*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const int64_t*>(), nullptr);
-    EXPECT_EQ(value.get_ptr<const uint64_t*>(), nullptr);
-    EXPECT_NE(value.get_ptr<const double*>(), nullptr);
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-readme.cpp b/wpiutil/src/test/native/cpp/json/unit-readme.cpp
deleted file mode 100644
index d9bb9e5..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-readme.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-#include <array>
-#include <deque>
-#include <forward_list>
-#include <list>
-#include <map>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "wpi/raw_ostream.h"
-
-TEST(JsonReadmeTest, Basic)
-{
-    // create an empty structure (null)
-    json j;
-
-    // add a number that is stored as double (note the implicit conversion of j to an object)
-    j["pi"] = 3.141;
-
-    // add a Boolean that is stored as bool
-    j["happy"] = true;
-
-    // add a string that is stored as std::string
-    j["name"] = "Niels";
-
-    // add another null object by passing nullptr
-    j["nothing"] = nullptr;
-
-    // add an object inside the object
-    j["answer"]["everything"] = 42;
-
-    // add an array that is stored as std::vector (using an initializer list)
-    j["list"] = { 1, 0, 2 };
-
-    // add another object (using an initializer list of pairs)
-    j["object"] = { {"currency", "USD"}, {"value", 42.99} };
-
-    // instead, you could also write (which looks very similar to the JSON above)
-    json j2 =
-    {
-        {"pi", 3.141},
-        {"happy", true},
-        {"name", "Niels"},
-        {"nothing", nullptr},
-        {
-            "answer", {
-                {"everything", 42}
-            }
-        },
-        {"list", {1, 0, 2}},
-        {
-            "object", {
-                {"currency", "USD"},
-                {"value", 42.99}
-            }
-        }
-    };
-}
-
-TEST(JsonReadmeTest, Other)
-{
-    // ways to express the empty array []
-    json empty_array_implicit = {{}};
-    json empty_array_explicit = json::array();
-
-    // a way to express the empty object {}
-    json empty_object_explicit = json::object();
-
-    // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
-    json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) };
-}
-
-TEST(JsonReadmeTest, FromToString)
-{
-    // create object from string literal
-    json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
-
-    // or even nicer with a raw string literal
-    auto j2 = R"(
-  {
-    "happy": true,
-    "pi": 3.141
-  }
-)"_json;
-
-    // or explicitly
-    auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
-
-    // explicit conversion to string
-    std::string s;
-    wpi::raw_string_ostream os(s);
-    j.dump(os);    // {\"happy\":true,\"pi\":3.141}
-    EXPECT_EQ(os.str(), "{\"happy\":true,\"pi\":3.141}");
-
-    // serialization with pretty printing
-    // pass in the amount of spaces to indent
-    std::string s2;
-    wpi::raw_string_ostream os2(s2);
-    j2.dump(os2, 4);
-    EXPECT_EQ(os2.str(), "{\n    \"happy\": true,\n    \"pi\": 3.141\n}");
-    // {
-    //     "happy": true,
-    //     "pi": 3.141
-    // }
-}
-
-TEST(JsonReadmeTest, Basic2)
-{
-    // create an array using push_back
-    json j;
-    j.push_back("foo");
-    j.push_back(1);
-    j.push_back(true);
-
-    std::string s;
-    wpi::raw_string_ostream os(s);
-
-    // iterate the array
-    for (json::iterator it = j.begin(); it != j.end(); ++it)
-    {
-        os << *it << '\n';
-    }
-
-    // range-based for
-    for (auto element : j)
-    {
-        os << element << '\n';
-    }
-
-    // comparison
-    bool x = (j == "[\"foo\", 1, true]"_json);  // true
-    EXPECT_EQ(x, true);
-
-    // getter/setter
-    const std::string tmp = j[0];
-    j[1] = 42;
-    bool foo = j.at(2);
-    EXPECT_EQ(foo, true);
-
-    // other stuff
-    EXPECT_EQ(j.size(), 3u);        // 3 entries
-    EXPECT_EQ(j.empty(), false);
-    EXPECT_EQ(j.type(), json::value_t::array);
-    j.clear();    // the array is empty again
-    EXPECT_EQ(j.size(), 0u);
-    EXPECT_EQ(j.empty(), true);
-
-    // create an object
-    json o;
-    o["foo"] = 23;
-    o["bar"] = false;
-    o["baz"] = 3.141;
-
-    // find an entry
-    if (o.find("foo") != o.end())
-    {
-        // there is an entry with key "foo"
-    }
-}
-
-TEST(JsonReadmeTest, OtherContainer)
-{
-    std::vector<int> c_vector {1, 2, 3, 4};
-    json j_vec(c_vector);
-    json j_vec2(std::span<const int>(c_vector.data(), c_vector.size()));
-    // [1, 2, 3, 4]
-
-    std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
-    json j_deque(c_deque);
-    // [1.2, 2.3, 3.4, 5.6]
-
-    std::list<bool> c_list {true, true, false, true};
-    json j_list(c_list);
-    // [true, true, false, true]
-
-    std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
-    json j_flist(c_flist);
-    // [12345678909876, 23456789098765, 34567890987654, 45678909876543]
-
-    std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
-    json j_array(c_array);
-    // [1, 2, 3, 4]
-
-    std::set<std::string> c_set {"one", "two", "three", "four", "one"};
-    json j_set(c_set); // only one entry for "one" is used
-    // ["four", "one", "three", "two"]
-
-    std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
-    json j_uset(c_uset); // only one entry for "one" is used
-    // maybe ["two", "three", "four", "one"]
-
-    std::multiset<std::string> c_mset {"one", "two", "one", "four"};
-    json j_mset(c_mset); // both entries for "one" are used
-    // maybe ["one", "two", "one", "four"]
-
-    std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
-    json j_umset(c_umset); // both entries for "one" are used
-    // maybe ["one", "two", "one", "four"]
-}
-
-TEST(JsonReadmeTest, MapContainer)
-{
-    std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
-    json j_map(c_map);
-    // {"one": 1, "two": 2, "three": 3}
-
-#if 0
-    std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
-    json j_umap(c_umap);
-    // {"one": 1.2, "two": 2.3, "three": 3.4}
-#endif
-
-    std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
-    json j_mmap(c_mmap); // only one entry for key "three" is used
-    // maybe {"one": true, "two": true, "three": true}
-
-    std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
-    json j_ummap(c_ummap); // only one entry for key "three" is used
-    // maybe {"one": true, "two": true, "three": true}
-}
-
-TEST(JsonReadmeTest, Values)
-{
-    // strings
-    std::string s1 = "Hello, world!";
-    json js = s1;
-    std::string s2 = js;
-    EXPECT_EQ(s1, s2);
-
-    // Booleans
-    bool b1 = true;
-    json jb = b1;
-    bool b2 = jb;
-    EXPECT_EQ(b1, b2);
-
-    // numbers
-    int i = 42;
-    json jn = i;
-    double f = jn;
-    EXPECT_EQ(i, f);
-
-    // etc.
-
-    std::string vs = js.get<std::string>();
-    bool vb = jb.get<bool>();
-    int vi = jn.get<int>();
-    EXPECT_EQ(s1, vs);
-    EXPECT_EQ(b1, vb);
-    EXPECT_EQ(i, vi);
-
-    // etc.
-}
-
-#if 0
-TEST(JsonReadmeTest, DiffPatch)
-{
-    // a JSON value
-    json j_original = R"({
-  "baz": ["one", "two", "three"],
-  "foo": "bar"
-})"_json;
-
-    // access members with a JSON pointer (RFC 6901)
-    j_original["/baz/1"_json_pointer];
-    // "two"
-
-    // a JSON patch (RFC 6902)
-    json j_patch = R"([
-  { "op": "replace", "path": "/baz", "value": "boo" },
-  { "op": "add", "path": "/hello", "value": ["world"] },
-  { "op": "remove", "path": "/foo"}
-])"_json;
-
-    // apply the patch
-    json j_result = j_original.patch(j_patch);
-    // {
-    //    "baz": "boo",
-    //    "hello": ["world"]
-    // }
-
-    // calculate a JSON patch from two JSON values
-    json::diff(j_result, j_original);
-    // [
-    //   { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
-    //   { "op":"remove","path":"/hello" },
-    //   { "op":"add","path":"/foo","value":"bar" }
-    // ]
-}
-#endif
diff --git a/wpiutil/src/test/native/cpp/json/unit-reference_access.cpp b/wpiutil/src/test/native/cpp/json/unit-reference_access.cpp
deleted file mode 100644
index 7c3cfb1..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-reference_access.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-// reference access to object_t
-TEST(JsonReferenceTest, ObjectT)
-{
-    using test_type = json::object_t;
-    json value = {{"one", 1}, {"two", 2}};
-
-    // check if references are returned correctly
-    test_type& p1 = value.get_ref<test_type&>();
-    EXPECT_EQ(&p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(p1, value.get<test_type>());
-
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-
-    // check if mismatching references throw correctly
-    EXPECT_NO_THROW(value.get_ref<json::object_t&>());
-    EXPECT_ANY_THROW(value.get_ref<json::array_t&>());
-    EXPECT_ANY_THROW(value.get_ref<std::string&>());
-    EXPECT_ANY_THROW(value.get_ref<bool&>());
-    EXPECT_ANY_THROW(value.get_ref<int64_t&>());
-    EXPECT_ANY_THROW(value.get_ref<double&>());
-}
-
-// const reference access to const object_t
-TEST(JsonReferenceTest, ConstObjectT)
-{
-    using test_type = json::object_t;
-    const json value = {{"one", 1}, {"two", 2}};
-
-    // this should not compile
-    // test_type& p1 = value.get_ref<test_type&>();
-
-    // check if references are returned correctly
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-}
-
-// reference access to array_t
-TEST(JsonReferenceTest, ArrayT)
-{
-    using test_type = json::array_t;
-    json value = {1, 2, 3, 4};
-
-    // check if references are returned correctly
-    test_type& p1 = value.get_ref<test_type&>();
-    EXPECT_EQ(&p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(p1, value.get<test_type>());
-
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-
-    // check if mismatching references throw correctly
-    EXPECT_ANY_THROW(value.get_ref<json::object_t&>());
-    EXPECT_NO_THROW(value.get_ref<json::array_t&>());
-    EXPECT_ANY_THROW(value.get_ref<std::string&>());
-    EXPECT_ANY_THROW(value.get_ref<bool&>());
-    EXPECT_ANY_THROW(value.get_ref<int64_t&>());
-    EXPECT_ANY_THROW(value.get_ref<double&>());
-}
-
-// reference access to string_t
-TEST(JsonReferenceTest, StringT)
-{
-    using test_type = std::string;
-    json value = "hello";
-
-    // check if references are returned correctly
-    test_type& p1 = value.get_ref<test_type&>();
-    EXPECT_EQ(&p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(p1, value.get<test_type>());
-
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-
-    // check if mismatching references throw correctly
-    EXPECT_ANY_THROW(value.get_ref<json::object_t&>());
-    EXPECT_ANY_THROW(value.get_ref<json::array_t&>());
-    EXPECT_NO_THROW(value.get_ref<std::string&>());
-    EXPECT_ANY_THROW(value.get_ref<bool&>());
-    EXPECT_ANY_THROW(value.get_ref<int64_t&>());
-    EXPECT_ANY_THROW(value.get_ref<double&>());
-}
-
-// reference access to boolean_t
-TEST(JsonReferenceTest, BooleanT)
-{
-    using test_type = bool;
-    json value = false;
-
-    // check if references are returned correctly
-    test_type& p1 = value.get_ref<test_type&>();
-    EXPECT_EQ(&p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(p1, value.get<test_type>());
-
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-
-    // check if mismatching references throw correctly
-    EXPECT_ANY_THROW(value.get_ref<json::object_t&>());
-    EXPECT_ANY_THROW(value.get_ref<json::array_t&>());
-    EXPECT_ANY_THROW(value.get_ref<std::string&>());
-    EXPECT_NO_THROW(value.get_ref<bool&>());
-    EXPECT_ANY_THROW(value.get_ref<int64_t&>());
-    EXPECT_ANY_THROW(value.get_ref<double&>());
-}
-
-// reference access to number_integer_t
-TEST(JsonReferenceTest, IntegerT)
-{
-    using test_type = int64_t;
-    json value = 23;
-
-    // check if references are returned correctly
-    test_type& p1 = value.get_ref<test_type&>();
-    EXPECT_EQ(&p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(p1, value.get<test_type>());
-
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-
-    // check if mismatching references throw correctly
-    EXPECT_ANY_THROW(value.get_ref<json::object_t&>());
-    EXPECT_ANY_THROW(value.get_ref<json::array_t&>());
-    EXPECT_ANY_THROW(value.get_ref<std::string&>());
-    EXPECT_ANY_THROW(value.get_ref<bool&>());
-    EXPECT_NO_THROW(value.get_ref<int64_t&>());
-    EXPECT_ANY_THROW(value.get_ref<double&>());
-}
-
-// reference access to number_float_t
-TEST(JsonReferenceTest, FloatT)
-{
-    using test_type = double;
-    json value = 42.23;
-
-    // check if references are returned correctly
-    test_type& p1 = value.get_ref<test_type&>();
-    EXPECT_EQ(&p1, value.get_ptr<test_type*>());
-    EXPECT_EQ(p1, value.get<test_type>());
-
-    const test_type& p2 = value.get_ref<const test_type&>();
-    EXPECT_EQ(&p2, value.get_ptr<const test_type*>());
-    EXPECT_EQ(p2, value.get<test_type>());
-
-    // check if mismatching references throw correctly
-    EXPECT_ANY_THROW(value.get_ref<json::object_t&>());
-    EXPECT_ANY_THROW(value.get_ref<json::array_t&>());
-    EXPECT_ANY_THROW(value.get_ref<std::string&>());
-    EXPECT_ANY_THROW(value.get_ref<bool&>());
-    EXPECT_ANY_THROW(value.get_ref<int64_t&>());
-    EXPECT_NO_THROW(value.get_ref<double&>());
-}
diff --git a/wpiutil/src/test/native/cpp/json/unit-unicode.cpp b/wpiutil/src/test/native/cpp/json/unit-unicode.cpp
deleted file mode 100644
index 6755fe2..0000000
--- a/wpiutil/src/test/native/cpp/json/unit-unicode.cpp
+++ /dev/null
@@ -1,1089 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Modifications Copyright (c) FIRST 2017. All Rights Reserved.               */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-/*
-    __ _____ _____ _____
- __|  |   __|     |   | |  JSON for Modern C++ (test suite)
-|  |  |__   |  |  | | | |  version 2.1.1
-|_____|_____|_____|_|___|  https://github.com/nlohmann/json
-
-Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
-
-Permission is hereby  granted, free of charge, to any  person obtaining a copy
-of this software and associated  documentation files (the "Software"), to deal
-in the Software  without restriction, including without  limitation the rights
-to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
-copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
-IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
-FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
-AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
-LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#include "gtest/gtest.h"
-
-#include "unit-json.h"
-using wpi::json;
-
-#include "fmt/format.h"
-#include "wpi/StringExtras.h"
-#include "wpi/raw_ostream.h"
-
-#include <fstream>
-
-// create and check a JSON string with up to four UTF-8 bytes
-::testing::AssertionResult check_utf8string(bool success_expected, int byte1, int byte2 = -1, int byte3 = -1, int byte4 = -1)
-{
-    std::string json_string = "\"";
-
-    json_string += std::string(1, static_cast<char>(byte1));
-
-    if (byte2 != -1)
-    {
-        json_string += std::string(1, static_cast<char>(byte2));
-    }
-
-    if (byte3 != -1)
-    {
-        json_string += std::string(1, static_cast<char>(byte3));
-    }
-
-    if (byte4 != -1)
-    {
-        json_string += std::string(1, static_cast<char>(byte4));
-    }
-
-    json_string += "\"";
-
-    const char* basemsg = "";
-
-    try {
-        json::parse(json_string);
-    } catch (json::parse_error&) {
-        if (success_expected)
-        {
-            basemsg = "parse_error";
-            goto error;
-        }
-        return ::testing::AssertionSuccess();
-    } catch (...) {
-        basemsg = "other exception";
-        goto error;
-    }
-
-    if (success_expected)
-    {
-        return ::testing::AssertionSuccess();
-    }
-    basemsg = "expected failure";
-
-error:
-    auto result = ::testing::AssertionFailure();
-    result << basemsg << " with {" << wpi::utohexstr(byte1);
-    if (byte2 != -1)
-    {
-        result << ',' << wpi::utohexstr(byte2);
-    }
-    if (byte3 != -1)
-    {
-        result << ',' << wpi::utohexstr(byte3);
-    }
-    if (byte4 != -1)
-    {
-        result << ',' << wpi::utohexstr(byte4);
-    }
-    result << '}';
-    return result;
-}
-
-/*
-RFC 3629 describes in Sect. 4 the syntax of UTF-8 byte sequences as
-follows:
-
-    A UTF-8 string is a sequence of octets representing a sequence of UCS
-    characters.  An octet sequence is valid UTF-8 only if it matches the
-    following syntax, which is derived from the rules for encoding UTF-8
-    and is expressed in the ABNF of [RFC2234].
-
-    UTF8-octets = *( UTF8-char )
-    UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
-    UTF8-1      = %x00-7F
-    UTF8-2      = %xC2-DF UTF8-tail
-    UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
-                  %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
-    UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
-                  %xF4 %x80-8F 2( UTF8-tail )
-    UTF8-tail   = %x80-BF
-*/
-
-// ill-formed first byte
-TEST(JsonUnicodeRfc3629Test, IllFormedFirstByte)
-{
-    for (int byte1 = 0x80; byte1 <= 0xC1; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-
-    for (int byte1 = 0xF5; byte1 <= 0xFF; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// UTF8-1 (x00-x7F), well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_1WellFormed)
-{
-    for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1)
-    {
-        // unescaped control characters are parse errors in JSON
-        if (0x00 <= byte1 && byte1 <= 0x1F)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1));
-            continue;
-        }
-
-        // a single quote is a parse error in JSON
-        if (byte1 == 0x22)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1));
-            continue;
-        }
-
-        // a single backslash is a parse error in JSON
-        if (byte1 == 0x5C)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1));
-            continue;
-        }
-
-        // all other characters are OK
-        EXPECT_TRUE(check_utf8string(true, byte1));
-    }
-}
-
-// UTF8-2 (xC2-xDF UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_2WellFormed)
-{
-    for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(true, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_2Missing2)
-{
-    for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_2Wrong2)
-{
-    for (int byte1 = 0xC2; byte1 <= 0xDF; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x80 <= byte2 && byte2 <= 0xBF)
-            {
-                continue;
-            }
-
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// UTF8-3 (xE0 xA0-BF UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_3AWellFormed)
-{
-    for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
-    {
-        for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3AMissing2)
-{
-    for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3AMissing3)
-{
-    for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
-    {
-        for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3AWrong2)
-{
-    for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0xA0 <= byte2 && byte2 <= 0xBF)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3AWrong3)
-{
-    for (int byte1 = 0xE0; byte1 <= 0xE0; ++byte1)
-    {
-        for (int byte2 = 0xA0; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// UTF8-3 (xE1-xEC UTF8-tail UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_3BWellFormed)
-{
-    for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3BMissing2)
-{
-    for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3BMissing3)
-{
-    for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_3BWrong2)
-{
-    for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x80 <= byte2 && byte2 <= 0xBF)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_3BWrong3)
-{
-    for (int byte1 = 0xE1; byte1 <= 0xEC; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// UTF8-3 (xED x80-9F UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_3CWellFormed)
-{
-    for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3CMissing2)
-{
-    for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3CMissing3)
-{
-    for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3CWrong2)
-{
-    for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x80 <= byte2 && byte2 <= 0x9F)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3CWrong3)
-{
-    for (int byte1 = 0xED; byte1 <= 0xED; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x9F; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// UTF8-3 (xEE-xEF UTF8-tail UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_3DWellFormed)
-{
-    for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3DMissing2)
-{
-    for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3DMissing3)
-{
-    for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3DWrong2)
-{
-    for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x80 <= byte2 && byte2 <= 0xBF)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_3DWrong3)
-{
-    for (int byte1 = 0xEE; byte1 <= 0xEF; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// UTF8-4 (xF0 x90-BF UTF8-tail UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_4AWellFormed)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4AMissing2)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4AMissing3)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: missing fourth byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4AMissing4)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_4AWrong2)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x90 <= byte2 && byte2 <= 0xBF)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_4AWrong3)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: wrong fourth byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4AWrong4)
-{
-    for (int byte1 = 0xF0; byte1 <= 0xF0; ++byte1)
-    {
-        for (int byte2 = 0x90; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4)
-                {
-                    // skip fourth second byte
-                    if (0x80 <= byte3 && byte3 <= 0xBF)
-                    {
-                        continue;
-                    }
-
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// UTF8-4 (xF1-F3 UTF8-tail UTF8-tail UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_4BWellFormed)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4BMissing2)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4BMissing3)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: missing fourth byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4BMissing4)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_4BWrong2)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x80 <= byte2 && byte2 <= 0xBF)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_4BWrong3)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: wrong fourth byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4BWrong4)
-{
-    for (int byte1 = 0xF1; byte1 <= 0xF3; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0xBF; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4)
-                {
-                    // skip correct fourth byte
-                    if (0x80 <= byte3 && byte3 <= 0xBF)
-                    {
-                        continue;
-                    }
-
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// UTF8-4 (xF4 x80-8F UTF8-tail UTF8-tail)
-// well-formed
-TEST(JsonUnicodeRfc3629Test, Utf8_4CWellFormed)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(true, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: missing second byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4CMissing2)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        EXPECT_TRUE(check_utf8string(false, byte1));
-    }
-}
-
-// ill-formed: missing third byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4CMissing3)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2)
-        {
-            EXPECT_TRUE(check_utf8string(false, byte1, byte2));
-        }
-    }
-}
-
-// ill-formed: missing fourth byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4CMissing4)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3));
-            }
-        }
-    }
-}
-
-// ill-formed: wrong second byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_4CWrong2)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
-        {
-            // skip correct second byte
-            if (0x80 <= byte2 && byte2 <= 0x8F)
-            {
-                continue;
-            }
-
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: wrong third byte
-TEST(JsonUnicodeRfc3629Test, DISABLED_Utf8_4CWrong3)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2)
-        {
-            for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
-            {
-                // skip correct third byte
-                if (0x80 <= byte3 && byte3 <= 0xBF)
-                {
-                    continue;
-                }
-
-                for (int byte4 = 0x80; byte4 <= 0xBF; ++byte4)
-                {
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// ill-formed: wrong fourth byte
-TEST(JsonUnicodeRfc3629Test, Utf8_4CWrong4)
-{
-    for (int byte1 = 0xF4; byte1 <= 0xF4; ++byte1)
-    {
-        for (int byte2 = 0x80; byte2 <= 0x8F; ++byte2)
-        {
-            for (int byte3 = 0x80; byte3 <= 0xBF; ++byte3)
-            {
-                for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4)
-                {
-                    // skip correct fourth byte
-                    if (0x80 <= byte3 && byte3 <= 0xBF)
-                    {
-                        continue;
-                    }
-
-                    EXPECT_TRUE(check_utf8string(false, byte1, byte2, byte3, byte4));
-                }
-            }
-        }
-    }
-}
-
-// \\uxxxx sequences
-
-// create an escaped string from a code point
-static std::string codepoint_to_unicode(std::size_t cp)
-{
-    // code points are represented as a six-character sequence: a
-    // reverse solidus, followed by the lowercase letter u, followed
-    // by four hexadecimal digits that encode the character's code
-    // point
-    return fmt::format("\\u{:04x}", cp);
-}
-
-// correct sequences
-TEST(JsonUnicodeCodepointTest, DISABLED_Correct)
-{
-    // generate all UTF-8 code points; in total, 1112064 code points are
-    // generated: 0x1FFFFF code points - 2048 invalid values between
-    // 0xD800 and 0xDFFF.
-    for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp)
-    {
-        // string to store the code point as in \uxxxx format
-        std::string json_text = "\"";
-
-        // decide whether to use one or two \uxxxx sequences
-        if (cp < 0x10000u)
-        {
-            // The Unicode standard permanently reserves these code point
-            // values for UTF-16 encoding of the high and low surrogates, and
-            // they will never be assigned a character, so there should be no
-            // reason to encode them. The official Unicode standard says that
-            // no UTF forms, including UTF-16, can encode these code points.
-            if (cp >= 0xD800u && cp <= 0xDFFFu)
-            {
-                // if we would not skip these code points, we would get a
-                // "missing low surrogate" exception
-                continue;
-            }
-
-            // code points in the Basic Multilingual Plane can be
-            // represented with one \uxxxx sequence
-            json_text += codepoint_to_unicode(cp);
-        }
-        else
-        {
-            // To escape an extended character that is not in the Basic
-            // Multilingual Plane, the character is represented as a
-            // 12-character sequence, encoding the UTF-16 surrogate pair
-            const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu);
-            const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu);
-            json_text += codepoint_to_unicode(codepoint1) + codepoint_to_unicode(codepoint2);
-        }
-
-        json_text += "\"";
-        SCOPED_TRACE(json_text);
-        EXPECT_NO_THROW(json::parse(json_text));
-    }
-}
-
-#if 0
-// incorrect sequences
-// high surrogate without low surrogate
-TEST(JsonUnicodeCodepointTest, IncorrectHighMissingLow)
-{
-    // D800..DBFF are high surrogates and must be followed by low
-    // surrogates DC00..DFFF; here, nothing follows
-    for (std::size_t cp = 0xD800u; cp <= 0xDBFFu; ++cp)
-    {
-        std::string json_text = "\"" + codepoint_to_unicode(cp) + "\"";
-        SCOPED_TRACE(json_text);
-        EXPECT_THROW(json::parse(json_text), json::parse_error);
-    }
-}
-
-// high surrogate with wrong low surrogate
-TEST(JsonUnicodeCodepointTest, IncorrectHighWrongLow)
-{
-    // D800..DBFF are high surrogates and must be followed by low
-    // surrogates DC00..DFFF; here a different sequence follows
-    for (std::size_t cp1 = 0xD800u; cp1 <= 0xDBFFu; ++cp1)
-    {
-        for (std::size_t cp2 = 0x0000u; cp2 <= 0xFFFFu; ++cp2)
-        {
-            if (0xDC00u <= cp2 && cp2 <= 0xDFFFu)
-            {
-                continue;
-            }
-
-            std::string json_text = "\"" + codepoint_to_unicode(cp1) + codepoint_to_unicode(cp2) + "\"";
-            SCOPED_TRACE(json_text);
-            EXPECT_THROW(json::parse(json_text), json::parse_error);
-        }
-    }
-}
-
-// low surrogate without high surrogate
-TEST(JsonUnicodeCodepointTest, IncorrectLowMissingHigh)
-{
-    // low surrogates DC00..DFFF must follow high surrogates; here,
-    // they occur alone
-    for (std::size_t cp = 0xDC00u; cp <= 0xDFFFu; ++cp)
-    {
-        std::string json_text = "\"" + codepoint_to_unicode(cp) + "\"";
-        SCOPED_TRACE(json_text);
-        EXPECT_THROW(json::parse(json_text), json::parse_error);
-    }
-}
-#endif
-
-#if 0
-// read all unicode characters
-TEST(JsonUnicodeTest, ReadAllUnicode)
-{
-    // read a file with all unicode characters stored as single-character
-    // strings in a JSON array
-    std::ifstream f("test/data/json_nlohmann_tests/all_unicode.json");
-    json j;
-    CHECK_NOTHROW(f >> j);
-
-    // the array has 1112064 + 1 elemnts (a terminating "null" value)
-    // Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between
-    // 0xD800 and 0xDFFF.
-    CHECK(j.size() == 1112065);
-
-    SECTION("check JSON Pointers")
-    {
-        for (auto s : j)
-        {
-            // skip non-string JSON values
-            if (not s.is_string())
-            {
-                continue;
-            }
-
-            std::string ptr = s;
-
-            // tilde must be followed by 0 or 1
-            if (ptr == "~")
-            {
-                ptr += "0";
-            }
-
-            // JSON Pointers must begin with "/"
-            ptr = "/" + ptr;
-
-            CHECK_NOTHROW(json::json_pointer("/" + ptr));
-
-            // check escape/unescape roundtrip
-            auto escaped = json::json_pointer::escape(ptr);
-            json::json_pointer::unescape(escaped);
-            CHECK(escaped == ptr);
-        }
-    }
-}
-
-// ignore byte-order-mark
-// in a stream
-TEST(JsonUnicodeTest, IgnoreBOMStream)
-{
-    // read a file with a UTF-8 BOM
-    std::ifstream f("test/data/json_nlohmann_tests/bom.json");
-    json j;
-    EXPECT_NO_THROW(f >> j);
-}
-
-// with an iterator
-TEST(JsonUnicodeTest, IgnoreBOMIterator)
-{
-    std::string i = "\xef\xbb\xbf{\n   \"foo\": true\n}";
-    EXPECT_NO_THROW(json::parse(i.begin(), i.end()));
-}
-#endif
-// error for incomplete/wrong BOM
-TEST(JsonUnicodeTest, WrongBOM)
-{
-    EXPECT_THROW(json::parse("\xef\xbb"), json::parse_error);
-    EXPECT_THROW(json::parse("\xef\xbb\xbb"), json::parse_error);
-}
diff --git a/wpiutil/src/test/native/cpp/leb128Test.cpp b/wpiutil/src/test/native/cpp/leb128Test.cpp
index cc537ae..6c78b51 100644
--- a/wpiutil/src/test/native/cpp/leb128Test.cpp
+++ b/wpiutil/src/test/native/cpp/leb128Test.cpp
@@ -16,7 +16,8 @@
 #include <string>
 #include <string_view>
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
 #include "wpi/SmallString.h"
 #include "wpi/leb128.h"
 #include "wpi/raw_istream.h"
diff --git a/wpiutil/src/test/native/cpp/llvm/ConvertUTFTest.cpp b/wpiutil/src/test/native/cpp/llvm/ConvertUTFTest.cpp
index 762682e..3ea7ab0 100644
--- a/wpiutil/src/test/native/cpp/llvm/ConvertUTFTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/ConvertUTFTest.cpp
@@ -26,6 +26,18 @@
   EXPECT_EQ(Expected, std::string{Result});
 }
 
+TEST(ConvertUTFTest, ConvertUTF32LittleEndianToUTF8String) {
+  // Src is the look of disapproval.
+  alignas(UTF32) static const char Src[] =
+      "\xFF\xFE\x00\x00\xA0\x0C\x00\x00\x5F\x00\x00\x00\xA0\x0C\x00\x00";
+  std::span<const char> Ref(Src, sizeof(Src) - 1);
+  std::string Result;
+  bool Success = convertUTF32ToUTF8String(Ref, Result);
+  EXPECT_TRUE(Success);
+  std::string Expected("\xE0\xB2\xA0_\xE0\xB2\xA0");
+  EXPECT_EQ(Expected, Result);
+}
+
 TEST(ConvertUTFTest, ConvertUTF16BigEndianToUTF8String) {
   // Src is the look of disapproval.
   alignas(UTF16) static const char Src[] = "\xfe\xff\x0c\xa0\x00_\x0c\xa0";
@@ -37,6 +49,18 @@
   EXPECT_EQ(Expected, std::string{Result});
 }
 
+TEST(ConvertUTFTest, ConvertUTF32BigEndianToUTF8String) {
+  // Src is the look of disapproval.
+  alignas(UTF32) static const char Src[] =
+      "\x00\x00\xFE\xFF\x00\x00\x0C\xA0\x00\x00\x00\x5F\x00\x00\x0C\xA0";
+  std::span<const char> Ref(Src, sizeof(Src) - 1);
+  std::string Result;
+  bool Success = convertUTF32ToUTF8String(Ref, Result);
+  EXPECT_TRUE(Success);
+  std::string Expected("\xE0\xB2\xA0_\xE0\xB2\xA0");
+  EXPECT_EQ(Expected, Result);
+}
+
 TEST(ConvertUTFTest, ConvertUTF8ToUTF16String) {
   // Src is the look of disapproval.
   static const char Src[] = "\xe0\xb2\xa0_\xe0\xb2\xa0";
@@ -58,7 +82,8 @@
 
 TEST(ConvertUTFTest, Empty) {
   SmallString<20> Result;
-  bool Success = convertUTF16ToUTF8String(std::span<const char>(), Result);
+  bool Success =
+      convertUTF16ToUTF8String(std::span<const char>(), Result);
   EXPECT_TRUE(Success);
   EXPECT_TRUE(std::string{Result}.empty());
 }
diff --git a/wpiutil/src/test/native/cpp/llvm/DenseMapTest.cpp b/wpiutil/src/test/native/cpp/llvm/DenseMapTest.cpp
index 68c37c0..22e535e 100644
--- a/wpiutil/src/test/native/cpp/llvm/DenseMapTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/DenseMapTest.cpp
@@ -11,9 +11,15 @@
 #endif
 
 #include "wpi/DenseMap.h"
+#include "wpi/DenseMapInfo.h"
+#include "wpi/DenseMapInfoVariant.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <map>
 #include <set>
+#include <string_view>
+#include <utility>
+#include <variant>
 
 using namespace wpi;
 
@@ -122,6 +128,7 @@
 
   // Lookup tests
   EXPECT_FALSE(this->Map.count(this->getKey()));
+  EXPECT_FALSE(this->Map.contains(this->getKey()));
   EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.end());
   EXPECT_EQ(typename TypeParam::mapped_type(),
             this->Map.lookup(this->getKey()));
@@ -153,11 +160,21 @@
 
   // Lookup tests
   EXPECT_TRUE(this->Map.count(this->getKey()));
+  EXPECT_TRUE(this->Map.contains(this->getKey()));
   EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.begin());
   EXPECT_EQ(this->getValue(), this->Map.lookup(this->getKey()));
   EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);
 }
 
+TYPED_TEST(DenseMapTest, AtTest) {
+  this->Map[this->getKey(0)] = this->getValue(0);
+  this->Map[this->getKey(1)] = this->getValue(1);
+  this->Map[this->getKey(2)] = this->getValue(2);
+  EXPECT_EQ(this->getValue(0), this->Map.at(this->getKey(0)));
+  EXPECT_EQ(this->getValue(1), this->Map.at(this->getKey(1)));
+  EXPECT_EQ(this->getValue(2), this->Map.at(this->getKey(2)));
+}
+
 // Test clear() method
 TYPED_TEST(DenseMapTest, ClearTest) {
   this->Map[this->getKey()] = this->getValue();
@@ -446,6 +463,7 @@
   std::vector<std::pair<int, CountCopyAndMove>> Values;
   // The size is a random value greater than 64 (hardcoded DenseMap min init)
   const int Count = 65;
+  Values.reserve(Count);
   for (int i = 0; i < Count; i++)
     Values.emplace_back(i, CountCopyAndMove());
 
@@ -586,6 +604,15 @@
   EXPECT_TRUE(map.find(0) == map.end());
 }
 
+TEST(DenseMapCustomTest, SmallDenseMapWithNumBucketsNonPowerOf2) {
+  // Is not power of 2.
+  const unsigned NumInitBuckets = 33;
+  // Power of 2 less then NumInitBuckets.
+  constexpr unsigned InlineBuckets = 4;
+  // Constructor should not trigger assert.
+  SmallDenseMap<int, int, InlineBuckets> map(NumInitBuckets);
+}
+
 TEST(DenseMapCustomTest, TryEmplaceTest) {
   DenseMap<int, std::unique_ptr<int>> Map;
   std::unique_ptr<int> P(new int(2));
@@ -644,11 +671,15 @@
 struct B : public A {
   using A::A;
 };
+
+struct AlwaysEqType {
+  bool operator==(const AlwaysEqType &RHS) const { return true; }
+};
 } // namespace
 
 namespace wpi {
 template <typename T>
-struct DenseMapInfo<T, std::enable_if_t<std::is_base_of<A, T>::value>> {
+struct DenseMapInfo<T, std::enable_if_t<std::is_base_of_v<A, T>>> {
   static inline T getEmptyKey() { return {static_cast<int>(~0)}; }
   static inline T getTombstoneKey() { return {static_cast<int>(~0U - 1)}; }
   static unsigned getHashValue(const T &Val) { return Val.value; }
@@ -656,6 +687,16 @@
     return LHS.value == RHS.value;
   }
 };
+
+template <> struct DenseMapInfo<AlwaysEqType> {
+  using T = AlwaysEqType;
+  static inline T getEmptyKey() { return {}; }
+  static inline T getTombstoneKey() { return {}; }
+  static unsigned getHashValue(const T &Val) { return 0; }
+  static bool isEqual(const T &LHS, const T &RHS) {
+    return false;
+  }
+};
 } // namespace wpi
 
 namespace {
@@ -677,4 +718,23 @@
   EXPECT_EQ(Map.find(Keys[1]), Map.end());
   EXPECT_EQ(Map.find(Keys[2]), Map.end());
 }
+
+TEST(DenseMapCustomTest, VariantSupport) {
+  using variant = std::variant<int, int, AlwaysEqType>;
+  DenseMap<variant, int> Map;
+  variant Keys[] = {
+      variant(std::in_place_index<0>, 1),
+      variant(std::in_place_index<1>, 1),
+      variant(std::in_place_index<2>),
+  };
+  Map.try_emplace(Keys[0], 0);
+  Map.try_emplace(Keys[1], 1);
+  EXPECT_THAT(Map, testing::SizeIs(2));
+  EXPECT_NE(DenseMapInfo<variant>::getHashValue(Keys[0]),
+            DenseMapInfo<variant>::getHashValue(Keys[1]));
+  // Check that isEqual dispatches to isEqual of underlying type, and not to
+  // operator==.
+  EXPECT_FALSE(DenseMapInfo<variant>::isEqual(Keys[2], Keys[2]));
+}
+
 } // namespace
diff --git a/wpiutil/src/test/native/cpp/llvm/MapVectorTest.cpp b/wpiutil/src/test/native/cpp/llvm/MapVectorTest.cpp
index 99bda8a..4bfa6b2 100644
--- a/wpiutil/src/test/native/cpp/llvm/MapVectorTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/MapVectorTest.cpp
@@ -94,8 +94,10 @@
   MV.insert(std::make_pair(5, 6));
   ASSERT_EQ(MV.size(), 3u);
 
+  ASSERT_TRUE(MV.contains(1));
   MV.erase(MV.find(1));
   ASSERT_EQ(MV.size(), 2u);
+  ASSERT_FALSE(MV.contains(1));
   ASSERT_EQ(MV.find(1), MV.end());
   ASSERT_EQ(MV[3], 4);
   ASSERT_EQ(MV[5], 6);
diff --git a/wpiutil/src/test/native/cpp/llvm/MathExtrasTest.cpp b/wpiutil/src/test/native/cpp/llvm/MathExtrasTest.cpp
index f392887..eab7ba1 100644
--- a/wpiutil/src/test/native/cpp/llvm/MathExtrasTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/MathExtrasTest.cpp
@@ -13,58 +13,6 @@
 
 namespace {
 
-TEST(MathExtras, countTrailingZeros) {
-  uint8_t Z8 = 0;
-  uint16_t Z16 = 0;
-  uint32_t Z32 = 0;
-  uint64_t Z64 = 0;
-  EXPECT_EQ(8u, countTrailingZeros(Z8));
-  EXPECT_EQ(16u, countTrailingZeros(Z16));
-  EXPECT_EQ(32u, countTrailingZeros(Z32));
-  EXPECT_EQ(64u, countTrailingZeros(Z64));
-
-  uint8_t NZ8 = 42;
-  uint16_t NZ16 = 42;
-  uint32_t NZ32 = 42;
-  uint64_t NZ64 = 42;
-  EXPECT_EQ(1u, countTrailingZeros(NZ8));
-  EXPECT_EQ(1u, countTrailingZeros(NZ16));
-  EXPECT_EQ(1u, countTrailingZeros(NZ32));
-  EXPECT_EQ(1u, countTrailingZeros(NZ64));
-}
-
-TEST(MathExtras, countLeadingZeros) {
-  uint8_t Z8 = 0;
-  uint16_t Z16 = 0;
-  uint32_t Z32 = 0;
-  uint64_t Z64 = 0;
-  EXPECT_EQ(8u, countLeadingZeros(Z8));
-  EXPECT_EQ(16u, countLeadingZeros(Z16));
-  EXPECT_EQ(32u, countLeadingZeros(Z32));
-  EXPECT_EQ(64u, countLeadingZeros(Z64));
-
-  uint8_t NZ8 = 42;
-  uint16_t NZ16 = 42;
-  uint32_t NZ32 = 42;
-  uint64_t NZ64 = 42;
-  EXPECT_EQ(2u, countLeadingZeros(NZ8));
-  EXPECT_EQ(10u, countLeadingZeros(NZ16));
-  EXPECT_EQ(26u, countLeadingZeros(NZ32));
-  EXPECT_EQ(58u, countLeadingZeros(NZ64));
-
-  EXPECT_EQ(8u, countLeadingZeros(0x00F000FFu));
-  EXPECT_EQ(8u, countLeadingZeros(0x00F12345u));
-  for (unsigned i = 0; i <= 30; ++i) {
-    EXPECT_EQ(31 - i, countLeadingZeros(1u << i));
-  }
-
-  EXPECT_EQ(8u, countLeadingZeros(0x00F1234500F12345ULL));
-  EXPECT_EQ(1u, countLeadingZeros(1ULL << 62));
-  for (unsigned i = 0; i <= 62; ++i) {
-    EXPECT_EQ(63 - i, countLeadingZeros(1ULL << i));
-  }
-}
-
 TEST(MathExtras, onesMask) {
   EXPECT_EQ(0U, maskLeadingOnes<uint8_t>(0));
   EXPECT_EQ(0U, maskTrailingOnes<uint8_t>(0));
@@ -90,46 +38,6 @@
   EXPECT_EQ(0xFFFFFFFFFFFF0000ULL, maskLeadingOnes<uint64_t>(48U));
 }
 
-TEST(MathExtras, findFirstSet) {
-  uint8_t Z8 = 0;
-  uint16_t Z16 = 0;
-  uint32_t Z32 = 0;
-  uint64_t Z64 = 0;
-  EXPECT_EQ(0xFFULL, findFirstSet(Z8));
-  EXPECT_EQ(0xFFFFULL, findFirstSet(Z16));
-  EXPECT_EQ(0xFFFFFFFFULL, findFirstSet(Z32));
-  EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findFirstSet(Z64));
-
-  uint8_t NZ8 = 42;
-  uint16_t NZ16 = 42;
-  uint32_t NZ32 = 42;
-  uint64_t NZ64 = 42;
-  EXPECT_EQ(1u, findFirstSet(NZ8));
-  EXPECT_EQ(1u, findFirstSet(NZ16));
-  EXPECT_EQ(1u, findFirstSet(NZ32));
-  EXPECT_EQ(1u, findFirstSet(NZ64));
-}
-
-TEST(MathExtras, findLastSet) {
-  uint8_t Z8 = 0;
-  uint16_t Z16 = 0;
-  uint32_t Z32 = 0;
-  uint64_t Z64 = 0;
-  EXPECT_EQ(0xFFULL, findLastSet(Z8));
-  EXPECT_EQ(0xFFFFULL, findLastSet(Z16));
-  EXPECT_EQ(0xFFFFFFFFULL, findLastSet(Z32));
-  EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findLastSet(Z64));
-
-  uint8_t NZ8 = 42;
-  uint16_t NZ16 = 42;
-  uint32_t NZ32 = 42;
-  uint64_t NZ64 = 42;
-  EXPECT_EQ(5u, findLastSet(NZ8));
-  EXPECT_EQ(5u, findLastSet(NZ16));
-  EXPECT_EQ(5u, findLastSet(NZ32));
-  EXPECT_EQ(5u, findLastSet(NZ64));
-}
-
 TEST(MathExtras, isIntN) {
   EXPECT_TRUE(isIntN(16, 32767));
   EXPECT_FALSE(isIntN(16, 32768));
@@ -175,6 +83,44 @@
   EXPECT_EQ(0x5400000000000000ULL, reverseBits(NZ64));
 }
 
+TEST(MathExtras, isShiftedMask_32) {
+  EXPECT_FALSE(isShiftedMask_32(0x01010101));
+  EXPECT_TRUE(isShiftedMask_32(0xf0000000));
+  EXPECT_TRUE(isShiftedMask_32(0xffff0000));
+  EXPECT_TRUE(isShiftedMask_32(0xff << 1));
+
+  unsigned MaskIdx, MaskLen;
+  EXPECT_FALSE(isShiftedMask_32(0x01010101, MaskIdx, MaskLen));
+  EXPECT_TRUE(isShiftedMask_32(0xf0000000, MaskIdx, MaskLen));
+  EXPECT_EQ(28, (int)MaskIdx);
+  EXPECT_EQ(4, (int)MaskLen);
+  EXPECT_TRUE(isShiftedMask_32(0xffff0000, MaskIdx, MaskLen));
+  EXPECT_EQ(16, (int)MaskIdx);
+  EXPECT_EQ(16, (int)MaskLen);
+  EXPECT_TRUE(isShiftedMask_32(0xff << 1, MaskIdx, MaskLen));
+  EXPECT_EQ(1, (int)MaskIdx);
+  EXPECT_EQ(8, (int)MaskLen);
+}
+
+TEST(MathExtras, isShiftedMask_64) {
+  EXPECT_FALSE(isShiftedMask_64(0x0101010101010101ull));
+  EXPECT_TRUE(isShiftedMask_64(0xf000000000000000ull));
+  EXPECT_TRUE(isShiftedMask_64(0xffff000000000000ull));
+  EXPECT_TRUE(isShiftedMask_64(0xffull << 55));
+
+  unsigned MaskIdx, MaskLen;
+  EXPECT_FALSE(isShiftedMask_64(0x0101010101010101ull, MaskIdx, MaskLen));
+  EXPECT_TRUE(isShiftedMask_64(0xf000000000000000ull, MaskIdx, MaskLen));
+  EXPECT_EQ(60, (int)MaskIdx);
+  EXPECT_EQ(4, (int)MaskLen);
+  EXPECT_TRUE(isShiftedMask_64(0xffff000000000000ull, MaskIdx, MaskLen));
+  EXPECT_EQ(48, (int)MaskIdx);
+  EXPECT_EQ(16, (int)MaskLen);
+  EXPECT_TRUE(isShiftedMask_64(0xffull << 55, MaskIdx, MaskLen));
+  EXPECT_EQ(55, (int)MaskIdx);
+  EXPECT_EQ(8, (int)MaskLen);
+}
+
 TEST(MathExtras, isPowerOf2_32) {
   EXPECT_FALSE(isPowerOf2_32(0));
   EXPECT_TRUE(isPowerOf2_32(1 << 6));
@@ -197,12 +143,6 @@
   EXPECT_EQ(8U, PowerOf2Ceil(7U));
 }
 
-TEST(MathExtras, PowerOf2Floor) {
-  EXPECT_EQ(0U, PowerOf2Floor(0U));
-  EXPECT_EQ(8U, PowerOf2Floor(8U));
-  EXPECT_EQ(4U, PowerOf2Floor(7U));
-}
-
 TEST(MathExtras, CTLog2) {
   EXPECT_EQ(CTLog2<1ULL << 0>(), 0U);
   EXPECT_EQ(CTLog2<1ULL << 1>(), 1U);
@@ -222,31 +162,6 @@
   EXPECT_EQ(CTLog2<1ULL << 15>(), 15U);
 }
 
-TEST(MathExtras, countLeadingOnes) {
-  for (int i = 30; i >= 0; --i) {
-    // Start with all ones and unset some bit.
-    EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i)));
-  }
-  for (int i = 62; i >= 0; --i) {
-    // Start with all ones and unset some bit.
-    EXPECT_EQ(63u - i, countLeadingOnes(0xFFFFFFFFFFFFFFFFULL ^ (1LL << i)));
-  }
-  for (int i = 30; i >= 0; --i) {
-    // Start with all ones and unset some bit.
-    EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i)));
-  }
-}
-
-TEST(MathExtras, FloatBits) {
-  static const float kValue = 5632.34f;
-  EXPECT_FLOAT_EQ(kValue, BitsToFloat(FloatToBits(kValue)));
-}
-
-TEST(MathExtras, DoubleBits) {
-  static const double kValue = 87987234.983498;
-  EXPECT_DOUBLE_EQ(kValue, BitsToDouble(DoubleToBits(kValue)));
-}
-
 TEST(MathExtras, MinAlign) {
   EXPECT_EQ(1u, MinAlign(2, 3));
   EXPECT_EQ(2u, MinAlign(2, 4));
@@ -271,9 +186,7 @@
   EXPECT_EQ(552u, alignTo(321, 255, 42));
 }
 
-template<typename T>
-void SaturatingAddTestHelper()
-{
+template <typename T> void SaturatingAddTestHelper() {
   const T Max = std::numeric_limits<T>::max();
   bool ResultOverflowed;
 
@@ -296,6 +209,42 @@
   EXPECT_EQ(Max, SaturatingAdd(Max, Max));
   EXPECT_EQ(Max, SaturatingAdd(Max, Max, &ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
+
+  EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3)));
+  EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3), &ResultOverflowed));
+  EXPECT_FALSE(ResultOverflowed);
+
+  EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4)));
+  EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4), &ResultOverflowed));
+  EXPECT_FALSE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0)));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0), &ResultOverflowed));
+  EXPECT_FALSE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max));
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max, &ResultOverflowed));
+  EXPECT_FALSE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1)));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1), &ResultOverflowed));
+  EXPECT_TRUE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max));
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max, &ResultOverflowed));
+  EXPECT_TRUE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1)));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1), &ResultOverflowed));
+  EXPECT_FALSE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2)));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2), &ResultOverflowed));
+  EXPECT_FALSE(ResultOverflowed);
+
+  EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max));
+  EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max, &ResultOverflowed));
+  EXPECT_TRUE(ResultOverflowed);
 }
 
 TEST(MathExtras, SaturatingAdd) {
diff --git a/wpiutil/src/test/native/cpp/llvm/MoveOnly.cpp b/wpiutil/src/test/native/cpp/llvm/MoveOnly.cpp
new file mode 100644
index 0000000..efbf244
--- /dev/null
+++ b/wpiutil/src/test/native/cpp/llvm/MoveOnly.cpp
@@ -0,0 +1,15 @@
+//===- llvm/unittest/ADT/MoveOnly.cpp - Optional unit tests ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MoveOnly.h"
+
+using namespace wpi;
+
+unsigned MoveOnly::MoveConstructions = 0;
+unsigned MoveOnly::Destructions = 0;
+unsigned MoveOnly::MoveAssignments = 0;
diff --git a/wpiutil/src/test/native/cpp/llvm/MoveOnly.h b/wpiutil/src/test/native/cpp/llvm/MoveOnly.h
new file mode 100644
index 0000000..b992335
--- /dev/null
+++ b/wpiutil/src/test/native/cpp/llvm/MoveOnly.h
@@ -0,0 +1,42 @@
+//===- llvm/unittest/ADT/MoveOnly.h - Optional unit tests -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_ADT_MOVEONLY_H
+#define LLVM_UNITTESTS_ADT_MOVEONLY_H
+
+namespace wpi {
+
+struct MoveOnly {
+  static unsigned MoveConstructions;
+  static unsigned Destructions;
+  static unsigned MoveAssignments;
+  int val;
+  explicit MoveOnly(int val) : val(val) {
+  }
+  MoveOnly(MoveOnly&& other) {
+    val = other.val;
+    ++MoveConstructions;
+  }
+  MoveOnly &operator=(MoveOnly&& other) {
+    val = other.val;
+    ++MoveAssignments;
+    return *this;
+  }
+  ~MoveOnly() {
+    ++Destructions;
+  }
+  static void ResetCounts() {
+    MoveConstructions = 0;
+    Destructions = 0;
+    MoveAssignments = 0;
+  }
+};
+
+}  // end namespace wpi
+
+#endif // LLVM_UNITTESTS_ADT_MOVEONLY_H
diff --git a/wpiutil/src/test/native/cpp/llvm/PointerIntPairTest.cpp b/wpiutil/src/test/native/cpp/llvm/PointerIntPairTest.cpp
index fcca5b6..03e22e1 100644
--- a/wpiutil/src/test/native/cpp/llvm/PointerIntPairTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/PointerIntPairTest.cpp
@@ -62,7 +62,11 @@
   EXPECT_EQ(&s, Pair2.getPointer());
   EXPECT_EQ(E::Case3, Pair2.getInt());
 
-  static_assert(std::is_trivially_copyable<PointerIntPair<S *, 2, E>>::value,
+  auto [Pointer2, Int2] = Pair2;
+  EXPECT_EQ(Pair2.getPointer(), Pointer2);
+  EXPECT_EQ(Pair2.getInt(), Int2);
+
+  static_assert(std::is_trivially_copyable_v<PointerIntPair<S *, 2, E>>,
                 "trivially copyable");
 }
 
@@ -100,10 +104,27 @@
   EXPECT_EQ(FixnumPointerTraits::NumLowBitsAvailable - 1,
             (int)PointerLikeTypeTraits<decltype(pair)>::NumLowBitsAvailable);
 
-  static_assert(
-      std::is_trivially_copyable<
-          PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits>>::value,
-      "trivially copyable");
+  static_assert(std::is_trivially_copyable_v<
+                    PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits>>,
+                "trivially copyable");
+}
+
+TEST(PointerIntPairTest, TypePunning) {
+  int I = 0;
+  int *IntPtr = &I;
+
+  int **IntPtrBegin = &IntPtr;
+  int **IntPtrEnd = IntPtrBegin + 1;
+
+  PointerIntPair<int *, 1> Pair;
+  int **PairAddr = Pair.getAddrOfPointer();
+
+  while (IntPtrBegin != IntPtrEnd) {
+    *PairAddr = *IntPtrBegin;
+    ++PairAddr;
+    ++IntPtrBegin;
+  }
+  EXPECT_EQ(Pair.getPointer(), IntPtr);
 }
 
 } // end anonymous namespace
diff --git a/wpiutil/src/test/native/cpp/llvm/PointerUnionTest.cpp b/wpiutil/src/test/native/cpp/llvm/PointerUnionTest.cpp
index 5a94a45..1bc2033 100644
--- a/wpiutil/src/test/native/cpp/llvm/PointerUnionTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/PointerUnionTest.cpp
@@ -89,29 +89,29 @@
 }
 
 TEST_F(PointerUnionTest, Is) {
-  EXPECT_FALSE(a.is<int *>());
-  EXPECT_TRUE(a.is<float *>());
-  EXPECT_TRUE(b.is<int *>());
-  EXPECT_FALSE(b.is<float *>());
-  EXPECT_TRUE(n.is<int *>());
-  EXPECT_FALSE(n.is<float *>());
-  EXPECT_TRUE(i3.is<int *>());
-  EXPECT_TRUE(f3.is<float *>());
-  EXPECT_TRUE(l3.is<long long *>());
-  EXPECT_TRUE(i4.is<int *>());
-  EXPECT_TRUE(f4.is<float *>());
-  EXPECT_TRUE(l4.is<long long *>());
-  EXPECT_TRUE(d4.is<double *>());
-  EXPECT_TRUE(i4null.is<int *>());
-  EXPECT_TRUE(f4null.is<float *>());
-  EXPECT_TRUE(l4null.is<long long *>());
-  EXPECT_TRUE(d4null.is<double *>());
+  EXPECT_FALSE(isa<int *>(a));
+  EXPECT_TRUE(isa<float *>(a));
+  EXPECT_TRUE(isa<int *>(b));
+  EXPECT_FALSE(isa<float *>(b));
+  EXPECT_TRUE(isa<int *>(n));
+  EXPECT_FALSE(isa<float *>(n));
+  EXPECT_TRUE(isa<int *>(i3));
+  EXPECT_TRUE(isa<float *>(f3));
+  EXPECT_TRUE(isa<long long *>(l3));
+  EXPECT_TRUE(isa<int *>(i4));
+  EXPECT_TRUE(isa<float *>(f4));
+  EXPECT_TRUE(isa<long long *>(l4));
+  EXPECT_TRUE(isa<double *>(d4));
+  EXPECT_TRUE(isa<int *>(i4null));
+  EXPECT_TRUE(isa<float *>(f4null));
+  EXPECT_TRUE(isa<long long *>(l4null));
+  EXPECT_TRUE(isa<double *>(d4null));
 }
 
 TEST_F(PointerUnionTest, Get) {
-  EXPECT_EQ(a.get<float *>(), &f);
-  EXPECT_EQ(b.get<int *>(), &i);
-  EXPECT_EQ(n.get<int *>(), (int *)nullptr);
+  EXPECT_EQ(cast<float *>(a), &f);
+  EXPECT_EQ(cast<int *>(b), &i);
+  EXPECT_EQ(cast<int *>(n), (int *)nullptr);
 }
 
 template<int I> struct alignas(8) Aligned {};
@@ -125,27 +125,27 @@
   Aligned<7> a7;
 
   PU8 a = &a0;
-  EXPECT_TRUE(a.is<Aligned<0>*>());
-  EXPECT_FALSE(a.is<Aligned<1>*>());
-  EXPECT_FALSE(a.is<Aligned<2>*>());
-  EXPECT_FALSE(a.is<Aligned<3>*>());
-  EXPECT_FALSE(a.is<Aligned<4>*>());
-  EXPECT_FALSE(a.is<Aligned<5>*>());
-  EXPECT_FALSE(a.is<Aligned<6>*>());
-  EXPECT_FALSE(a.is<Aligned<7>*>());
-  EXPECT_EQ(a.dyn_cast<Aligned<0>*>(), &a0);
+  EXPECT_TRUE(isa<Aligned<0> *>(a));
+  EXPECT_FALSE(isa<Aligned<1> *>(a));
+  EXPECT_FALSE(isa<Aligned<2> *>(a));
+  EXPECT_FALSE(isa<Aligned<3> *>(a));
+  EXPECT_FALSE(isa<Aligned<4> *>(a));
+  EXPECT_FALSE(isa<Aligned<5> *>(a));
+  EXPECT_FALSE(isa<Aligned<6> *>(a));
+  EXPECT_FALSE(isa<Aligned<7> *>(a));
+  EXPECT_EQ(dyn_cast_if_present<Aligned<0> *>(a), &a0);
   EXPECT_EQ(*a.getAddrOfPtr1(), &a0);
 
   a = &a7;
-  EXPECT_FALSE(a.is<Aligned<0>*>());
-  EXPECT_FALSE(a.is<Aligned<1>*>());
-  EXPECT_FALSE(a.is<Aligned<2>*>());
-  EXPECT_FALSE(a.is<Aligned<3>*>());
-  EXPECT_FALSE(a.is<Aligned<4>*>());
-  EXPECT_FALSE(a.is<Aligned<5>*>());
-  EXPECT_FALSE(a.is<Aligned<6>*>());
-  EXPECT_TRUE(a.is<Aligned<7>*>());
-  EXPECT_EQ(a.dyn_cast<Aligned<7>*>(), &a7);
+  EXPECT_FALSE(isa<Aligned<0> *>(a));
+  EXPECT_FALSE(isa<Aligned<1> *>(a));
+  EXPECT_FALSE(isa<Aligned<2> *>(a));
+  EXPECT_FALSE(isa<Aligned<3> *>(a));
+  EXPECT_FALSE(isa<Aligned<4> *>(a));
+  EXPECT_FALSE(isa<Aligned<5> *>(a));
+  EXPECT_FALSE(isa<Aligned<6> *>(a));
+  EXPECT_TRUE(isa<Aligned<7> *>(a));
+  EXPECT_EQ(dyn_cast_if_present<Aligned<7> *>(a), &a7);
 
   EXPECT_TRUE(a == PU8(&a7));
   EXPECT_TRUE(a != PU8(&a0));
@@ -156,4 +156,137 @@
   EXPECT_TRUE((void *)n.getAddrOfPtr1() == (void *)&n);
 }
 
+TEST_F(PointerUnionTest, NewCastInfra) {
+  // test isa<>
+  EXPECT_TRUE(isa<float *>(a));
+  EXPECT_TRUE(isa<int *>(b));
+  EXPECT_TRUE(isa<int *>(c));
+  EXPECT_TRUE(isa<int *>(n));
+  EXPECT_TRUE(isa<int *>(i3));
+  EXPECT_TRUE(isa<float *>(f3));
+  EXPECT_TRUE(isa<long long *>(l3));
+  EXPECT_TRUE(isa<int *>(i4));
+  EXPECT_TRUE(isa<float *>(f4));
+  EXPECT_TRUE(isa<long long *>(l4));
+  EXPECT_TRUE(isa<double *>(d4));
+  EXPECT_TRUE(isa<int *>(i4null));
+  EXPECT_TRUE(isa<float *>(f4null));
+  EXPECT_TRUE(isa<long long *>(l4null));
+  EXPECT_TRUE(isa<double *>(d4null));
+  EXPECT_FALSE(isa<int *>(a));
+  EXPECT_FALSE(isa<float *>(b));
+  EXPECT_FALSE(isa<float *>(c));
+  EXPECT_FALSE(isa<float *>(n));
+  EXPECT_FALSE(isa<float *>(i3));
+  EXPECT_FALSE(isa<long long *>(i3));
+  EXPECT_FALSE(isa<int *>(f3));
+  EXPECT_FALSE(isa<long long *>(f3));
+  EXPECT_FALSE(isa<int *>(l3));
+  EXPECT_FALSE(isa<float *>(l3));
+  EXPECT_FALSE(isa<float *>(i4));
+  EXPECT_FALSE(isa<long long *>(i4));
+  EXPECT_FALSE(isa<double *>(i4));
+  EXPECT_FALSE(isa<int *>(f4));
+  EXPECT_FALSE(isa<long long *>(f4));
+  EXPECT_FALSE(isa<double *>(f4));
+  EXPECT_FALSE(isa<int *>(l4));
+  EXPECT_FALSE(isa<float *>(l4));
+  EXPECT_FALSE(isa<double *>(l4));
+  EXPECT_FALSE(isa<int *>(d4));
+  EXPECT_FALSE(isa<float *>(d4));
+  EXPECT_FALSE(isa<long long *>(d4));
+  EXPECT_FALSE(isa<float *>(i4null));
+  EXPECT_FALSE(isa<long long *>(i4null));
+  EXPECT_FALSE(isa<double *>(i4null));
+  EXPECT_FALSE(isa<int *>(f4null));
+  EXPECT_FALSE(isa<long long *>(f4null));
+  EXPECT_FALSE(isa<double *>(f4null));
+  EXPECT_FALSE(isa<int *>(l4null));
+  EXPECT_FALSE(isa<float *>(l4null));
+  EXPECT_FALSE(isa<double *>(l4null));
+  EXPECT_FALSE(isa<int *>(d4null));
+  EXPECT_FALSE(isa<float *>(d4null));
+  EXPECT_FALSE(isa<long long *>(d4null));
+
+  // test cast<>
+  EXPECT_EQ(cast<float *>(a), &f);
+  EXPECT_EQ(cast<int *>(b), &i);
+  EXPECT_EQ(cast<int *>(c), &i);
+  EXPECT_EQ(cast<int *>(i3), &i);
+  EXPECT_EQ(cast<float *>(f3), &f);
+  EXPECT_EQ(cast<long long *>(l3), &l);
+  EXPECT_EQ(cast<int *>(i4), &i);
+  EXPECT_EQ(cast<float *>(f4), &f);
+  EXPECT_EQ(cast<long long *>(l4), &l);
+  EXPECT_EQ(cast<double *>(d4), &d);
+
+  // test dyn_cast
+  EXPECT_EQ(dyn_cast<int *>(a), nullptr);
+  EXPECT_EQ(dyn_cast<float *>(a), &f);
+  EXPECT_EQ(dyn_cast<int *>(b), &i);
+  EXPECT_EQ(dyn_cast<float *>(b), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(c), &i);
+  EXPECT_EQ(dyn_cast<float *>(c), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<int *>(n), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<float *>(n), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(i3), &i);
+  EXPECT_EQ(dyn_cast<float *>(i3), nullptr);
+  EXPECT_EQ(dyn_cast<long long *>(i3), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(f3), nullptr);
+  EXPECT_EQ(dyn_cast<float *>(f3), &f);
+  EXPECT_EQ(dyn_cast<long long *>(f3), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(l3), nullptr);
+  EXPECT_EQ(dyn_cast<float *>(l3), nullptr);
+  EXPECT_EQ(dyn_cast<long long *>(l3), &l);
+  EXPECT_EQ(dyn_cast<int *>(i4), &i);
+  EXPECT_EQ(dyn_cast<float *>(i4), nullptr);
+  EXPECT_EQ(dyn_cast<long long *>(i4), nullptr);
+  EXPECT_EQ(dyn_cast<double *>(i4), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(f4), nullptr);
+  EXPECT_EQ(dyn_cast<float *>(f4), &f);
+  EXPECT_EQ(dyn_cast<long long *>(f4), nullptr);
+  EXPECT_EQ(dyn_cast<double *>(f4), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(l4), nullptr);
+  EXPECT_EQ(dyn_cast<float *>(l4), nullptr);
+  EXPECT_EQ(dyn_cast<long long *>(l4), &l);
+  EXPECT_EQ(dyn_cast<double *>(l4), nullptr);
+  EXPECT_EQ(dyn_cast<int *>(d4), nullptr);
+  EXPECT_EQ(dyn_cast<float *>(d4), nullptr);
+  EXPECT_EQ(dyn_cast<long long *>(d4), nullptr);
+  EXPECT_EQ(dyn_cast<double *>(d4), &d);
+  EXPECT_EQ(dyn_cast_if_present<int *>(i4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<float *>(i4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<long long *>(i4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<double *>(i4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<int *>(f4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<float *>(f4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<long long *>(f4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<double *>(f4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<int *>(l4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<float *>(l4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<long long *>(l4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<double *>(l4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<int *>(d4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<float *>(d4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<long long *>(d4null), nullptr);
+  EXPECT_EQ(dyn_cast_if_present<double *>(d4null), nullptr);
+
+  // test for const
+  const PU4 constd4(&d);
+  EXPECT_TRUE(isa<double *>(constd4));
+  EXPECT_FALSE(isa<int *>(constd4));
+  EXPECT_EQ(cast<double *>(constd4), &d);
+  EXPECT_EQ(dyn_cast<long long *>(constd4), nullptr);
+
+  auto *result1 = cast<double *>(constd4);
+  static_assert(std::is_same_v<double *, decltype(result1)>,
+                "type mismatch for cast with PointerUnion");
+
+  PointerUnion<int *, const double *> constd2(&d);
+  auto *result2 = cast<const double *>(constd2);
+  EXPECT_EQ(result2, &d);
+  static_assert(std::is_same_v<const double *, decltype(result2)>,
+                "type mismatch for cast with PointerUnion");
+}
+
 } // end anonymous namespace
diff --git a/wpiutil/src/test/native/cpp/llvm/STLForwardCompatTest.cpp b/wpiutil/src/test/native/cpp/llvm/STLForwardCompatTest.cpp
index 333359e..153305b 100644
--- a/wpiutil/src/test/native/cpp/llvm/STLForwardCompatTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/STLForwardCompatTest.cpp
@@ -7,41 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "wpi/STLForwardCompat.h"
+#include "MoveOnly.h"
 #include "gtest/gtest.h"
 
 namespace {
 
-TEST(STLForwardCompatTest, NegationTest) {
-  EXPECT_TRUE((wpi::negation<std::false_type>::value));
-  EXPECT_FALSE((wpi::negation<std::true_type>::value));
-}
-
-struct incomplete_type;
-
-TEST(STLForwardCompatTest, ConjunctionTest) {
-  EXPECT_TRUE((wpi::conjunction<>::value));
-  EXPECT_FALSE((wpi::conjunction<std::false_type>::value));
-  EXPECT_TRUE((wpi::conjunction<std::true_type>::value));
-  EXPECT_FALSE((wpi::conjunction<std::false_type, incomplete_type>::value));
-  EXPECT_FALSE((wpi::conjunction<std::false_type, std::true_type>::value));
-  EXPECT_FALSE((wpi::conjunction<std::true_type, std::false_type>::value));
-  EXPECT_TRUE((wpi::conjunction<std::true_type, std::true_type>::value));
-  EXPECT_TRUE((wpi::conjunction<std::true_type, std::true_type,
-                                 std::true_type>::value));
-}
-
-TEST(STLForwardCompatTest, DisjunctionTest) {
-  EXPECT_FALSE((wpi::disjunction<>::value));
-  EXPECT_FALSE((wpi::disjunction<std::false_type>::value));
-  EXPECT_TRUE((wpi::disjunction<std::true_type>::value));
-  EXPECT_TRUE((wpi::disjunction<std::true_type, incomplete_type>::value));
-  EXPECT_TRUE((wpi::disjunction<std::false_type, std::true_type>::value));
-  EXPECT_TRUE((wpi::disjunction<std::true_type, std::false_type>::value));
-  EXPECT_TRUE((wpi::disjunction<std::true_type, std::true_type>::value));
-  EXPECT_TRUE((wpi::disjunction<std::true_type, std::true_type,
-                                 std::true_type>::value));
-}
-
 template <typename T>
 class STLForwardCompatRemoveCVRefTest : public ::testing::Test {};
 
@@ -75,4 +45,78 @@
                             wpi::remove_cvref_t<From>>::value));
 }
 
+TEST(TransformTest, TransformStd) {
+  std::optional<int> A;
+
+  std::optional<int> B = wpi::transformOptional(A, [&](int N) { return N + 1; });
+  EXPECT_FALSE(B.has_value());
+
+  A = 3;
+  std::optional<int> C = wpi::transformOptional(A, [&](int N) { return N + 1; });
+  EXPECT_TRUE(C.has_value());
+  EXPECT_EQ(4, *C);
+}
+
+TEST(TransformTest, MoveTransformStd) {
+  using wpi::MoveOnly;
+
+  std::optional<MoveOnly> A;
+
+  MoveOnly::ResetCounts();
+  std::optional<int> B = wpi::transformOptional(
+      std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+  EXPECT_FALSE(B.has_value());
+  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+  EXPECT_EQ(0u, MoveOnly::Destructions);
+
+  A = MoveOnly(5);
+  MoveOnly::ResetCounts();
+  std::optional<int> C = wpi::transformOptional(
+      std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+  EXPECT_TRUE(C.has_value());
+  EXPECT_EQ(7, *C);
+  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+  EXPECT_EQ(0u, MoveOnly::Destructions);
+}
+
+TEST(TransformTest, TransformLlvm) {
+  std::optional<int> A;
+
+  std::optional<int> B =
+      wpi::transformOptional(A, [&](int N) { return N + 1; });
+  EXPECT_FALSE(B.has_value());
+
+  A = 3;
+  std::optional<int> C =
+      wpi::transformOptional(A, [&](int N) { return N + 1; });
+  EXPECT_TRUE(C.has_value());
+  EXPECT_EQ(4, *C);
+}
+
+TEST(TransformTest, MoveTransformLlvm) {
+  using wpi::MoveOnly;
+
+  std::optional<MoveOnly> A;
+
+  MoveOnly::ResetCounts();
+  std::optional<int> B = wpi::transformOptional(
+      std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+  EXPECT_FALSE(B.has_value());
+  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+  EXPECT_EQ(0u, MoveOnly::Destructions);
+
+  A = MoveOnly(5);
+  MoveOnly::ResetCounts();
+  std::optional<int> C = wpi::transformOptional(
+      std::move(A), [&](const MoveOnly &M) { return M.val + 2; });
+  EXPECT_TRUE(C.has_value());
+  EXPECT_EQ(7, *C);
+  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
+  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
+  EXPECT_EQ(0u, MoveOnly::Destructions);
+}
+
 } // namespace
diff --git a/wpiutil/src/test/native/cpp/llvm/SmallSetTest.cpp b/wpiutil/src/test/native/cpp/llvm/SmallSetTest.cpp
index e245aa4..6f35907 100644
--- a/wpiutil/src/test/native/cpp/llvm/SmallSetTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/SmallSetTest.cpp
@@ -12,6 +12,7 @@
 
 #include "wpi/SmallSet.h"
 #include "gtest/gtest.h"
+#include <algorithm>
 #include <string>
 
 using namespace wpi;
@@ -20,11 +21,17 @@
 
   SmallSet<int, 4> s1;
 
-  for (int i = 0; i < 4; i++)
-    s1.insert(i);
+  for (int i = 0; i < 4; i++) {
+    auto InsertResult = s1.insert(i);
+    EXPECT_EQ(*InsertResult.first, i);
+    EXPECT_EQ(InsertResult.second, true);
+  }
 
-  for (int i = 0; i < 4; i++)
-    s1.insert(i);
+  for (int i = 0; i < 4; i++) {
+    auto InsertResult = s1.insert(i);
+    EXPECT_EQ(*InsertResult.first, i);
+    EXPECT_EQ(InsertResult.second, false);
+  }
 
   EXPECT_EQ(4u, s1.size());
 
@@ -37,8 +44,17 @@
 TEST(SmallSetTest, Grow) {
   SmallSet<int, 4> s1;
 
-  for (int i = 0; i < 8; i++)
-    s1.insert(i);
+  for (int i = 0; i < 8; i++) {
+    auto InsertResult = s1.insert(i);
+    EXPECT_EQ(*InsertResult.first, i);
+    EXPECT_EQ(InsertResult.second, true);
+  }
+
+  for (int i = 0; i < 8; i++) {
+    auto InsertResult = s1.insert(i);
+    EXPECT_EQ(*InsertResult.first, i);
+    EXPECT_EQ(InsertResult.second, false);
+  }
 
   EXPECT_EQ(8u, s1.size());
 
diff --git a/wpiutil/src/test/native/cpp/llvm/SmallVectorTest.cpp b/wpiutil/src/test/native/cpp/llvm/SmallVectorTest.cpp
index a60e683..53a941c 100644
--- a/wpiutil/src/test/native/cpp/llvm/SmallVectorTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/SmallVectorTest.cpp
@@ -11,10 +11,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "wpi/SmallVector.h"
-#include <span>
 #include "wpi/Compiler.h"
 #include "gtest/gtest.h"
+#include <array>
 #include <list>
+#include <span>
 #include <stdarg.h>
 
 #if defined(__GNUC__)
@@ -127,14 +128,30 @@
     return numCopyAssignmentCalls;
   }
 
-  friend bool operator==(const Constructable & c0, const Constructable & c1) {
+  friend bool operator==(const Constructable &c0, const Constructable &c1) {
     return c0.getValue() == c1.getValue();
   }
 
-  friend bool LLVM_ATTRIBUTE_UNUSED
-  operator!=(const Constructable & c0, const Constructable & c1) {
+  friend bool LLVM_ATTRIBUTE_UNUSED operator!=(const Constructable &c0,
+                                               const Constructable &c1) {
     return c0.getValue() != c1.getValue();
   }
+
+  friend bool operator<(const Constructable &c0, const Constructable &c1) {
+    return c0.getValue() < c1.getValue();
+  }
+  friend bool LLVM_ATTRIBUTE_UNUSED operator<=(const Constructable &c0,
+                                               const Constructable &c1) {
+    return c0.getValue() <= c1.getValue();
+  }
+  friend bool LLVM_ATTRIBUTE_UNUSED operator>(const Constructable &c0,
+                                              const Constructable &c1) {
+    return c0.getValue() > c1.getValue();
+  }
+  friend bool LLVM_ATTRIBUTE_UNUSED operator>=(const Constructable &c0,
+                                               const Constructable &c1) {
+    return c0.getValue() >= c1.getValue();
+  }
 };
 
 int Constructable::numConstructorCalls;
@@ -159,42 +176,50 @@
   V.resize(42);
 }
 
+TEST(SmallVectorTest, ConstructNonCopyableTest) {
+  SmallVector<NonCopyable, 0> V(42);
+  EXPECT_EQ(V.size(), (size_t)42);
+}
+
+// Assert that v contains the specified values, in order.
+template <typename VectorT>
+void assertValuesInOrder(VectorT &v, size_t size, ...) {
+  EXPECT_EQ(size, v.size());
+
+  va_list ap;
+  va_start(ap, size);
+  for (size_t i = 0; i < size; ++i) {
+    int value = va_arg(ap, int);
+    EXPECT_EQ(value, v[i].getValue());
+  }
+
+  va_end(ap);
+}
+
+template <typename VectorT> void assertEmpty(VectorT &v) {
+  // Size tests
+  EXPECT_EQ(0u, v.size());
+  EXPECT_TRUE(v.empty());
+
+  // Iterator tests
+  EXPECT_TRUE(v.begin() == v.end());
+}
+
+// Generate a sequence of values to initialize the vector.
+template <typename VectorT> void makeSequence(VectorT &v, int start, int end) {
+  for (int i = start; i <= end; ++i) {
+    v.push_back(Constructable(i));
+  }
+}
+
+template <typename T, unsigned N>
+constexpr static unsigned NumBuiltinElts(const SmallVector<T, N> &) {
+  return N;
+}
+
 class SmallVectorTestBase : public testing::Test {
 protected:
   void SetUp() override { Constructable::reset(); }
-
-  template <typename VectorT>
-  void assertEmpty(VectorT & v) {
-    // Size tests
-    EXPECT_EQ(0u, v.size());
-    EXPECT_TRUE(v.empty());
-
-    // Iterator tests
-    EXPECT_TRUE(v.begin() == v.end());
-  }
-
-  // Assert that v contains the specified values, in order.
-  template <typename VectorT>
-  void assertValuesInOrder(VectorT & v, size_t size, ...) {
-    EXPECT_EQ(size, v.size());
-
-    va_list ap;
-    va_start(ap, size);
-    for (size_t i = 0; i < size; ++i) {
-      int value = va_arg(ap, int);
-      EXPECT_EQ(value, v[i].getValue());
-    }
-
-    va_end(ap);
-  }
-
-  // Generate a sequence of values to initialize the vector.
-  template <typename VectorT>
-  void makeSequence(VectorT & v, int start, int end) {
-    for (int i = start; i <= end; ++i) {
-      v.push_back(Constructable(i));
-    }
-  }
 };
 
 // Test fixture class
@@ -217,24 +242,38 @@
 // Constructor test.
 TYPED_TEST(SmallVectorTest, ConstructorNonIterTest) {
   SCOPED_TRACE("ConstructorTest");
-  this->theVector = SmallVector<Constructable, 2>(2, 2);
-  this->assertValuesInOrder(this->theVector, 2u, 2, 2);
+  auto &V = this->theVector;
+  V = SmallVector<Constructable, 2>(2, 2);
+  assertValuesInOrder(V, 2u, 2, 2);
 }
 
 // Constructor test.
 TYPED_TEST(SmallVectorTest, ConstructorIterTest) {
   SCOPED_TRACE("ConstructorTest");
   int arr[] = {1, 2, 3};
-  this->theVector =
-      SmallVector<Constructable, 4>(std::begin(arr), std::end(arr));
-  this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
+  auto &V = this->theVector;
+  V = SmallVector<Constructable, 4>(std::begin(arr), std::end(arr));
+  assertValuesInOrder(V, 3u, 1, 2, 3);
+}
+
+// Constructor test.
+TYPED_TEST(SmallVectorTest, ConstructorFromSpanSimpleTest) {
+  SCOPED_TRACE("ConstructorFromSpanSimpleTest");
+  std::array<Constructable, 3> StdArray = {Constructable(1), Constructable(2),
+                                           Constructable(3)};
+  std::span<const Constructable> Array = StdArray;
+  auto &V = this->theVector;
+  V = SmallVector<Constructable, 4>(Array);
+  assertValuesInOrder(V, 3u, 1, 2, 3);
+  ASSERT_EQ(NumBuiltinElts(TypeParam{}), NumBuiltinElts(V));
 }
 
 // New vector test.
 TYPED_TEST(SmallVectorTest, EmptyVectorTest) {
   SCOPED_TRACE("EmptyVectorTest");
-  this->assertEmpty(this->theVector);
-  EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
+  auto &V = this->theVector;
+  assertEmpty(V);
+  EXPECT_TRUE(V.rbegin() == V.rend());
   EXPECT_EQ(0, Constructable::getNumConstructorCalls());
   EXPECT_EQ(0, Constructable::getNumDestructorCalls());
 }
@@ -242,35 +281,35 @@
 // Simple insertions and deletions.
 TYPED_TEST(SmallVectorTest, PushPopTest) {
   SCOPED_TRACE("PushPopTest");
-
+  auto &V = this->theVector;
   // Track whether the vector will potentially have to grow.
-  bool RequiresGrowth = this->theVector.capacity() < 3;
+  bool RequiresGrowth = V.capacity() < 3;
 
   // Push an element
-  this->theVector.push_back(Constructable(1));
+  V.push_back(Constructable(1));
 
   // Size tests
-  this->assertValuesInOrder(this->theVector, 1u, 1);
-  EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
-  EXPECT_FALSE(this->theVector.empty());
+  assertValuesInOrder(V, 1u, 1);
+  EXPECT_FALSE(V.begin() == V.end());
+  EXPECT_FALSE(V.empty());
 
   // Push another element
-  this->theVector.push_back(Constructable(2));
-  this->assertValuesInOrder(this->theVector, 2u, 1, 2);
+  V.push_back(Constructable(2));
+  assertValuesInOrder(V, 2u, 1, 2);
 
   // Insert at beginning. Reserve space to avoid reference invalidation from
-  // this->theVector[1].
-  this->theVector.reserve(this->theVector.size() + 1);
-  this->theVector.insert(this->theVector.begin(), this->theVector[1]);
-  this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
+  // V[1].
+  V.reserve(V.size() + 1);
+  V.insert(V.begin(), V[1]);
+  assertValuesInOrder(V, 3u, 2, 1, 2);
 
   // Pop one element
-  this->theVector.pop_back();
-  this->assertValuesInOrder(this->theVector, 2u, 2, 1);
+  V.pop_back();
+  assertValuesInOrder(V, 2u, 2, 1);
 
   // Pop remaining elements
-  this->theVector.pop_back_n(2);
-  this->assertEmpty(this->theVector);
+  V.pop_back_n(2);
+  assertEmpty(V);
 
   // Check number of constructor calls. Should be 2 for each list element,
   // one for the argument to push_back, one for the argument to insert,
@@ -290,12 +329,12 @@
 // Clear test.
 TYPED_TEST(SmallVectorTest, ClearTest) {
   SCOPED_TRACE("ClearTest");
+  auto &V = this->theVector;
+  V.reserve(2);
+  makeSequence(V, 1, 2);
+  V.clear();
 
-  this->theVector.reserve(2);
-  this->makeSequence(this->theVector, 1, 2);
-  this->theVector.clear();
-
-  this->assertEmpty(this->theVector);
+  assertEmpty(V);
   EXPECT_EQ(4, Constructable::getNumConstructorCalls());
   EXPECT_EQ(4, Constructable::getNumDestructorCalls());
 }
@@ -303,12 +342,12 @@
 // Resize smaller test.
 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) {
   SCOPED_TRACE("ResizeShrinkTest");
+  auto &V = this->theVector;
+  V.reserve(3);
+  makeSequence(V, 1, 3);
+  V.resize(1);
 
-  this->theVector.reserve(3);
-  this->makeSequence(this->theVector, 1, 3);
-  this->theVector.resize(1);
-
-  this->assertValuesInOrder(this->theVector, 1u, 1);
+  assertValuesInOrder(V, 1u, 1);
   EXPECT_EQ(6, Constructable::getNumConstructorCalls());
   EXPECT_EQ(5, Constructable::getNumDestructorCalls());
 }
@@ -316,25 +355,25 @@
 // Truncate test.
 TYPED_TEST(SmallVectorTest, TruncateTest) {
   SCOPED_TRACE("TruncateTest");
+  auto &V = this->theVector;
+  V.reserve(3);
+  makeSequence(V, 1, 3);
+  V.truncate(1);
 
-  this->theVector.reserve(3);
-  this->makeSequence(this->theVector, 1, 3);
-  this->theVector.truncate(1);
-
-  this->assertValuesInOrder(this->theVector, 1u, 1);
+  assertValuesInOrder(V, 1u, 1);
   EXPECT_EQ(6, Constructable::getNumConstructorCalls());
   EXPECT_EQ(5, Constructable::getNumDestructorCalls());
 
 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
-  EXPECT_DEATH(this->theVector.truncate(2), "Cannot increase size");
+  EXPECT_DEATH(V.truncate(2), "Cannot increase size");
 #endif
-  this->theVector.truncate(1);
-  this->assertValuesInOrder(this->theVector, 1u, 1);
+  V.truncate(1);
+  assertValuesInOrder(V, 1u, 1);
   EXPECT_EQ(6, Constructable::getNumConstructorCalls());
   EXPECT_EQ(5, Constructable::getNumDestructorCalls());
 
-  this->theVector.truncate(0);
-  this->assertEmpty(this->theVector);
+  V.truncate(0);
+  assertEmpty(V);
   EXPECT_EQ(6, Constructable::getNumConstructorCalls());
   EXPECT_EQ(6, Constructable::getNumDestructorCalls());
 }
@@ -342,20 +381,21 @@
 // Resize bigger test.
 TYPED_TEST(SmallVectorTest, ResizeGrowTest) {
   SCOPED_TRACE("ResizeGrowTest");
-
-  this->theVector.resize(2);
+  auto &V = this->theVector;
+  V.resize(2);
 
   EXPECT_EQ(2, Constructable::getNumConstructorCalls());
   EXPECT_EQ(0, Constructable::getNumDestructorCalls());
-  EXPECT_EQ(2u, this->theVector.size());
+  EXPECT_EQ(2u, V.size());
 }
 
 TYPED_TEST(SmallVectorTest, ResizeWithElementsTest) {
-  this->theVector.resize(2);
+  auto &V = this->theVector;
+  V.resize(2);
 
   Constructable::reset();
 
-  this->theVector.resize(4);
+  V.resize(4);
 
   size_t Ctors = Constructable::getNumConstructorCalls();
   EXPECT_TRUE(Ctors == 2 || Ctors == 4);
@@ -368,9 +408,9 @@
 // Resize with fill value.
 TYPED_TEST(SmallVectorTest, ResizeFillTest) {
   SCOPED_TRACE("ResizeFillTest");
-
-  this->theVector.resize(3, Constructable(77));
-  this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
+  auto &V = this->theVector;
+  V.resize(3, Constructable(77));
+  assertValuesInOrder(V, 3u, 77, 77, 77);
 }
 
 TEST(SmallVectorTest, ResizeForOverwrite) {
@@ -401,100 +441,103 @@
 // Overflow past fixed size.
 TYPED_TEST(SmallVectorTest, OverflowTest) {
   SCOPED_TRACE("OverflowTest");
-
+  auto &V = this->theVector;
   // Push more elements than the fixed size.
-  this->makeSequence(this->theVector, 1, 10);
+  makeSequence(V, 1, 10);
 
   // Test size and values.
-  EXPECT_EQ(10u, this->theVector.size());
+  EXPECT_EQ(10u, V.size());
   for (int i = 0; i < 10; ++i) {
-    EXPECT_EQ(i+1, this->theVector[i].getValue());
+    EXPECT_EQ(i + 1, V[i].getValue());
   }
 
   // Now resize back to fixed size.
-  this->theVector.resize(1);
+  V.resize(1);
 
-  this->assertValuesInOrder(this->theVector, 1u, 1);
+  assertValuesInOrder(V, 1u, 1);
 }
 
 // Iteration tests.
 TYPED_TEST(SmallVectorTest, IterationTest) {
-  this->makeSequence(this->theVector, 1, 2);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 2);
 
   // Forward Iteration
-  typename TypeParam::iterator it = this->theVector.begin();
-  EXPECT_TRUE(*it == this->theVector.front());
-  EXPECT_TRUE(*it == this->theVector[0]);
+  typename TypeParam::iterator it = V.begin();
+  EXPECT_TRUE(*it == V.front());
+  EXPECT_TRUE(*it == V[0]);
   EXPECT_EQ(1, it->getValue());
   ++it;
-  EXPECT_TRUE(*it == this->theVector[1]);
-  EXPECT_TRUE(*it == this->theVector.back());
+  EXPECT_TRUE(*it == V[1]);
+  EXPECT_TRUE(*it == V.back());
   EXPECT_EQ(2, it->getValue());
   ++it;
-  EXPECT_TRUE(it == this->theVector.end());
+  EXPECT_TRUE(it == V.end());
   --it;
-  EXPECT_TRUE(*it == this->theVector[1]);
+  EXPECT_TRUE(*it == V[1]);
   EXPECT_EQ(2, it->getValue());
   --it;
-  EXPECT_TRUE(*it == this->theVector[0]);
+  EXPECT_TRUE(*it == V[0]);
   EXPECT_EQ(1, it->getValue());
 
   // Reverse Iteration
-  typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
-  EXPECT_TRUE(*rit == this->theVector[1]);
+  typename TypeParam::reverse_iterator rit = V.rbegin();
+  EXPECT_TRUE(*rit == V[1]);
   EXPECT_EQ(2, rit->getValue());
   ++rit;
-  EXPECT_TRUE(*rit == this->theVector[0]);
+  EXPECT_TRUE(*rit == V[0]);
   EXPECT_EQ(1, rit->getValue());
   ++rit;
-  EXPECT_TRUE(rit == this->theVector.rend());
+  EXPECT_TRUE(rit == V.rend());
   --rit;
-  EXPECT_TRUE(*rit == this->theVector[0]);
+  EXPECT_TRUE(*rit == V[0]);
   EXPECT_EQ(1, rit->getValue());
   --rit;
-  EXPECT_TRUE(*rit == this->theVector[1]);
+  EXPECT_TRUE(*rit == V[1]);
   EXPECT_EQ(2, rit->getValue());
 }
 
 // Swap test.
 TYPED_TEST(SmallVectorTest, SwapTest) {
   SCOPED_TRACE("SwapTest");
+  auto &V = this->theVector;
+  auto &U = this->otherVector;
+  makeSequence(V, 1, 2);
+  std::swap(V, U);
 
-  this->makeSequence(this->theVector, 1, 2);
-  std::swap(this->theVector, this->otherVector);
-
-  this->assertEmpty(this->theVector);
-  this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
+  assertEmpty(V);
+  assertValuesInOrder(U, 2u, 1, 2);
 }
 
 // Append test
 TYPED_TEST(SmallVectorTest, AppendTest) {
   SCOPED_TRACE("AppendTest");
+  auto &V = this->theVector;
+  auto &U = this->otherVector;
+  makeSequence(U, 2, 3);
 
-  this->makeSequence(this->otherVector, 2, 3);
+  V.push_back(Constructable(1));
+  V.append(U.begin(), U.end());
 
-  this->theVector.push_back(Constructable(1));
-  this->theVector.append(this->otherVector.begin(), this->otherVector.end());
-
-  this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
+  assertValuesInOrder(V, 3u, 1, 2, 3);
 }
 
 // Append repeated test
 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) {
   SCOPED_TRACE("AppendRepeatedTest");
-
-  this->theVector.push_back(Constructable(1));
-  this->theVector.append(2, Constructable(77));
-  this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
+  auto &V = this->theVector;
+  V.push_back(Constructable(1));
+  V.append(2, Constructable(77));
+  assertValuesInOrder(V, 3u, 1, 77, 77);
 }
 
 // Append test
 TYPED_TEST(SmallVectorTest, AppendNonIterTest) {
   SCOPED_TRACE("AppendRepeatedTest");
-
-  this->theVector.push_back(Constructable(1));
-  this->theVector.append(2, 7);
-  this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7);
+  auto &V = this->theVector;
+  V.push_back(Constructable(1));
+  V.append(2, 7);
+  assertValuesInOrder(V, 3u, 1, 7, 7);
 }
 
 struct output_iterator {
@@ -509,84 +552,85 @@
 
 TYPED_TEST(SmallVectorTest, AppendRepeatedNonForwardIterator) {
   SCOPED_TRACE("AppendRepeatedTest");
-
-  this->theVector.push_back(Constructable(1));
-  this->theVector.append(output_iterator(), output_iterator());
-  this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7);
+  auto &V = this->theVector;
+  V.push_back(Constructable(1));
+  V.append(output_iterator(), output_iterator());
+  assertValuesInOrder(V, 3u, 1, 7, 7);
 }
 
 TYPED_TEST(SmallVectorTest, AppendSmallVector) {
   SCOPED_TRACE("AppendSmallVector");
-
+  auto &V = this->theVector;
   SmallVector<Constructable, 3> otherVector = {7, 7};
-  this->theVector.push_back(Constructable(1));
-  this->theVector.append(otherVector);
-  this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7);
+  V.push_back(Constructable(1));
+  V.append(otherVector);
+  assertValuesInOrder(V, 3u, 1, 7, 7);
 }
 
 // Assign test
 TYPED_TEST(SmallVectorTest, AssignTest) {
   SCOPED_TRACE("AssignTest");
-
-  this->theVector.push_back(Constructable(1));
-  this->theVector.assign(2, Constructable(77));
-  this->assertValuesInOrder(this->theVector, 2u, 77, 77);
+  auto &V = this->theVector;
+  V.push_back(Constructable(1));
+  V.assign(2, Constructable(77));
+  assertValuesInOrder(V, 2u, 77, 77);
 }
 
 // Assign test
 TYPED_TEST(SmallVectorTest, AssignRangeTest) {
   SCOPED_TRACE("AssignTest");
-
-  this->theVector.push_back(Constructable(1));
+  auto &V = this->theVector;
+  V.push_back(Constructable(1));
   int arr[] = {1, 2, 3};
-  this->theVector.assign(std::begin(arr), std::end(arr));
-  this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
+  V.assign(std::begin(arr), std::end(arr));
+  assertValuesInOrder(V, 3u, 1, 2, 3);
 }
 
 // Assign test
 TYPED_TEST(SmallVectorTest, AssignNonIterTest) {
   SCOPED_TRACE("AssignTest");
-
-  this->theVector.push_back(Constructable(1));
-  this->theVector.assign(2, 7);
-  this->assertValuesInOrder(this->theVector, 2u, 7, 7);
+  auto &V = this->theVector;
+  V.push_back(Constructable(1));
+  V.assign(2, 7);
+  assertValuesInOrder(V, 2u, 7, 7);
 }
 
 TYPED_TEST(SmallVectorTest, AssignSmallVector) {
   SCOPED_TRACE("AssignSmallVector");
-
+  auto &V = this->theVector;
   SmallVector<Constructable, 3> otherVector = {7, 7};
-  this->theVector.push_back(Constructable(1));
-  this->theVector.assign(otherVector);
-  this->assertValuesInOrder(this->theVector, 2u, 7, 7);
+  V.push_back(Constructable(1));
+  V.assign(otherVector);
+  assertValuesInOrder(V, 2u, 7, 7);
 }
 
 // Move-assign test
 TYPED_TEST(SmallVectorTest, MoveAssignTest) {
   SCOPED_TRACE("MoveAssignTest");
-
+  auto &V = this->theVector;
+  auto &U = this->otherVector;
   // Set up our vector with a single element, but enough capacity for 4.
-  this->theVector.reserve(4);
-  this->theVector.push_back(Constructable(1));
-  
+  V.reserve(4);
+  V.push_back(Constructable(1));
+
   // Set up the other vector with 2 elements.
-  this->otherVector.push_back(Constructable(2));
-  this->otherVector.push_back(Constructable(3));
+  U.push_back(Constructable(2));
+  U.push_back(Constructable(3));
 
   // Move-assign from the other vector.
-  this->theVector = std::move(this->otherVector);
+  V = std::move(U);
 
   // Make sure we have the right result.
-  this->assertValuesInOrder(this->theVector, 2u, 2, 3);
+  assertValuesInOrder(V, 2u, 2, 3);
 
   // Make sure the # of constructor/destructor calls line up. There
   // are two live objects after clearing the other vector.
-  this->otherVector.clear();
+  U.clear();
   EXPECT_EQ(Constructable::getNumConstructorCalls()-2, 
             Constructable::getNumDestructorCalls());
 
   // There shouldn't be any live objects any more.
-  this->theVector.clear();
+  V.clear();
   EXPECT_EQ(Constructable::getNumConstructorCalls(), 
             Constructable::getNumDestructorCalls());
 }
@@ -594,54 +638,51 @@
 // Erase a single element
 TYPED_TEST(SmallVectorTest, EraseTest) {
   SCOPED_TRACE("EraseTest");
-
-  this->makeSequence(this->theVector, 1, 3);
-  const auto &theConstVector = this->theVector;
-  this->theVector.erase(theConstVector.begin());
-  this->assertValuesInOrder(this->theVector, 2u, 2, 3);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 3);
+  const auto &theConstVector = V;
+  V.erase(theConstVector.begin());
+  assertValuesInOrder(V, 2u, 2, 3);
 }
 
 // Erase a range of elements
 TYPED_TEST(SmallVectorTest, EraseRangeTest) {
   SCOPED_TRACE("EraseRangeTest");
-
-  this->makeSequence(this->theVector, 1, 3);
-  const auto &theConstVector = this->theVector;
-  this->theVector.erase(theConstVector.begin(), theConstVector.begin() + 2);
-  this->assertValuesInOrder(this->theVector, 1u, 3);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 3);
+  const auto &theConstVector = V;
+  V.erase(theConstVector.begin(), theConstVector.begin() + 2);
+  assertValuesInOrder(V, 1u, 3);
 }
 
 // Insert a single element.
 TYPED_TEST(SmallVectorTest, InsertTest) {
   SCOPED_TRACE("InsertTest");
-
-  this->makeSequence(this->theVector, 1, 3);
-  typename TypeParam::iterator I =
-    this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
-  EXPECT_EQ(this->theVector.begin() + 1, I);
-  this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 3);
+  typename TypeParam::iterator I = V.insert(V.begin() + 1, Constructable(77));
+  EXPECT_EQ(V.begin() + 1, I);
+  assertValuesInOrder(V, 4u, 1, 77, 2, 3);
 }
 
 // Insert a copy of a single element.
 TYPED_TEST(SmallVectorTest, InsertCopy) {
   SCOPED_TRACE("InsertTest");
-
-  this->makeSequence(this->theVector, 1, 3);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 3);
   Constructable C(77);
-  typename TypeParam::iterator I =
-      this->theVector.insert(this->theVector.begin() + 1, C);
-  EXPECT_EQ(this->theVector.begin() + 1, I);
-  this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
+  typename TypeParam::iterator I = V.insert(V.begin() + 1, C);
+  EXPECT_EQ(V.begin() + 1, I);
+  assertValuesInOrder(V, 4u, 1, 77, 2, 3);
 }
 
 // Insert repeated elements.
 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) {
   SCOPED_TRACE("InsertRepeatedTest");
-
-  this->makeSequence(this->theVector, 1, 4);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 4);
   Constructable::reset();
-  auto I =
-      this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
+  auto I = V.insert(V.begin() + 1, 2, Constructable(16));
   // Move construct the top element into newly allocated space, and optionally
   // reallocate the whole buffer, move constructing into it.
   // FIXME: This is inefficient, we shouldn't move things into newly allocated
@@ -655,26 +696,26 @@
   EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
   // All without any copy construction.
   EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls());
-  EXPECT_EQ(this->theVector.begin() + 1, I);
-  this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4);
+  EXPECT_EQ(V.begin() + 1, I);
+  assertValuesInOrder(V, 6u, 1, 16, 16, 2, 3, 4);
 }
 
 TYPED_TEST(SmallVectorTest, InsertRepeatedNonIterTest) {
   SCOPED_TRACE("InsertRepeatedTest");
-
-  this->makeSequence(this->theVector, 1, 4);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 4);
   Constructable::reset();
-  auto I = this->theVector.insert(this->theVector.begin() + 1, 2, 7);
-  EXPECT_EQ(this->theVector.begin() + 1, I);
-  this->assertValuesInOrder(this->theVector, 6u, 1, 7, 7, 2, 3, 4);
+  auto I = V.insert(V.begin() + 1, 2, 7);
+  EXPECT_EQ(V.begin() + 1, I);
+  assertValuesInOrder(V, 6u, 1, 7, 7, 2, 3, 4);
 }
 
 TYPED_TEST(SmallVectorTest, InsertRepeatedAtEndTest) {
   SCOPED_TRACE("InsertRepeatedTest");
-
-  this->makeSequence(this->theVector, 1, 4);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 4);
   Constructable::reset();
-  auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
+  auto I = V.insert(V.end(), 2, Constructable(16));
   // Just copy construct them into newly allocated space
   EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls());
   // Move everything across if reallocation is needed.
@@ -684,34 +725,30 @@
   EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
   EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
 
-  EXPECT_EQ(this->theVector.begin() + 4, I);
-  this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16);
+  EXPECT_EQ(V.begin() + 4, I);
+  assertValuesInOrder(V, 6u, 1, 2, 3, 4, 16, 16);
 }
 
 TYPED_TEST(SmallVectorTest, InsertRepeatedEmptyTest) {
   SCOPED_TRACE("InsertRepeatedTest");
-
-  this->makeSequence(this->theVector, 10, 15);
+  auto &V = this->theVector;
+  makeSequence(V, 10, 15);
 
   // Empty insert.
-  EXPECT_EQ(this->theVector.end(),
-            this->theVector.insert(this->theVector.end(),
-                                   0, Constructable(42)));
-  EXPECT_EQ(this->theVector.begin() + 1,
-            this->theVector.insert(this->theVector.begin() + 1,
-                                   0, Constructable(42)));
+  EXPECT_EQ(V.end(), V.insert(V.end(), 0, Constructable(42)));
+  EXPECT_EQ(V.begin() + 1, V.insert(V.begin() + 1, 0, Constructable(42)));
 }
 
 // Insert range.
 TYPED_TEST(SmallVectorTest, InsertRangeTest) {
   SCOPED_TRACE("InsertRangeTest");
-
+  auto &V = this->theVector;
   Constructable Arr[3] =
     { Constructable(77), Constructable(77), Constructable(77) };
 
-  this->makeSequence(this->theVector, 1, 3);
+  makeSequence(V, 1, 3);
   Constructable::reset();
-  auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3);
+  auto I = V.insert(V.begin() + 1, Arr, Arr + 3);
   // Move construct the top 3 elements into newly allocated space.
   // Possibly move the whole sequence into new space first.
   // FIXME: This is inefficient, we shouldn't move things into newly allocated
@@ -723,22 +760,22 @@
   EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
   // Copy construct the third element into newly allocated space.
   EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls());
-  EXPECT_EQ(this->theVector.begin() + 1, I);
-  this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
+  EXPECT_EQ(V.begin() + 1, I);
+  assertValuesInOrder(V, 6u, 1, 77, 77, 77, 2, 3);
 }
 
 
 TYPED_TEST(SmallVectorTest, InsertRangeAtEndTest) {
   SCOPED_TRACE("InsertRangeTest");
-
+  auto &V = this->theVector;
   Constructable Arr[3] =
     { Constructable(77), Constructable(77), Constructable(77) };
 
-  this->makeSequence(this->theVector, 1, 3);
+  makeSequence(V, 1, 3);
 
   // Insert at end.
   Constructable::reset();
-  auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
+  auto I = V.insert(V.end(), Arr, Arr + 3);
   // Copy construct the 3 elements into new space at the top.
   EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls());
   // Don't copy/move anything else.
@@ -748,42 +785,67 @@
   EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
               Constructable::getNumMoveConstructorCalls() == 3);
   EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
-  EXPECT_EQ(this->theVector.begin() + 3, I);
-  this->assertValuesInOrder(this->theVector, 6u,
-                            1, 2, 3, 77, 77, 77);
+  EXPECT_EQ(V.begin() + 3, I);
+  assertValuesInOrder(V, 6u, 1, 2, 3, 77, 77, 77);
 }
 
 TYPED_TEST(SmallVectorTest, InsertEmptyRangeTest) {
   SCOPED_TRACE("InsertRangeTest");
-
-  this->makeSequence(this->theVector, 1, 3);
+  auto &V = this->theVector;
+  makeSequence(V, 1, 3);
 
   // Empty insert.
-  EXPECT_EQ(this->theVector.end(),
-            this->theVector.insert(this->theVector.end(),
-                                   this->theVector.begin(),
-                                   this->theVector.begin()));
-  EXPECT_EQ(this->theVector.begin() + 1,
-            this->theVector.insert(this->theVector.begin() + 1,
-                                   this->theVector.begin(),
-                                   this->theVector.begin()));
+  EXPECT_EQ(V.end(), V.insert(V.end(), V.begin(), V.begin()));
+  EXPECT_EQ(V.begin() + 1, V.insert(V.begin() + 1, V.begin(), V.begin()));
 }
 
 // Comparison tests.
-TYPED_TEST(SmallVectorTest, ComparisonTest) {
-  SCOPED_TRACE("ComparisonTest");
+TYPED_TEST(SmallVectorTest, ComparisonEqualityTest) {
+  SCOPED_TRACE("ComparisonEqualityTest");
+  auto &V = this->theVector;
+  auto &U = this->otherVector;
+  makeSequence(V, 1, 3);
+  makeSequence(U, 1, 3);
 
-  this->makeSequence(this->theVector, 1, 3);
-  this->makeSequence(this->otherVector, 1, 3);
+  EXPECT_TRUE(V == U);
+  EXPECT_FALSE(V != U);
 
-  EXPECT_TRUE(this->theVector == this->otherVector);
-  EXPECT_FALSE(this->theVector != this->otherVector);
+  U.clear();
+  makeSequence(U, 2, 4);
 
-  this->otherVector.clear();
-  this->makeSequence(this->otherVector, 2, 4);
+  EXPECT_FALSE(V == U);
+  EXPECT_TRUE(V != U);
+}
 
-  EXPECT_FALSE(this->theVector == this->otherVector);
-  EXPECT_TRUE(this->theVector != this->otherVector);
+// Comparison tests.
+TYPED_TEST(SmallVectorTest, ComparisonLessThanTest) {
+  SCOPED_TRACE("ComparisonLessThanTest");
+  auto &V = this->theVector;
+  auto &U = this->otherVector;
+  V = {1, 2, 4};
+  U = {1, 4};
+
+  EXPECT_TRUE(V < U);
+  EXPECT_TRUE(V <= U);
+  EXPECT_FALSE(V > U);
+  EXPECT_FALSE(V >= U);
+
+  EXPECT_FALSE(U < V);
+  EXPECT_FALSE(U <= V);
+  EXPECT_TRUE(U > V);
+  EXPECT_TRUE(U >= V);
+
+  U = {1, 2, 4};
+
+  EXPECT_FALSE(V < U);
+  EXPECT_TRUE(V <= U);
+  EXPECT_FALSE(V > U);
+  EXPECT_TRUE(V >= U);
+
+  EXPECT_FALSE(U < V);
+  EXPECT_TRUE(U <= V);
+  EXPECT_FALSE(U > V);
+  EXPECT_TRUE(U >= V);
 }
 
 // Constant vector tests.
@@ -797,25 +859,27 @@
 
 // Direct array access.
 TYPED_TEST(SmallVectorTest, DirectVectorTest) {
-  EXPECT_EQ(0u, this->theVector.size());
-  this->theVector.reserve(4);
-  EXPECT_LE(4u, this->theVector.capacity());
+  auto &V = this->theVector;
+  EXPECT_EQ(0u, V.size());
+  V.reserve(4);
+  EXPECT_LE(4u, V.capacity());
   EXPECT_EQ(0, Constructable::getNumConstructorCalls());
-  this->theVector.push_back(1);
-  this->theVector.push_back(2);
-  this->theVector.push_back(3);
-  this->theVector.push_back(4);
-  EXPECT_EQ(4u, this->theVector.size());
+  V.push_back(1);
+  V.push_back(2);
+  V.push_back(3);
+  V.push_back(4);
+  EXPECT_EQ(4u, V.size());
   EXPECT_EQ(8, Constructable::getNumConstructorCalls());
-  EXPECT_EQ(1, this->theVector[0].getValue());
-  EXPECT_EQ(2, this->theVector[1].getValue());
-  EXPECT_EQ(3, this->theVector[2].getValue());
-  EXPECT_EQ(4, this->theVector[3].getValue());
+  EXPECT_EQ(1, V[0].getValue());
+  EXPECT_EQ(2, V[1].getValue());
+  EXPECT_EQ(3, V[2].getValue());
+  EXPECT_EQ(4, V[3].getValue());
 }
 
 TYPED_TEST(SmallVectorTest, IteratorTest) {
+  auto &V = this->theVector;
   std::list<int> L;
-  this->theVector.insert(this->theVector.end(), L.begin(), L.end());
+  V.insert(V.end(), L.begin(), L.end());
 }
 
 template <typename InvalidType> class DualSmallVectorsTest;
@@ -825,9 +889,6 @@
 protected:
   VectorT1 theVector;
   VectorT2 otherVector;
-
-  template <typename T, unsigned N>
-  static unsigned NumBuiltinElts(const SmallVector<T, N>&) { return N; }
 };
 
 typedef ::testing::Types<
@@ -845,33 +906,32 @@
 
 TYPED_TEST(DualSmallVectorsTest, MoveAssignment) {
   SCOPED_TRACE("MoveAssignTest-DualVectorTypes");
-
+  auto &V = this->theVector;
+  auto &U = this->otherVector;
   // Set up our vector with four elements.
   for (unsigned I = 0; I < 4; ++I)
-    this->otherVector.push_back(Constructable(I));
+    U.push_back(Constructable(I));
 
-  const Constructable *OrigDataPtr = this->otherVector.data();
+  const Constructable *OrigDataPtr = U.data();
 
   // Move-assign from the other vector.
-  this->theVector =
-    std::move(static_cast<SmallVectorImpl<Constructable>&>(this->otherVector));
+  V = std::move(static_cast<SmallVectorImpl<Constructable> &>(U));
 
   // Make sure we have the right result.
-  this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3);
+  assertValuesInOrder(V, 4u, 0, 1, 2, 3);
 
   // Make sure the # of constructor/destructor calls line up. There
   // are two live objects after clearing the other vector.
-  this->otherVector.clear();
+  U.clear();
   EXPECT_EQ(Constructable::getNumConstructorCalls()-4,
             Constructable::getNumDestructorCalls());
 
   // If the source vector (otherVector) was in small-mode, assert that we just
   // moved the data pointer over.
-  EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 ||
-              this->theVector.data() == OrigDataPtr);
+  EXPECT_TRUE(NumBuiltinElts(U) == 4 || V.data() == OrigDataPtr);
 
   // There shouldn't be any live objects any more.
-  this->theVector.clear();
+  V.clear();
   EXPECT_EQ(Constructable::getNumConstructorCalls(),
             Constructable::getNumDestructorCalls());
 
@@ -1074,6 +1134,83 @@
   EXPECT_EQ(NestedV[0][0][0], 42);
 }
 
+TEST(SmallVectorTest, ToVector) {
+  {
+    std::vector<char> v = {'a', 'b', 'c'};
+    auto Vector = to_vector<4>(v);
+    static_assert(NumBuiltinElts(Vector) == 4u);
+    ASSERT_EQ(3u, Vector.size());
+    for (size_t I = 0; I < v.size(); ++I)
+      EXPECT_EQ(v[I], Vector[I]);
+  }
+  {
+    std::vector<char> v = {'a', 'b', 'c'};
+    auto Vector = to_vector(v);
+    static_assert(NumBuiltinElts(Vector) != 4u);
+    ASSERT_EQ(3u, Vector.size());
+    for (size_t I = 0; I < v.size(); ++I)
+      EXPECT_EQ(v[I], Vector[I]);
+  }
+}
+
+struct To {
+  int Content;
+  friend bool operator==(const To &LHS, const To &RHS) {
+    return LHS.Content == RHS.Content;
+  }
+};
+
+class From {
+public:
+  From() = default;
+  From(To M) { T = M; }
+  operator To() const { return T; }
+
+private:
+  To T;
+};
+
+TEST(SmallVectorTest, ConstructFromSpanOfConvertibleType) {
+  To to1{1}, to2{2}, to3{3};
+  std::vector<From> StdVector = {From(to1), From(to2), From(to3)};
+  std::span<const From> Array = StdVector;
+  {
+    wpi::SmallVector<To> Vector(Array);
+
+    ASSERT_EQ(Array.size(), Vector.size());
+    for (size_t I = 0; I < Array.size(); ++I)
+      EXPECT_EQ(Array[I], Vector[I]);
+  }
+  {
+    wpi::SmallVector<To, 4> Vector(Array);
+
+    ASSERT_EQ(Array.size(), Vector.size());
+    ASSERT_EQ(4u, NumBuiltinElts(Vector));
+    for (size_t I = 0; I < Array.size(); ++I)
+      EXPECT_EQ(Array[I], Vector[I]);
+  }
+}
+
+TEST(SmallVectorTest, ToVectorOf) {
+  To to1{1}, to2{2}, to3{3};
+  std::vector<From> StdVector = {From(to1), From(to2), From(to3)};
+  {
+    wpi::SmallVector<To> Vector = wpi::to_vector_of<To>(StdVector);
+
+    ASSERT_EQ(StdVector.size(), Vector.size());
+    for (size_t I = 0; I < StdVector.size(); ++I)
+      EXPECT_EQ(StdVector[I], Vector[I]);
+  }
+  {
+    auto Vector = wpi::to_vector_of<To, 4>(StdVector);
+
+    ASSERT_EQ(StdVector.size(), Vector.size());
+    static_assert(NumBuiltinElts(Vector) == 4u);
+    for (size_t I = 0; I < StdVector.size(); ++I)
+      EXPECT_EQ(StdVector[I], Vector[I]);
+  }
+}
+
 template <class VectorT>
 class SmallVectorReferenceInvalidationTest : public SmallVectorTestBase {
 protected:
@@ -1083,13 +1220,8 @@
 
   VectorT V;
 
-  template <typename T, unsigned N>
-  static unsigned NumBuiltinElts(const SmallVector<T, N> &) {
-    return N;
-  }
-
   template <class T> static bool isValueType() {
-    return std::is_same<T, typename VectorT::value_type>::value;
+    return std::is_same_v<T, typename VectorT::value_type>;
   }
 
   void SetUp() override {
@@ -1113,7 +1245,7 @@
 TYPED_TEST(SmallVectorReferenceInvalidationTest, PushBack) {
   // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
   auto &V = this->V;
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
 
   // Push back a reference to last element when growing from small storage.
   V.push_back(V.back());
@@ -1135,7 +1267,7 @@
 TYPED_TEST(SmallVectorReferenceInvalidationTest, PushBackMoved) {
   // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
   auto &V = this->V;
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
 
   // Push back a reference to last element when growing from small storage.
   V.push_back(std::move(V.back()));
@@ -1164,7 +1296,7 @@
 TYPED_TEST(SmallVectorReferenceInvalidationTest, Resize) {
   auto &V = this->V;
   (void)V;
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
   V.resize(N + 1, V.back());
   EXPECT_EQ(N, V.back());
 
@@ -1179,7 +1311,7 @@
   auto &V = this->V;
   (void)V;
   V.append(1, V.back());
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
   EXPECT_EQ(N, V[N - 1]);
 
   // Append enough more elements that V will grow again. This tests growing
@@ -1197,7 +1329,7 @@
 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
   EXPECT_DEATH(V.append(V.begin(), V.begin() + 1), this->AssertionMessage);
 
-  ASSERT_EQ(3u, this->NumBuiltinElts(V));
+  ASSERT_EQ(3u, NumBuiltinElts(V));
   ASSERT_EQ(3u, V.size());
   V.pop_back();
   ASSERT_EQ(2u, V.size());
@@ -1212,7 +1344,7 @@
   // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
   auto &V = this->V;
   (void)V;
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
   ASSERT_EQ(unsigned(N), V.size());
   ASSERT_EQ(unsigned(N), V.capacity());
 
@@ -1312,7 +1444,7 @@
 
   // Cover NumToInsert <= this->end() - I.
   V.insert(V.begin() + 1, 1, V.back());
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
   EXPECT_EQ(N, V[1]);
 
   // Cover NumToInsert > this->end() - I, inserting enough elements that V will
@@ -1332,7 +1464,7 @@
   EXPECT_DEATH(V.insert(V.begin(), V.begin(), V.begin() + 1),
                this->AssertionMessage);
 
-  ASSERT_EQ(3u, this->NumBuiltinElts(V));
+  ASSERT_EQ(3u, NumBuiltinElts(V));
   ASSERT_EQ(3u, V.size());
   V.pop_back();
   ASSERT_EQ(2u, V.size());
@@ -1346,7 +1478,7 @@
 TYPED_TEST(SmallVectorReferenceInvalidationTest, EmplaceBack) {
   // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
   auto &V = this->V;
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
 
   // Push back a reference to last element when growing from small storage.
   V.emplace_back(V.back());
@@ -1375,11 +1507,6 @@
 
   VectorT V;
 
-  template <typename T, unsigned N>
-  static unsigned NumBuiltinElts(const SmallVector<T, N> &) {
-    return N;
-  }
-
   void SetUp() override {
     SmallVectorTestBase::SetUp();
 
@@ -1400,7 +1527,7 @@
 TYPED_TEST(SmallVectorInternalReferenceInvalidationTest, EmplaceBack) {
   // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
   auto &V = this->V;
-  int N = this->NumBuiltinElts(V);
+  int N = NumBuiltinElts(V);
 
   // Push back a reference to last element when growing from small storage.
   V.emplace_back(V.back().first, V.back().second);
diff --git a/wpiutil/src/test/native/cpp/llvm/StringMapTest.cpp b/wpiutil/src/test/native/cpp/llvm/StringMapTest.cpp
index 71baa20..7607498 100644
--- a/wpiutil/src/test/native/cpp/llvm/StringMapTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/StringMapTest.cpp
@@ -15,6 +15,10 @@
 
 namespace {
 
+static_assert(sizeof(StringMap<uint32_t>) <
+                  sizeof(StringMap<uint32_t, MallocAllocator &>),
+              "Ensure empty base optimization happens with default allocator");
+
 // Test fixture
 class StringMapTest : public testing::Test {
 protected:
@@ -22,7 +26,7 @@
 
   static const char testKey[];
   static const uint32_t testValue;
-  static const char* testKeyFirst;
+  static const char *testKeyFirst;
   static size_t testKeyLength;
   static const std::string testKeyStr;
 
@@ -35,11 +39,12 @@
     EXPECT_TRUE(testMap.begin() == testMap.end());
 
     // Lookup tests
+    EXPECT_FALSE(testMap.contains(testKey));
     EXPECT_EQ(0u, testMap.count(testKey));
     EXPECT_EQ(0u, testMap.count(std::string_view(testKeyFirst, testKeyLength)));
     EXPECT_EQ(0u, testMap.count(testKeyStr));
     EXPECT_TRUE(testMap.find(testKey) == testMap.end());
-    EXPECT_TRUE(testMap.find(std::string_view(testKeyFirst, testKeyLength)) == 
+    EXPECT_TRUE(testMap.find(std::string_view(testKeyFirst, testKeyLength)) ==
                 testMap.end());
     EXPECT_TRUE(testMap.find(testKeyStr) == testMap.end());
   }
@@ -58,11 +63,12 @@
     EXPECT_TRUE(it == testMap.end());
 
     // Lookup tests
+    EXPECT_TRUE(testMap.contains(testKey));
     EXPECT_EQ(1u, testMap.count(testKey));
     EXPECT_EQ(1u, testMap.count(std::string_view(testKeyFirst, testKeyLength)));
     EXPECT_EQ(1u, testMap.count(testKeyStr));
     EXPECT_TRUE(testMap.find(testKey) == testMap.begin());
-    EXPECT_TRUE(testMap.find(std::string_view(testKeyFirst, testKeyLength)) == 
+    EXPECT_TRUE(testMap.find(std::string_view(testKeyFirst, testKeyLength)) ==
                 testMap.begin());
     EXPECT_TRUE(testMap.find(testKeyStr) == testMap.begin());
   }
@@ -70,7 +76,7 @@
 
 const char StringMapTest::testKey[] = "key";
 const uint32_t StringMapTest::testValue = 1u;
-const char* StringMapTest::testKeyFirst = testKey;
+const char *StringMapTest::testKeyFirst = testKey;
 size_t StringMapTest::testKeyLength = sizeof(testKey) - 1;
 const std::string StringMapTest::testKeyStr(testKey);
 
@@ -85,13 +91,11 @@
 };
 
 // Empty map tests.
-TEST_F(StringMapTest, EmptyMapTest) {
-  assertEmptyMap();
-}
+TEST_F(StringMapTest, EmptyMapTest) { assertEmptyMap(); }
 
 // Constant map tests.
 TEST_F(StringMapTest, ConstEmptyMapTest) {
-  const StringMap<uint32_t>& constTestMap = testMap;
+  const StringMap<uint32_t> &constTestMap = testMap;
 
   // Size tests
   EXPECT_EQ(0u, constTestMap.size());
@@ -201,6 +205,18 @@
   EXPECT_EQ(5, Map2.lookup("funf"));
 }
 
+TEST_F(StringMapTest, AtTest) {
+  wpi::StringMap<int> Map;
+
+  // keys both found and not found on non-empty map
+  Map["a"] = 1;
+  Map["b"] = 2;
+  Map["c"] = 3;
+  EXPECT_EQ(1, Map.at("a"));
+  EXPECT_EQ(2, Map.at("b"));
+  EXPECT_EQ(3, Map.at("c"));
+}
+
 // A more complex iteration test.
 TEST_F(StringMapTest, IterationTest) {
   bool visited[100];
@@ -214,8 +230,8 @@
   }
 
   // Iterate over all numbers and mark each one found.
-  for (StringMap<uint32_t>::iterator it = testMap.begin();
-      it != testMap.end(); ++it) {
+  for (StringMap<uint32_t>::iterator it = testMap.begin(); it != testMap.end();
+       ++it) {
     std::stringstream ss;
     ss << "key_" << it->second;
     ASSERT_STREQ(ss.str().c_str(), it->first().data());
@@ -232,7 +248,7 @@
 TEST_F(StringMapTest, StringMapEntryTest) {
   MallocAllocator Allocator;
   StringMap<uint32_t>::value_type *entry =
-      StringMap<uint32_t>::value_type::Create(
+      StringMap<uint32_t>::value_type::create(
           std::string_view(testKeyFirst, testKeyLength), Allocator, 1u);
   EXPECT_STREQ(testKey, entry->first().data());
   EXPECT_EQ(1u, entry->second);
@@ -242,10 +258,8 @@
 // Test insert() method.
 TEST_F(StringMapTest, InsertTest) {
   SCOPED_TRACE("InsertTest");
-  testMap.insert(
-      StringMap<uint32_t>::value_type::Create(
-          std::string_view(testKeyFirst, testKeyLength),
-          testMap.getAllocator(), 1u));
+  testMap.insert(StringMap<uint32_t>::value_type::create(
+      std::string_view(testKeyFirst, testKeyLength), testMap.getAllocator(), 1u));
   assertSingleItemMap();
 }
 
@@ -280,7 +294,7 @@
   EXPECT_EQ(0u, t.getNumBuckets());
 
   StringMap<uint32_t>::iterator It =
-    t.insert(std::make_pair("abcdef", 42)).first;
+      t.insert(std::make_pair("abcdef", 42)).first;
   EXPECT_EQ(16u, t.getNumBuckets());
   EXPECT_EQ("abcdef", It->first());
   EXPECT_EQ(42u, It->second);
@@ -338,13 +352,13 @@
 
 struct Immovable {
   Immovable() {}
-  Immovable(Immovable&&) = delete; // will disable the other special members
+  Immovable(Immovable &&) = delete; // will disable the other special members
 };
 
 struct MoveOnly {
   int i;
   MoveOnly(int i) : i(i) {}
-  MoveOnly(const Immovable&) : i(0) {}
+  MoveOnly(const Immovable &) : i(0) {}
   MoveOnly(MoveOnly &&RHS) : i(RHS.i) {}
   MoveOnly &operator=(MoveOnly &&RHS) {
     i = RHS.i;
@@ -360,14 +374,14 @@
   StringMap<MoveOnly> t;
   t.insert(std::make_pair("Test", MoveOnly(42)));
   std::string_view Key = "Test";
-  StringMapEntry<MoveOnly>::Create(Key, t.getAllocator(), MoveOnly(42))
+  StringMapEntry<MoveOnly>::create(Key, t.getAllocator(), MoveOnly(42))
       ->Destroy(t.getAllocator());
 }
 
 TEST_F(StringMapTest, CtorArg) {
   std::string_view Key = "Test";
   MallocAllocator Allocator;
-  StringMapEntry<MoveOnly>::Create(Key, Allocator, Immovable())
+  StringMapEntry<MoveOnly>::create(Key, Allocator, Immovable())
       ->Destroy(Allocator);
 }
 
@@ -501,6 +515,16 @@
   ASSERT_TRUE(B.empty());
 }
 
+TEST_F(StringMapTest, StructuredBindings) {
+  StringMap<int> A;
+  A["a"] = 42;
+
+  for (auto &[Key, Value] : A) {
+    EXPECT_EQ("a", Key);
+    EXPECT_EQ(42, Value);
+  }
+}
+
 namespace {
 // Simple class that counts how many moves and copy happens when growing a map
 struct CountCtorCopyAndMove {
@@ -570,7 +594,7 @@
   NonMoveableNonCopyableType(const NonMoveableNonCopyableType &) = delete;
   NonMoveableNonCopyableType(NonMoveableNonCopyableType &&) = delete;
 };
-}
+} // namespace
 
 // Test that we can "emplace" an element in the map without involving map/move
 TEST(StringMapCustomTest, EmplaceTest) {
diff --git a/wpiutil/src/test/native/cpp/llvm/SwapByteOrderTest.cpp b/wpiutil/src/test/native/cpp/llvm/SwapByteOrderTest.cpp
index abacef7..23ad2ab 100644
--- a/wpiutil/src/test/native/cpp/llvm/SwapByteOrderTest.cpp
+++ b/wpiutil/src/test/native/cpp/llvm/SwapByteOrderTest.cpp
@@ -16,16 +16,6 @@
 
 namespace {
 
-TEST(ByteSwap, Swap_32) {
-  EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
-  EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));
-}
-
-TEST(ByteSwap, Swap_64) {
-  EXPECT_EQ(0x8877665544332211ULL, ByteSwap_64(0x1122334455667788LL));
-  EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL));
-}
-
 // In these first two tests all of the original_uintx values are truncated
 // except for 64. We could avoid this, but there's really no point.
 
diff --git a/wpiutil/src/test/native/cpp/llvm/xxhashTest.cpp b/wpiutil/src/test/native/cpp/llvm/xxhashTest.cpp
new file mode 100644
index 0000000..133c542
--- /dev/null
+++ b/wpiutil/src/test/native/cpp/llvm/xxhashTest.cpp
@@ -0,0 +1,63 @@
+//===- llvm/unittest/Support/xxhashTest.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/xxhash.h"
+#include "gtest/gtest.h"
+
+using namespace wpi;
+
+TEST(xxhashTest, Basic) {
+  EXPECT_EQ(0xef46db3751d8e999U, xxHash64(std::string_view()));
+  EXPECT_EQ(0x33bf00a859c4ba3fU, xxHash64("foo"));
+  EXPECT_EQ(0x48a37c90ad27a659U, xxHash64("bar"));
+  EXPECT_EQ(0x69196c1b3af0bff9U,
+            xxHash64("0123456789abcdefghijklmnopqrstuvwxyz"));
+}
+
+TEST(xxhashTest, xxh3) {
+  constexpr size_t size = 2243;
+  uint8_t a[size];
+  uint64_t x = 1;
+  for (size_t i = 0; i < size; ++i) {
+    x ^= x << 13;
+    x ^= x >> 7;
+    x ^= x << 17;
+    a[i] = uint8_t(x);
+  }
+
+#define F(len, expected)                                                       \
+  EXPECT_EQ(uint64_t(expected), xxh3_64bits(std::span(a, size_t(len))))
+  F(0, 0x2d06800538d394c2);
+  F(1, 0xd0d496e05c553485);
+  F(2, 0x84d625edb7055eac);
+  F(3, 0x6ea2d59aca5c3778);
+  F(4, 0xbf65290914e80242);
+  F(5, 0xc01fd099ad4fc8e4);
+  F(6, 0x9e3ea8187399caa5);
+  F(7, 0x9da8b60540644f5a);
+  F(8, 0xabc1413da6cd0209);
+  F(9, 0x8bc89400bfed51f6);
+  F(16, 0x7e46916754d7c9b8);
+  F(17, 0xed4be912ba5f836d);
+  F(32, 0xf59b59b58c304fd1);
+  F(33, 0x9013fb74ca603e0c);
+  F(64, 0xfa5271fcce0db1c3);
+  F(65, 0x79c42431727f1012);
+  F(96, 0x591ee0ddf9c9ccd1);
+  F(97, 0x8ffc6a3111fe19da);
+  F(128, 0x06a146ee9a2da378);
+  F(129, 0xbc7138129bf065da);
+  F(403, 0xcefeb3ffa532ad8c);
+  F(512, 0xcdfa6b6268e3650f);
+  F(513, 0x4bb5d42742f9765f);
+  F(2048, 0x330ce110cbb79eae);
+  F(2049, 0x3ba6afa0249fef9a);
+  F(2240, 0xd61d4d2a94e926a8);
+  F(2243, 0x0979f786a24edde7);
+#undef F
+}
diff --git a/wpiutil/src/test/native/cpp/main.cpp b/wpiutil/src/test/native/cpp/main.cpp
index 09072ee..e993c1f 100644
--- a/wpiutil/src/test/native/cpp/main.cpp
+++ b/wpiutil/src/test/native/cpp/main.cpp
@@ -2,7 +2,7 @@
 // Open Source Software; you can modify and/or share it under the terms of
 // the WPILib BSD license file in the root directory of this project.
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/wpiutil/src/test/native/cpp/priority_mutex_test.cpp b/wpiutil/src/test/native/cpp/priority_mutex_test.cpp
index 832e8f3..8e2ec3e 100644
--- a/wpiutil/src/test/native/cpp/priority_mutex_test.cpp
+++ b/wpiutil/src/test/native/cpp/priority_mutex_test.cpp
@@ -8,7 +8,7 @@
 #include <condition_variable>
 #include <thread>
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 namespace wpi {
 
@@ -157,7 +157,7 @@
 //
 // To run the test, we need 3 threads, and then 1 thread to kick the test off.
 // The threads must all run on the same core, otherwise they wouldn't starve
-// eachother. The threads and their roles are as follows:
+// each other. The threads and their roles are as follows:
 //
 // Low priority thread:
 //   Holds a lock that the high priority thread needs, and releases it upon
diff --git a/wpiutil/src/test/native/cpp/sha1Test.cpp b/wpiutil/src/test/native/cpp/sha1Test.cpp
index 0257431..814e47e 100644
--- a/wpiutil/src/test/native/cpp/sha1Test.cpp
+++ b/wpiutil/src/test/native/cpp/sha1Test.cpp
@@ -21,7 +21,8 @@
 
 #include <string>
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+
 #include "wpi/sha1.h"
 
 namespace wpi {
diff --git a/wpiutil/src/test/native/cpp/sigslot/function-traits.cpp b/wpiutil/src/test/native/cpp/sigslot/function-traits.cpp
index f31e296..9901488 100644
--- a/wpiutil/src/test/native/cpp/sigslot/function-traits.cpp
+++ b/wpiutil/src/test/native/cpp/sigslot/function-traits.cpp
@@ -33,10 +33,10 @@
 
 #include "wpi/Signal.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"  // NOLINT(build/include_order)
-
 #include <type_traits>
 
+#include <gtest/gtest.h>
+
 using namespace wpi::sig::trait;
 
 namespace {
diff --git a/wpiutil/src/test/native/cpp/sigslot/recursive.cpp b/wpiutil/src/test/native/cpp/sigslot/recursive.cpp
index 82613f2..6d35f78 100644
--- a/wpiutil/src/test/native/cpp/sigslot/recursive.cpp
+++ b/wpiutil/src/test/native/cpp/sigslot/recursive.cpp
@@ -33,7 +33,7 @@
 
 #include "wpi/Signal.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 namespace {
 
diff --git a/wpiutil/src/test/native/cpp/sigslot/signal-extended.cpp b/wpiutil/src/test/native/cpp/sigslot/signal-extended.cpp
index a0dbdfc..e863ca6 100644
--- a/wpiutil/src/test/native/cpp/sigslot/signal-extended.cpp
+++ b/wpiutil/src/test/native/cpp/sigslot/signal-extended.cpp
@@ -33,7 +33,7 @@
 
 #include "wpi/Signal.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"
+#include <gtest/gtest.h>
 
 using namespace wpi::sig;
 
diff --git a/wpiutil/src/test/native/cpp/sigslot/signal-threaded.cpp b/wpiutil/src/test/native/cpp/sigslot/signal-threaded.cpp
index 00001a8..15dc3a8 100644
--- a/wpiutil/src/test/native/cpp/sigslot/signal-threaded.cpp
+++ b/wpiutil/src/test/native/cpp/sigslot/signal-threaded.cpp
@@ -33,12 +33,12 @@
 
 #include "wpi/Signal.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"  // NOLINT(build/include_order)
-
 #include <array>
 #include <atomic>
 #include <thread>
 
+#include <gtest/gtest.h>
+
 using namespace wpi::sig;
 
 namespace {
diff --git a/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp b/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp
index d05ee1a..b77f5a4 100644
--- a/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp
+++ b/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp
@@ -33,12 +33,12 @@
 
 #include "wpi/Signal.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"  // NOLINT(build/include_order)
-
 #include <cmath>
 #include <sstream>
 #include <string>
 
+#include <gtest/gtest.h>
+
 using namespace wpi::sig;
 
 namespace {
diff --git a/wpiutil/src/test/native/cpp/sigslot/signal.cpp b/wpiutil/src/test/native/cpp/sigslot/signal.cpp
index cc2ff80..34d149e 100644
--- a/wpiutil/src/test/native/cpp/sigslot/signal.cpp
+++ b/wpiutil/src/test/native/cpp/sigslot/signal.cpp
@@ -33,12 +33,12 @@
 
 #include "wpi/Signal.h"  // NOLINT(build/include_order)
 
-#include "gtest/gtest.h"  // NOLINT(build/include_order)
-
 #include <cmath>
 #include <sstream>
 #include <string>
 
+#include <gtest/gtest.h>
+
 using namespace wpi::sig;
 
 namespace {
diff --git a/wpiutil/src/test/native/cpp/spinlock_bench.cpp b/wpiutil/src/test/native/cpp/spinlock_bench.cpp
index 9534837..c8af3d2 100644
--- a/wpiutil/src/test/native/cpp/spinlock_bench.cpp
+++ b/wpiutil/src/test/native/cpp/spinlock_bench.cpp
@@ -8,8 +8,9 @@
 #include <mutex>
 #include <thread>
 
-#include "fmt/core.h"
-#include "gtest/gtest.h"
+#include <fmt/core.h>
+#include <gtest/gtest.h>
+
 #include "wpi/mutex.h"
 
 static std::mutex std_mutex;
@@ -28,7 +29,7 @@
 
   // warmup
   std::thread thr([]() {
-    int value = 0;
+    [[maybe_unused]] int value = 0;
 
     auto start = high_resolution_clock::now();
     for (int i = 0; i < 10000000; i++) {
diff --git a/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp b/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp
new file mode 100644
index 0000000..d5d21d1
--- /dev/null
+++ b/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp
@@ -0,0 +1,358 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/struct/DynamicStruct.h"  // NOLINT(build/include_order)
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+using namespace wpi;
+
+class DynamicStructTest : public ::testing::Test {
+ protected:
+  StructDescriptorDatabase db;
+  std::string err;
+};
+
+TEST_F(DynamicStructTest, Empty) {
+  auto desc = db.Add("test", "", &err);
+  ASSERT_TRUE(desc);
+  ASSERT_EQ(desc->GetName(), "test");
+  ASSERT_EQ(desc->GetSchema(), "");
+  ASSERT_TRUE(desc->GetFields().empty());
+  ASSERT_TRUE(desc->IsValid());
+  ASSERT_EQ(desc->GetSize(), 0u);
+}
+
+TEST_F(DynamicStructTest, NestedStruct) {
+  auto desc = db.Add("test", "int32 a", &err);
+  ASSERT_TRUE(desc);
+  ASSERT_TRUE(desc->IsValid());
+  auto desc2 = db.Add("test2", "test a", &err);
+  ASSERT_TRUE(desc2);
+  ASSERT_TRUE(desc2->IsValid());
+  ASSERT_EQ(desc2->GetSize(), 4u);
+}
+
+TEST_F(DynamicStructTest, DelayedValid) {
+  auto desc = db.Add("test", "foo a", &err);
+  ASSERT_TRUE(desc);
+  ASSERT_FALSE(desc->IsValid());
+  auto desc2 = db.Add("test2", "foo a[2]", &err);
+  ASSERT_TRUE(desc2);
+  ASSERT_FALSE(desc2->IsValid());
+  auto desc3 = db.Add("foo", "int32 a", &err);
+  ASSERT_TRUE(desc3);
+  ASSERT_TRUE(desc3->IsValid());
+  ASSERT_TRUE(desc->IsValid());
+  ASSERT_EQ(desc->GetSize(), 4u);
+  ASSERT_TRUE(desc2->IsValid());
+  ASSERT_EQ(desc2->GetSize(), 8u);
+}
+
+TEST_F(DynamicStructTest, InvalidBitfield) {
+  auto desc = db.Add("test", "float a:1", &err);
+  EXPECT_FALSE(desc);
+  EXPECT_EQ(err, "field a: type float cannot be bitfield");
+
+  desc = db.Add("test", "double a:1", &err);
+  EXPECT_FALSE(desc);
+  EXPECT_EQ(err, "field a: type double cannot be bitfield");
+
+  desc = db.Add("test", "foo a:1", &err);
+  EXPECT_FALSE(desc);
+  EXPECT_EQ(err, "field a: type foo cannot be bitfield");
+}
+
+TEST_F(DynamicStructTest, CircularStructReference) {
+  auto desc = db.Add("test", "test a", &err);
+  ASSERT_FALSE(desc);
+  ASSERT_EQ(err, "field a: recursive struct reference");
+}
+
+TEST_F(DynamicStructTest, NestedCircularStructRef) {
+  auto desc = db.Add("test", "foo a", &err);
+  ASSERT_TRUE(desc);
+  auto desc2 = db.Add("foo", "bar a", &err);
+  ASSERT_TRUE(desc2);
+  auto desc3 = db.Add("bar", "test a", &err);
+  ASSERT_FALSE(desc3);
+  ASSERT_EQ(err, "circular struct reference: bar <- foo <- test");
+
+  // ok
+  auto desc4 = db.Add("baz", "bar a", &err);
+  ASSERT_TRUE(desc4);
+  ASSERT_FALSE(desc4->IsValid());
+}
+
+TEST_F(DynamicStructTest, NestedCircularStructRef2) {
+  auto desc = db.Add("test", "foo a", &err);
+  ASSERT_TRUE(desc);
+  auto desc2 = db.Add("bar", "test a", &err);
+  ASSERT_TRUE(desc2);
+  auto desc3 = db.Add("foo", "bar a", &err);
+  ASSERT_FALSE(desc3);
+  ASSERT_EQ(err, "circular struct reference: foo <- test <- bar");
+}
+
+TEST_F(DynamicStructTest, BitfieldBasic) {
+  auto desc = db.Add("test", "int32 a:2; uint32 b:30", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 4u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 2u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0x3u);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 4u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 30u);
+  EXPECT_EQ(fields[1].GetBitShift(), 2u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x3fffffffu);
+  EXPECT_EQ(fields[1].GetOffset(), 0u);
+  EXPECT_EQ(fields[1].GetSize(), 4u);
+}
+
+TEST_F(DynamicStructTest, BitfieldDiffType) {
+  auto desc = db.Add("test", "int32 a:2; int16 b:2", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 6u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 2u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0x3u);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 4u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 2u);
+  EXPECT_EQ(fields[1].GetBitShift(), 0u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x3u);
+  EXPECT_EQ(fields[1].GetOffset(), 4u);
+  EXPECT_EQ(fields[1].GetSize(), 2u);
+}
+
+TEST_F(DynamicStructTest, BitfieldOverflow) {
+  auto desc = db.Add("test", "int8 a:4; int8 b:5", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 2u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 4u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0xfu);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 1u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 5u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x1fu);
+  EXPECT_EQ(fields[1].GetBitShift(), 0u);
+  EXPECT_EQ(fields[1].GetOffset(), 1u);
+  EXPECT_EQ(fields[1].GetSize(), 1u);
+}
+
+TEST_F(DynamicStructTest, BitfieldBoolBegin8) {
+  auto desc = db.Add("test", "bool a:1; int8 b:5", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 1u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 1u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0x1u);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 1u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 5u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x1fu);
+  EXPECT_EQ(fields[1].GetBitShift(), 1u);
+  EXPECT_EQ(fields[1].GetOffset(), 0u);
+  EXPECT_EQ(fields[1].GetSize(), 1u);
+}
+
+TEST_F(DynamicStructTest, BitfieldBoolBegin16) {
+  auto desc = db.Add("test", "bool a:1; int16 b:5", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 3u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 1u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0x1u);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 1u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 5u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x1fu);
+  EXPECT_EQ(fields[1].GetBitShift(), 0u);
+  EXPECT_EQ(fields[1].GetOffset(), 1u);
+  EXPECT_EQ(fields[1].GetSize(), 2u);
+}
+
+TEST_F(DynamicStructTest, BitfieldBoolMid) {
+  auto desc = db.Add("test", "int16 a:2; bool b:1; bool c:1; uint16 d:5", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 2u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 4u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 2u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0x3u);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 2u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 1u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x1u);
+  EXPECT_EQ(fields[1].GetBitShift(), 2u);
+  EXPECT_EQ(fields[1].GetOffset(), 0u);
+  EXPECT_EQ(fields[1].GetSize(), 2u);
+  EXPECT_EQ(fields[2].GetBitWidth(), 1u);
+  EXPECT_EQ(fields[2].GetBitMask(), 0x1u);
+  EXPECT_EQ(fields[2].GetBitShift(), 3u);
+  EXPECT_EQ(fields[2].GetOffset(), 0u);
+  EXPECT_EQ(fields[2].GetSize(), 2u);
+  EXPECT_EQ(fields[3].GetBitWidth(), 5u);
+  EXPECT_EQ(fields[3].GetBitMask(), 0x1fu);
+  EXPECT_EQ(fields[3].GetBitShift(), 4u);
+  EXPECT_EQ(fields[3].GetOffset(), 0u);
+  EXPECT_EQ(fields[3].GetSize(), 2u);
+}
+
+TEST_F(DynamicStructTest, BitfieldBoolEnd) {
+  auto desc = db.Add("test", "int16 a:15; bool b:1", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 2u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 15u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0x7fffu);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 2u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 1u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x1u);
+  EXPECT_EQ(fields[1].GetBitShift(), 15u);
+  EXPECT_EQ(fields[1].GetOffset(), 0u);
+  EXPECT_EQ(fields[1].GetSize(), 2u);
+}
+
+TEST_F(DynamicStructTest, BitfieldBoolEnd2) {
+  auto desc = db.Add("test", "int16 a:16; bool b:1", &err);
+  ASSERT_TRUE(desc);
+  EXPECT_EQ(desc->GetSize(), 3u);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 2u);
+  EXPECT_EQ(fields[0].GetBitWidth(), 16u);
+  EXPECT_EQ(fields[0].GetBitShift(), 0u);
+  EXPECT_EQ(fields[0].GetBitMask(), 0xffffu);
+  EXPECT_EQ(fields[0].GetOffset(), 0u);
+  EXPECT_EQ(fields[0].GetSize(), 2u);
+  EXPECT_EQ(fields[1].GetBitWidth(), 1u);
+  EXPECT_EQ(fields[1].GetBitMask(), 0x1u);
+  EXPECT_EQ(fields[1].GetBitShift(), 0u);
+  EXPECT_EQ(fields[1].GetOffset(), 2u);
+  EXPECT_EQ(fields[1].GetSize(), 1u);
+}
+
+TEST_F(DynamicStructTest, BitfieldBoolWrongSize) {
+  auto desc = db.Add("test", "bool a:2", &err);
+  ASSERT_FALSE(desc);
+  ASSERT_EQ(err, "field a: bit width must be 1 for bool type");
+}
+
+TEST_F(DynamicStructTest, BitfieldTooBig) {
+  auto desc = db.Add("test", "int16 a:17", &err);
+  ASSERT_FALSE(desc);
+  ASSERT_EQ(err, "field a: bit width 17 exceeds type size");
+}
+
+TEST_F(DynamicStructTest, DuplicateFieldName) {
+  auto desc = db.Add("test", "int16 a; int8 a", &err);
+  ASSERT_FALSE(desc);
+  ASSERT_EQ(err, "duplicate field a");
+}
+
+struct SimpleTestParam {
+  const char* schema;
+  size_t size;
+  StructFieldType type;
+  bool isInt;
+  bool isUint;
+  unsigned int bitWidth;
+  uint64_t bitMask;
+};
+
+std::ostream& operator<<(std::ostream& os, const SimpleTestParam& param) {
+  return os << "SimpleTestParam(Schema: \"" << param.schema << "\")";
+}
+
+class DynamicSimpleStructTest
+    : public ::testing::TestWithParam<SimpleTestParam> {
+ protected:
+  StructDescriptorDatabase db;
+  std::string err;
+};
+
+TEST_P(DynamicSimpleStructTest, Check) {
+  auto desc = db.Add("test", GetParam().schema, &err);
+  ASSERT_TRUE(desc);
+  ASSERT_EQ(desc->GetName(), "test");
+  ASSERT_EQ(desc->GetSchema(), GetParam().schema);
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 1u);
+  EXPECT_EQ(fields[0].GetParent(), desc);
+  EXPECT_EQ(fields[0].GetName(), "a");
+  EXPECT_EQ(fields[0].IsInt(), GetParam().isInt);
+  EXPECT_EQ(fields[0].IsUint(), GetParam().isUint);
+  EXPECT_FALSE(fields[0].IsArray());
+  if (GetParam().type != StructFieldType::kStruct) {
+    ASSERT_TRUE(desc->IsValid());
+    ASSERT_EQ(desc->GetSize(), GetParam().size);
+    ASSERT_EQ(fields[0].GetSize(), GetParam().size);
+    ASSERT_EQ(fields[0].GetBitWidth(), GetParam().bitWidth);
+    ASSERT_EQ(fields[0].GetBitMask(), GetParam().bitMask);
+  } else {
+    ASSERT_FALSE(desc->IsValid());
+    ASSERT_TRUE(fields[0].GetStruct());
+  }
+}
+
+TEST_P(DynamicSimpleStructTest, Array) {
+  auto desc = db.Add("test", GetParam().schema + std::string{"[2]"}, &err);
+  ASSERT_TRUE(desc);
+  ASSERT_EQ(desc->GetName(), "test");
+  ASSERT_EQ(desc->GetSchema(), GetParam().schema + std::string{"[2]"});
+  auto& fields = desc->GetFields();
+  ASSERT_EQ(fields.size(), 1u);
+  EXPECT_EQ(fields[0].GetParent(), desc);
+  EXPECT_EQ(fields[0].GetName(), "a");
+  EXPECT_EQ(fields[0].IsInt(), GetParam().isInt);
+  EXPECT_EQ(fields[0].IsUint(), GetParam().isUint);
+  EXPECT_TRUE(fields[0].IsArray());
+  EXPECT_EQ(fields[0].GetArraySize(), 2u);
+  if (GetParam().type != StructFieldType::kStruct) {
+    ASSERT_TRUE(desc->IsValid());
+    ASSERT_EQ(desc->GetSize(), GetParam().size * 2u);
+  } else {
+    ASSERT_FALSE(desc->IsValid());
+    ASSERT_TRUE(fields[0].GetStruct());
+  }
+}
+
+static SimpleTestParam simpleTests[] = {
+    {"bool a", 1, StructFieldType::kBool, false, false, 8, UINT8_MAX},
+    {"char a", 1, StructFieldType::kChar, false, false, 8, UINT8_MAX},
+    {"int8 a", 1, StructFieldType::kInt8, true, false, 8, UINT8_MAX},
+    {"int16 a", 2, StructFieldType::kInt16, true, false, 16, UINT16_MAX},
+    {"int32 a", 4, StructFieldType::kInt32, true, false, 32, UINT32_MAX},
+    {"int64 a", 8, StructFieldType::kInt64, true, false, 64, UINT64_MAX},
+    {"uint8 a", 1, StructFieldType::kUint8, false, true, 8, UINT8_MAX},
+    {"uint16 a", 2, StructFieldType::kUint16, false, true, 16, UINT16_MAX},
+    {"uint32 a", 4, StructFieldType::kUint32, false, true, 32, UINT32_MAX},
+    {"uint64 a", 8, StructFieldType::kUint64, false, true, 64, UINT64_MAX},
+    {"float a", 4, StructFieldType::kFloat, false, false, 32, UINT32_MAX},
+    {"float32 a", 4, StructFieldType::kFloat, false, false, 32, UINT32_MAX},
+    {"double a", 8, StructFieldType::kDouble, false, false, 64, UINT64_MAX},
+    {"float64 a", 8, StructFieldType::kDouble, false, false, 64, UINT64_MAX},
+    {"foo a", 0, StructFieldType::kStruct, false, false, 0, 0},
+};
+
+INSTANTIATE_TEST_SUITE_P(DynamicSimpleStructTests, DynamicSimpleStructTest,
+                         ::testing::ValuesIn(simpleTests));
diff --git a/wpiutil/src/test/native/cpp/struct/SchemaParserTest.cpp b/wpiutil/src/test/native/cpp/struct/SchemaParserTest.cpp
new file mode 100644
index 0000000..bf24141
--- /dev/null
+++ b/wpiutil/src/test/native/cpp/struct/SchemaParserTest.cpp
@@ -0,0 +1,218 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "wpi/struct/SchemaParser.h"  // NOLINT(build/include_order)
+
+#include <gtest/gtest.h>
+
+using namespace wpi::structparser;
+
+TEST(StructParserTest, Empty) {
+  Parser p{""};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_TRUE(schema.declarations.empty());
+}
+
+TEST(StructParserTest, EmptySemicolon) {
+  Parser p{";"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_TRUE(schema.declarations.empty());
+}
+
+TEST(StructParserTest, Simple) {
+  Parser p{"int32 a"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  EXPECT_EQ(decl.arraySize, 1u);
+}
+
+TEST(StructParserTest, SimpleTrailingSemi) {
+  Parser p{"int32 a;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+}
+
+TEST(StructParserTest, Array) {
+  Parser p{"int32 a[2]"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  EXPECT_EQ(decl.arraySize, 2u);
+}
+
+TEST(StructParserTest, ArrayTrailingSemi) {
+  Parser p{"int32 a[2];"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+}
+
+TEST(StructParserTest, Bitfield) {
+  Parser p{"int32 a:2"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  EXPECT_EQ(decl.bitWidth, 2u);
+}
+
+TEST(StructParserTest, BitfieldTrailingSemi) {
+  Parser p{"int32 a:2;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+}
+
+TEST(StructParserTest, EnumKeyword) {
+  Parser p{"enum {x=1} int32 a;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  ASSERT_EQ(decl.enumValues.size(), 1u);
+  EXPECT_EQ(decl.enumValues[0].first, "x");
+  EXPECT_EQ(decl.enumValues[0].second, 1);
+}
+
+TEST(StructParserTest, EnumNoKeyword) {
+  Parser p{"{x=1} int32 a;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  ASSERT_EQ(decl.enumValues.size(), 1u);
+  EXPECT_EQ(decl.enumValues[0].first, "x");
+  EXPECT_EQ(decl.enumValues[0].second, 1);
+}
+
+TEST(StructParserTest, EnumNoValues) {
+  Parser p{"{} int32 a;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  ASSERT_TRUE(decl.enumValues.empty());
+}
+
+TEST(StructParserTest, EnumMultipleValues) {
+  Parser p{"{x=1,y=-2} int32 a;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  ASSERT_EQ(decl.enumValues.size(), 2u);
+  EXPECT_EQ(decl.enumValues[0].first, "x");
+  EXPECT_EQ(decl.enumValues[0].second, 1);
+  EXPECT_EQ(decl.enumValues[1].first, "y");
+  EXPECT_EQ(decl.enumValues[1].second, -2);
+}
+
+TEST(StructParserTest, EnumTrailingComma) {
+  Parser p{"{x=1,y=2,} int32 a;"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 1u);
+  auto& decl = schema.declarations[0];
+  EXPECT_EQ(decl.typeString, "int32");
+  EXPECT_EQ(decl.name, "a");
+  ASSERT_EQ(decl.enumValues.size(), 2u);
+  EXPECT_EQ(decl.enumValues[0].first, "x");
+  EXPECT_EQ(decl.enumValues[0].second, 1);
+  EXPECT_EQ(decl.enumValues[1].first, "y");
+  EXPECT_EQ(decl.enumValues[1].second, 2);
+}
+
+TEST(StructParserTest, MultipleNoTrailingSemi) {
+  Parser p{"int32 a; int16 b"};
+  ParsedSchema schema;
+  ASSERT_TRUE(p.Parse(&schema));
+  ASSERT_EQ(schema.declarations.size(), 2u);
+  EXPECT_EQ(schema.declarations[0].typeString, "int32");
+  EXPECT_EQ(schema.declarations[0].name, "a");
+  EXPECT_EQ(schema.declarations[1].typeString, "int16");
+  EXPECT_EQ(schema.declarations[1].name, "b");
+}
+
+TEST(StructParserTest, ErrBitfieldArray) {
+  Parser p{"int32 a[1]:2"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "10: expected ';', got ':'");
+}
+
+TEST(StructParserTest, ErrNoArrayValue) {
+  Parser p{"int32 a[]"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "8: expected integer, got ']'");
+}
+
+TEST(StructParserTest, ErrNoBitfieldValue) {
+  Parser p{"int32 a:"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "8: expected integer, got ''");
+}
+
+TEST(StructParserTest, ErrNoNameArray) {
+  Parser p{"int32 [2]"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "6: expected identifier, got '['");
+}
+
+TEST(StructParserTest, ErrNoNameBitField) {
+  Parser p{"int32 :2"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "6: expected identifier, got ':'");
+}
+
+TEST(StructParserTest, NegativeBitField) {
+  Parser p{"int32 a:-1"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "8: bitfield width '-1' is not a positive integer");
+}
+
+TEST(StructParserTest, NegativeArraySize) {
+  Parser p{"int32 a[-1]"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "8: array size '-1' is not a positive integer");
+}
+
+TEST(StructParserTest, ZeroBitField) {
+  Parser p{"int32 a:0"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "8: bitfield width '0' is not a positive integer");
+}
+
+TEST(StructParserTest, ZeroArraySize) {
+  Parser p{"int32 a[0]"};
+  ParsedSchema schema;
+  ASSERT_FALSE(p.Parse(&schema));
+  ASSERT_EQ(p.GetError(), "8: array size '0' is not a positive integer");
+}
diff --git a/wpiutil/src/test/native/include/wpi/SpanMatcher.h b/wpiutil/src/test/native/include/wpi/SpanMatcher.h
new file mode 100644
index 0000000..247c142
--- /dev/null
+++ b/wpiutil/src/test/native/include/wpi/SpanMatcher.h
@@ -0,0 +1,75 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <algorithm>
+#include <initializer_list>
+#include <memory>
+#include <ostream>
+#include <span>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+#include "wpi/TestPrinters.h"
+
+namespace wpi {
+
+template <typename T>
+class SpanMatcher : public ::testing::MatcherInterface<std::span<T>> {
+ public:
+  explicit SpanMatcher(std::span<T> good_) : good{good_.begin(), good_.end()} {}
+
+  bool MatchAndExplain(std::span<T> val,
+                       ::testing::MatchResultListener* listener) const override;
+  void DescribeTo(::std::ostream* os) const override;
+  void DescribeNegationTo(::std::ostream* os) const override;
+
+ private:
+  std::vector<std::remove_cv_t<T>> good;
+};
+
+template <typename T>
+inline ::testing::Matcher<std::span<const typename T::value_type>> SpanEq(
+    const T& good) {
+  return ::testing::MakeMatcher(
+      new SpanMatcher(std::span<const typename T::value_type>(good)));
+}
+
+template <typename T>
+inline ::testing::Matcher<std::span<const T>> SpanEq(
+    std::initializer_list<const T> good) {
+  return ::testing::MakeMatcher(
+      new SpanMatcher<const T>({good.begin(), good.end()}));
+}
+
+template <typename T>
+bool SpanMatcher<T>::MatchAndExplain(
+    std::span<T> val, ::testing::MatchResultListener* listener) const {
+  if (val.size() != good.size() ||
+      !std::equal(val.begin(), val.end(), good.begin())) {
+    return false;
+  }
+  return true;
+}
+
+template <typename T>
+void SpanMatcher<T>::DescribeTo(::std::ostream* os) const {
+  PrintTo(std::span<T>{good}, os);
+}
+
+template <typename T>
+void SpanMatcher<T>::DescribeNegationTo(::std::ostream* os) const {
+  *os << "is not equal to ";
+  PrintTo(std::span<T>{good}, os);
+}
+
+}  // namespace wpi
+
+inline std::span<const uint8_t> operator"" _us(const char* str, size_t len) {
+  return {reinterpret_cast<const uint8_t*>(str), len};
+}
diff --git a/wpiutil/src/test/native/include/wpi/TestPrinters.h b/wpiutil/src/test/native/include/wpi/TestPrinters.h
new file mode 100644
index 0000000..72d7da3
--- /dev/null
+++ b/wpiutil/src/test/native/include/wpi/TestPrinters.h
@@ -0,0 +1,41 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <ostream>
+#include <span>
+#include <string>
+#include <string_view>
+
+#include <gtest/gtest.h>
+
+#include "wpi/json.h"
+
+namespace wpi {
+
+inline void PrintTo(std::string_view str, ::std::ostream* os) {
+  ::testing::internal::PrintStringTo(std::string{str}, os);
+}
+
+template <typename T>
+void PrintTo(std::span<T> val, ::std::ostream* os) {
+  *os << '{';
+  bool first = true;
+  for (auto v : val) {
+    if (first) {
+      first = false;
+    } else {
+      *os << ", ";
+    }
+    *os << ::testing::PrintToString(v);
+  }
+  *os << '}';
+}
+
+inline void PrintTo(const json& val, ::std::ostream* os) {
+  *os << val.dump();
+}
+
+}  // namespace wpi
diff --git a/wpiutil/wpiutil-config.cmake.in b/wpiutil/wpiutil-config.cmake.in
index fde839e..3f696c8 100644
--- a/wpiutil/wpiutil-config.cmake.in
+++ b/wpiutil/wpiutil-config.cmake.in
@@ -4,5 +4,9 @@
 find_dependency(Threads)
 @FMTLIB_SYSTEM_REPLACE@
 
+if(@USE_SYSTEM_FMTLIB@)
+    find_dependency(fmt)
+endif()
+
 @FILENAME_DEP_REPLACE@
 include(${SELF_DIR}/wpiutil.cmake)